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 let type: PieceType
|
||||
public struct Piece: Equatable {
|
||||
public let owner: Player
|
||||
public var type: PieceType { owner.piece_type }
|
||||
|
||||
// Required for public visibility
|
||||
public init(type: PieceType) {
|
||||
self.type = type
|
||||
public init(owner: Player) {
|
||||
self.owner = owner
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue