Как изменить значение свойства статическим методом?

В этой простой игре есть класс Fighter, цель которого - заставить двух бойцов сражаться. Тот, кто теряет здоровье ниже 0, проигрывает игру.

Для борьбы используется статический метод fight (..), который повторяется до тех пор, пока один боец ​​не выиграет игру, поддерживаемый атакой другого не статического метода (..)

Здоровье объекта-бойца должно меняться, так как два объекта сражаются во время игры, используя методы бой (...) и атака (...). Проблема в том, что он всегда печатает одно и то же здоровье бойца, и игра никогда не заканчивается. Я не вижу, где проблема

class ViewController: UIViewController {
     override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let david = Fighter(name: "David", health: 100, damage: 30, defense: 10, initiative: 80)
        let goliath = Fighter(name: "Goliath", health: 300, damage: 60, defense: 14, initiative: 90)


        let myFight1 = Fighter.fight(fighter1: david, fighter2: goliath) // always executing same Fighters
        print(myFight1)

    }
}

import Foundation


struct Fighter {
    var name: String
    var health: Double
    var damage: Int
    var defense: Int
    var initiative: Int

    init (name: String, health: Double, damage: Int, defense: Int, initiative: Int) {
        self.name = name
        self.health = health
        self.damage = damage
        self.defense = defense
        self.initiative = initiative
    }

     init (name: String, health: Double, damage: Int, defense: Int) {
        self.name = name
        self.health = health
        self.damage = damage
        self.defense = defense
        self.initiative = 0
    }

    static func fight(fighter1: Fighter, fighter2: Fighter) -> Fighter {
        let f1 = fighter1
        let f2 = fighter2

        if f1.health == f2.health {
            return f1
        }

        if f2.initiative > f1.initiative {
           f2.attack(f: f1)
        }

        var i = 0

        while f1.health > 0 {
            i += 1
            print("--> i: \(i)")
            f1.attack(f: f2 )

            if f2.health <= 0 {
                return f1
            }
        f2.attack(f: f1)
            }
        return f2
        }

    func attack(f: Fighter) -> Void {
        var g = f
        g.health = g.health - Double(g.damage * (1 - g.defense / 100))
        print(g)
    }        
}

4 ответа

Решение

Вы используете struct за Fighter который является типом значения в Swift.

Самая основная отличительная особенность типа значения заключается в том, что копирование - эффект присваивания, инициализации и передачи аргумента - создает независимый экземпляр со своей уникальной копией своих данных.

Решение: Изменить Fighter к class и ты в порядке.

Вывод операторов печати: (Второй оператор печати изменен на print(g.name, g.health))

Давид 70,0
-> я: 1
Голиаф 240.0
Давид 40,0
-> я: 2
Голиаф 180.0
Давид 10,0
-> я: 3
Голиаф 120.0
Дэвид -20,0


Для получения дополнительной информации: Тип значения и ссылки

Когда ты говоришь...

    var g = f

... вы на самом деле создаете копию этого объекта, а не ссылку. Таким образом, когда вы меняете свойство "здоровье", вы меняете его в копии. Есть 2 простых решения:

1) Измените структуру на класс, потому что на классы ссылаются, в отличие от структур, которые просто копируют.

2) Заменить оригинальный объект его измененной копией (г)

После вызова метода func attack(f: Fighter) -> Void каждый раз, свойства Fighter кто подвергается нападению, не получают обновления. Так while Цикл не сломается ни в одной точке.

Пожалуйста, замените код ниже.

static func fight(fighter1: Fighter, fighter2: Fighter) -> Fighter {
        var f1 = fighter1
        var f2 = fighter2

        if f1.health == f2.health {
            return f1
        }

        if f2.initiative > f1.initiative {
            f1 = f2.attack(f: f1)
        }

        var i = 0

        while f1.health > 0 {
            i += 1
            print("--> i: \(i)")
            f2 = f1.attack(f: f2 )

            if f2.health <= 0 {
                return f1
            }
            f1 = f2.attack(f: f1)
        }
        return f2
    }

    func attack( f: Fighter) -> Fighter {
        var g = f
        g.health = g.health - Double(g.damage * (1 - g.defense / 100))
        print(g)
        return g
    }

Как отмечает Ракеша, структуры являются типами значений, поэтому ваши attack код на самом деле ничего не меняет:

func attack(f: Fighter) -> Void {
    var g = f   // Make a mutable copy of `f` called `g`
    g.health = g.health - Double(g.damage * (1 - g.defense / 100)) // Modify g
    print(g) // Print g
    // Throw g away
}

(Примечание: я думаю, g.damage здесь неверно; Я думаю ты наверное имел ввиду self.damage.)

На самом деле ничего там не изменяется f, Есть несколько способов решения этой проблемы. Одним из них является использование классов, которые вводят тонкое изменяемое состояние. Я не думаю, что я сделал бы это здесь. Под "тонким изменчивым состоянием" я имею в виду, что вы ожидаете attack модифицировать f, но ничто в подписи не говорит, что это так, так что звонящий может быть удивлен.

Вместо этого у вас есть несколько способов реализовать это, чтобы сделать ваши мутации явными в структурах. Ты можешь сделать attack явно изменить f:

func attack(f: inout Fighter) {
    f.health = f.health - Double(damage * (1 - f.defense / 100))
}

Или вы можете перевернуть его и изменить себя, если на вас напал кто-то еще:

mutating func attackedBy(f: Fighter) {
    health = health - Double(f.damage * (1 - defense / 100)
}
Другие вопросы по тегам