Bob
Bob

Reputation: 188

Update values in a dictionary based on changes made to another dictionary

I would like to know if there is a way to automatically update the value in a dictionary based on changes made to values in another dictionary. I have 2 dictionaries as follows:

enum CharacterAttributes: String, Codable  {
    case strength
    case constitution
    case dexterity
    case intelligence
}

enum CharacterStats: String, Codable  {
    case maxHealthPoint
    case maxTacticPoint
    case maxActionPoint
    case movementSpeed
}

var attributes = [CharacterAttributes: Float]()
var stats = [CharacterStats: Float]()

The logics are:

stats[.maxHealthPoint] = attributes[.constitution] *  100
stats[.maxTacticPoint] = (attributes[.dexterity] +  attributes[.intelligence]) * 1.5
stats[.maxActionPoint] = attributes[.constitution] * 10
stats[.movementSpeed] = attributes[.dexterity] + 70

What I want to achieve is that whenever a value is changed from attributes dictionary, the corresponding values in stats get updated automatically. I know for a normal variable I can use didSet keyword, but how to apply the concept to dictionaries?

Thanks in advance for any help.

Upvotes: 1

Views: 61

Answers (1)

Sash Sinha
Sash Sinha

Reputation: 22370

Try using the didSet observer after encapsulating your dictionaries within a class:

import Foundation

enum CharacterAttributes: String, Codable {
    case strength
    case constitution
    case dexterity
    case intelligence
}

enum CharacterStats: String, Codable {
    case maxHealthPoint
    case maxTacticPoint
    case maxActionPoint
    case movementSpeed
}

class Character {
    private var _attributes = [CharacterAttributes: Float]() {
        didSet {
            updateStats()
        }
    }
    
    private var _stats = [CharacterStats: Float]()
    
    var attributes: [CharacterAttributes: Float] {
        get { _attributes }
        set {
            _attributes = newValue
            updateStats()
        }
    }
    
    var stats: [CharacterStats: Float] {
        get { _stats }
        set {
            _stats = newValue
        }
    }
    
    init(attributes: [CharacterAttributes: Float]) {
        self._attributes = attributes
        updateStats()
    }
    
    private func updateStats() {
        _stats[.maxHealthPoint] = (_attributes[.constitution] ?? 0) * 100
        _stats[.maxTacticPoint] = ((_attributes[.dexterity] ?? 0) + (_attributes[.intelligence] ?? 0)) * 1.5
        _stats[.maxActionPoint] = (_attributes[.constitution] ?? 0) * 10
        if _stats[.movementSpeed] == nil { // Allow manual setting
            _stats[.movementSpeed] = (_attributes[.dexterity] ?? 0) + 70
        }
    }
}

Example Usage:

var character = Character(attributes: [.constitution: 5, .dexterity: 3, .intelligence: 2])
print(character.stats)
character.attributes[.constitution] = 7
character.stats[.movementSpeed] = 100
character.attributes[.dexterity] = 4
print(character.stats)

Output:

[SwiftPlayground.CharacterStats.maxHealthPoint: 500.0, SwiftPlayground.CharacterStats.maxTacticPoint: 7.5, SwiftPlayground.CharacterStats.maxActionPoint: 50.0, SwiftPlayground.CharacterStats.movementSpeed: 73.0]
[SwiftPlayground.CharacterStats.maxHealthPoint: 700.0, SwiftPlayground.CharacterStats.maxTacticPoint: 9.0, SwiftPlayground.CharacterStats.maxActionPoint: 70.0, SwiftPlayground.CharacterStats.movementSpeed: 100.0]

Upvotes: 3

Related Questions