Skip to content

Instantly share code, notes, and snippets.

@vikingosegundo
Created October 5, 2021 13:35
Show Gist options
  • Save vikingosegundo/e31385c1ac99c994d3b013348cc3f159 to your computer and use it in GitHub Desktop.
Save vikingosegundo/e31385c1ac99c994d3b013348cc3f159 to your computer and use it in GitHub Desktop.
class Board {
var territories: [Territory]
let borders:[Border]
enum Change {
case move(Move)
case hold(Territory, with:Unit, of:Empire)
enum Move{
case army(of:Empire, from:Territory, to:Territory)
case fleet(of:Empire, from:Territory, to:Territory)
}
}
init(territories:[Territory], borders:[Border]) {
self.territories = territories
self.borders = borders
}
func execute(_ change:Change) {
switch change {
case let .move( .army(empire,from:from, to: to)): move(unit: .army(empire),from:from,to:to)
case let .move(.fleet(empire,from:from, to: to)): move(unit:.fleet(empire),from:from,to:to)
case let .hold(territory, with:unit, of:empire): print("hold \(territory.name) with:\(unit) of \(empire)")
}
}
func connected(left:Territory, right:Territory) -> Bool {
guard
let from = territories.first(where: {$0.name == left.name}),
let to = territories.first(where: {$0.name == right.name}) else { return false }
return borders.first { border in
switch border {
case let .land(l, r): return ((l.name == from.name && r.name == to.name) || (r.name == from.name && l.name == to.name))
case let .sea (l, r): return ((l.name == from.name && r.name == to.name) || (r.name == from.name && l.name == to.name))
default: return false
}
} != nil
}
private
func move(unit:Unit, from:Territory, to:Territory) {
switch (unit, from.kind, to.kind) {
case let ( .army(empire),.land,.land): connected(left: from, right: to) ? moveArmy (for: empire, fromLand: from, toLand: to) : ()
case let (.fleet(empire), .sea, .sea): connected(left: from, right: to) ? moveFleet(for: empire, fromLand: from, toLand: to) : ()
default: ()
}
}
private
func moveArmy(for empire:Empire, fromLand:Territory, toLand:Territory) {
guard
let idxFrom = territories.firstIndex(where: { $0.name == fromLand.name && $0.occupiedBy == .army(empire) }),
let idxTo = territories.firstIndex(where: { $0.name == toLand.name })
else { return }
let territories = Array(territories.prefix(idxFrom)) + [fromLand.execute(.occupy(nil))] + Array(territories.suffix(territories.count - 1 - idxFrom ))
update(territories:Array(territories.prefix(idxTo )) + [ toLand.execute(.occupy(.army(empire)))] + Array(territories.suffix(territories.count - 1 - idxTo )))
}
private
func moveFleet(for empire:Empire, fromLand:Territory, toLand:Territory) {
guard
let idxFrom = territories.firstIndex(where: { $0.name == fromLand.name && $0.occupiedBy == .fleet(empire) }),
let idxTo = territories.firstIndex(where: { $0.name == toLand.name })
else { return }
let territories = Array(territories.prefix(idxFrom)) + [fromLand.execute(.occupy(nil))] + Array(territories.suffix(territories.count - 1 - idxFrom ))
update(territories:Array(territories.prefix(idxTo )) + [ toLand.execute(.occupy(.fleet(empire)))] + Array(territories.suffix(territories.count - 1 - idxTo )))
}
private func update(territories t:[Territory]) { territories = t }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment