Tic Tac Toe

Rules
Mathieu GROUSSEAU 4 weeks ago
parent e286e7e78a
commit 7206c0fa14

@ -42,15 +42,21 @@ public struct Board {
}
}
public func forEach(_ consumer: (Piece?) -> Void) {
for column in grid {
for piece in column {
consumer(piece)
}
}
}
public func countPieces(filter: (Piece) -> Bool = { piece in true }) -> Int {
var count = 0
for column in grid {
for piece in column {
if let piece = piece {
if filter(piece) {
count += 1
}
self.forEach {
if let piece = $0 {
if filter(piece) {
count += 1
}
}
}

@ -32,14 +32,7 @@ public struct FourInARowRules: Rules {
public func isValid(board: Board, move: Move) -> Bool {
guard self.isValid(board: board) else { return false }
switch self.state {
case .Playing(let turn) where turn != move.player:
fallthrough
case .Finished(_):
return false
default:
break
}
guard case .Playing(let turn) = state, turn == move.player else { return false }
if case .InsertOnSide(.Top, let offset) = move.action, offset >= 0 && offset < self.columns {
return board.fallCoordinates(

@ -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…
Cancel
Save