parent
f66d5fe3f3
commit
38aa08ba5a
@ -0,0 +1,96 @@
|
|||||||
|
public typealias BoardChangedListener = (Board) -> Void
|
||||||
|
public typealias GameStateChangedListener = (GameState) -> Void
|
||||||
|
|
||||||
|
public class Game {
|
||||||
|
public var boardChanged = Event<Board>()
|
||||||
|
public var gameStateChanged = Event<GameState>()
|
||||||
|
public var moveIsInvalid = Event<Move>()
|
||||||
|
|
||||||
|
public let players: [Player]
|
||||||
|
public let rules: Rules
|
||||||
|
|
||||||
|
public init(players: [Player], rules: Rules) {
|
||||||
|
self.players = players
|
||||||
|
self.rules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
public func play() {
|
||||||
|
var board = rules.createBoard()
|
||||||
|
var state = rules.gameState(board: board, last_turn: nil)
|
||||||
|
|
||||||
|
boardChanged(board)
|
||||||
|
gameStateChanged(state)
|
||||||
|
|
||||||
|
while case .Playing(let player_turn) = state {
|
||||||
|
let valid_moves = rules.validMoves(board: board, for_player: player_turn)
|
||||||
|
|
||||||
|
if valid_moves.isEmpty {
|
||||||
|
player_turn.skipMove(board: board)
|
||||||
|
} else {
|
||||||
|
while true {
|
||||||
|
let choosen_action = player_turn.chooseMove(allowed_moves: valid_moves, board: board)
|
||||||
|
let move = Move(player: player_turn, action: choosen_action)
|
||||||
|
|
||||||
|
guard rules.isValid(board: board, move: move) else {
|
||||||
|
moveIsInvalid(move)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
self.performMove(move: move, on_board: &board)
|
||||||
|
precondition(rules.isValid(board: board), "move that was valid made the board invalid")
|
||||||
|
|
||||||
|
boardChanged(board)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state = rules.gameState(board: board, last_turn: player_turn)
|
||||||
|
gameStateChanged(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finished
|
||||||
|
}
|
||||||
|
|
||||||
|
private func performMove(move: Move, on_board board: inout Board) {
|
||||||
|
let finalCoords = switch move.action {
|
||||||
|
case .InsertAt(let at): at
|
||||||
|
|
||||||
|
case .InsertOnSide(let side, let offset):
|
||||||
|
{
|
||||||
|
// TODO: with this, I am unsure how other moves on sides should handle pushing, popping, ...
|
||||||
|
let insertCoords = board.getInsertionCoordinates(from: side, offset: offset)
|
||||||
|
return switch board.fallCoordinates(initialCoords: insertCoords, direction: side.opposite) {
|
||||||
|
case .Border(let at), .Piece(let at, _):
|
||||||
|
at
|
||||||
|
case .Occupied:
|
||||||
|
// NOTE: assure the move is indeed legal and replace the current piece
|
||||||
|
insertCoords
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
board[finalCoords] = Piece(owner: move.player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@dynamicCallable
|
||||||
|
public struct Event<Param> {
|
||||||
|
private var listeners: [(Param) -> Void] = []
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
public mutating func add(_ listener: @escaping (Param) -> Void) {
|
||||||
|
self.listeners.append(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func dynamicallyCall(withArguments args: [Int]) -> Int { return args.count }
|
||||||
|
|
||||||
|
func dynamicallyCall(withArguments args: [Param]) -> Void {
|
||||||
|
for param in args {
|
||||||
|
for listener in self.listeners {
|
||||||
|
listener(param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
public struct Piece: Equatable, Sendable {
|
public struct Piece: Equatable {
|
||||||
public let type: PieceType
|
public let owner: Player
|
||||||
|
public var type: PieceType { owner.piece_type }
|
||||||
|
|
||||||
// Required for public visibility
|
public init(owner: Player) {
|
||||||
public init(type: PieceType) {
|
self.owner = owner
|
||||||
self.type = type
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue