Как изменить значение свойства статическим методом?
В этой простой игре есть класс 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)
}