parent
e286e7e78a
commit
7206c0fa14
@ -0,0 +1,82 @@
|
|||||||
|
public struct TicTacToeRules: Rules {
|
||||||
|
public var state: GameState = .Playing(turn: .A)
|
||||||
|
|
||||||
|
public var history: [Move] = []
|
||||||
|
|
||||||
|
private let columns: Int, rows: Int, minAligned: Int
|
||||||
|
|
||||||
|
public init(columns: Int, rows: Int, minAligned: Int = 3) {
|
||||||
|
self.columns = columns
|
||||||
|
self.rows = rows
|
||||||
|
self.minAligned = minAligned
|
||||||
|
}
|
||||||
|
|
||||||
|
public func createBoard() -> Board {
|
||||||
|
Board(columns: self.columns, rows: self.rows)!
|
||||||
|
}
|
||||||
|
|
||||||
|
public func isValid(board: Board) -> Bool {
|
||||||
|
abs(board.countPieces(filter: { p in p.owner == .A }) -
|
||||||
|
board.countPieces(filter: { p in p.owner == .B })) <= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public func isValid(board: Board, move: Move) -> Bool {
|
||||||
|
guard self.isValid(board: board) else { return false }
|
||||||
|
|
||||||
|
guard case .Playing(let turn) = state, turn == move.player else { return false }
|
||||||
|
|
||||||
|
if case .InsertAt(let coord) = move.action, board.isInBounds(coord) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func validMoves(board: Board) -> [Move] {
|
||||||
|
let player = Self.nextPlayer(board: board)
|
||||||
|
|
||||||
|
return self.validMoves(board: board, for_player: player).map { Move(player: player, action: $0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func nextPlayer(board: Board) -> Player {
|
||||||
|
if board.countPieces(filter: { p in p.owner == .A }) > board.countPieces(filter: { p in p.owner == .B }) {
|
||||||
|
.B
|
||||||
|
} else {
|
||||||
|
.A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func validMoves(board: Board, for_player player: Player) -> [Move.Action] {
|
||||||
|
var moves: [Move.Action] = []
|
||||||
|
|
||||||
|
for col in 0..<board.columns {
|
||||||
|
for row in 0..<board.rows {
|
||||||
|
if board[col, row] == nil {
|
||||||
|
moves.append(.InsertAt(where: Coords(col, row)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return moves
|
||||||
|
}
|
||||||
|
|
||||||
|
public mutating func onMoveDone(move: Move, board: Board) {
|
||||||
|
self.history.append(move)
|
||||||
|
|
||||||
|
guard case .InsertAt(let coords) = move.action else {
|
||||||
|
fatalError("Illegal move \(move.action)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if FourInARowRules.countMaxRow(center: coords, board: board) >= self.minAligned {
|
||||||
|
self.state = .Finished(winner: move.player)
|
||||||
|
} else if board.countPieces() == board.columns * board.rows {
|
||||||
|
self.state = .Finished(winner: nil)
|
||||||
|
} else {
|
||||||
|
let next: Player = switch move.player {
|
||||||
|
case .A: .B
|
||||||
|
case .B: .A
|
||||||
|
}
|
||||||
|
self.state = .Playing(turn: next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue