Rename Player enum to PieceType

pull/3/head
Mathieu GROUSSEAU 4 weeks ago
parent ffdfebe560
commit b9853390ed

@ -18,7 +18,7 @@ for move in rules.validMoves(board: board) {
print(move) print(move)
} }
print("Moves for \(Player.A):") print("Moves for \(PieceType.A):")
for move in rules.validMoves(board: board, for_player: .A) { for move in rules.validMoves(board: board, for_player: .A) {
print(move) print(move)
} }
@ -42,7 +42,7 @@ while case .Playing(let turn) = rules.state {
direction: .Bottom direction: .Bottom
) { ) {
case .Border(let at), .Piece(let at, _): case .Border(let at), .Piece(let at, _):
board[at] = Piece(owner: turn) board[at] = Piece(type: turn)
case .Occupied: case .Occupied:
fatalError("Occupied???") fatalError("Occupied???")
} }

@ -1,6 +1,6 @@
import Model import Model
extension Player: CustomStringConvertible { extension PieceType: CustomStringConvertible {
public var description: String { public var description: String {
switch self { switch self {
case .A: case .A:
@ -17,7 +17,7 @@ extension Board: CustomStringConvertible, CustomDebugStringConvertible {
for row in 0..<self.rows { for row in 0..<self.rows {
for col in 0..<self.columns { for col in 0..<self.columns {
str += self[col, row]?.owner.description ?? "" str += self[col, row]?.type.description ?? ""
} }
str += "\n" str += "\n"
@ -27,7 +27,7 @@ extension Board: CustomStringConvertible, CustomDebugStringConvertible {
} }
public var debugDescription: String { public var debugDescription: String {
return "Board[\(self.columns)x\(self.rows), \(self.countPieces { p in p.owner == .A }) A and \(self.countPieces { p in p.owner == .B }) B pieces]" return "Board[\(self.columns)x\(self.rows), \(self.countPieces { p in p.type == .A }) A and \(self.countPieces { p in p.type == .B }) B pieces]"
} }
} }

@ -9,10 +9,10 @@ final class CustomTypesTests: XCTestCase {
return return
} }
board[1, 1] = Piece(owner: .A) board[1, 1] = Piece(type: .A)
board[2, 1] = Piece(owner: .A) board[2, 1] = Piece(type: .A)
board[2, 2] = Piece(owner: .A) board[2, 2] = Piece(type: .A)
board[1, 2] = Piece(owner: .B) board[1, 2] = Piece(type: .B)
let text: String = board.description let text: String = board.description

@ -1,8 +1,8 @@
public struct Piece : Sendable { public struct Piece : Sendable {
public let owner: Player public let type: PieceType
// Required for public visibility // Required for public visibility
public init(owner: Player) { public init(type: PieceType) {
self.owner = owner self.type = type
} }
} }

@ -0,0 +1,3 @@
public enum PieceType: CaseIterable, Sendable {
case A, B
}

@ -1,3 +0,0 @@
public enum Player: CaseIterable, Sendable {
case A, B
}

@ -63,14 +63,14 @@ public struct FourInARowRules: Rules {
} }
public func validMoves(board: Board) -> [Move] { public func validMoves(board: Board) -> [Move] {
return Player.allCases.flatMap({ return PieceType.allCases.flatMap({
player in self.validMoves(board: board, for_player: player).map({ player in self.validMoves(board: board, for_player: player).map({
action in Move(player: player, action: action) action in Move(player: player, action: action)
}) })
}) })
} }
public func validMoves(board: Board, for_player player: Player) -> [Move.Action] { public func validMoves(board: Board, for_player player: PieceType) -> [Move.Action] {
var moves: [Move.Action] = []; var moves: [Move.Action] = [];
for c in 0..<board.columns { for c in 0..<board.columns {
@ -110,7 +110,7 @@ public struct FourInARowRules: Rules {
} else if board.countPieces() == board.columns * board.rows { } else if board.countPieces() == board.columns * board.rows {
self.state = .Finished(winner: nil) self.state = .Finished(winner: nil)
} else { } else {
let next: Player = switch move.player { let next: PieceType = switch move.player {
case .A: .B case .A: .B
case .B: .A case .B: .A
} }
@ -122,7 +122,7 @@ public struct FourInARowRules: Rules {
} }
internal static func countMaxRow(center: Coords, board: Board) -> Int { internal static func countMaxRow(center: Coords, board: Board) -> Int {
guard let of = board[center]?.owner else { return 0 } guard let of = board[center]?.type else { return 0 }
var maxLength = 0 var maxLength = 0
// For each "axis" (described as one direction) // For each "axis" (described as one direction)
@ -135,7 +135,7 @@ public struct FourInARowRules: Rules {
while true { while true {
pos = Coords(pos.col + dc, pos.row + dr) pos = Coords(pos.col + dc, pos.row + dr)
if !board.isInBounds(pos) || board[pos]?.owner != of { break } if !board.isInBounds(pos) || board[pos]?.type != of { break }
length += 1 length += 1
} }
} }

@ -1,8 +1,8 @@
public struct Move: Equatable { public struct Move: Equatable {
public let player: Player public let player: PieceType
public let action: Action public let action: Action
public init(player: Player, action: Action) { public init(player: PieceType, action: Action) {
self.player = player self.player = player
self.action = action self.action = action
} }

@ -11,13 +11,13 @@ public protocol Rules {
func validMoves(board: Board) -> [Move] func validMoves(board: Board) -> [Move]
func validMoves(board: Board, for_player player: Player) -> [Move.Action] func validMoves(board: Board, for_player player: PieceType) -> [Move.Action]
mutating func onMoveDone(move: Move, board: Board) -> Void mutating func onMoveDone(move: Move, board: Board) -> Void
} }
public enum GameState: Equatable { public enum GameState: Equatable {
case Playing(turn: Player) case Playing(turn: PieceType)
case Finished(winner: Player?) case Finished(winner: PieceType?)
} }

@ -16,8 +16,8 @@ public struct TicTacToeRules: Rules {
} }
public func isValid(board: Board) -> Bool { public func isValid(board: Board) -> Bool {
abs(board.countPieces(filter: { p in p.owner == .A }) - abs(board.countPieces(filter: { p in p.type == .A }) -
board.countPieces(filter: { p in p.owner == .B })) <= 1 board.countPieces(filter: { p in p.type == .B })) <= 1
} }
public func isValid(board: Board, move: Move) -> Bool { public func isValid(board: Board, move: Move) -> Bool {
@ -38,15 +38,15 @@ public struct TicTacToeRules: Rules {
return self.validMoves(board: board, for_player: player).map { Move(player: player, action: $0) } return self.validMoves(board: board, for_player: player).map { Move(player: player, action: $0) }
} }
private static func nextPlayer(board: Board) -> Player { private static func nextPlayer(board: Board) -> PieceType {
if board.countPieces(filter: { p in p.owner == .A }) > board.countPieces(filter: { p in p.owner == .B }) { if board.countPieces(filter: { p in p.type == .A }) > board.countPieces(filter: { p in p.type == .B }) {
.B .B
} else { } else {
.A .A
} }
} }
public func validMoves(board: Board, for_player player: Player) -> [Move.Action] { public func validMoves(board: Board, for_player player: PieceType) -> [Move.Action] {
var moves: [Move.Action] = [] var moves: [Move.Action] = []
for col in 0..<board.columns { for col in 0..<board.columns {
@ -72,7 +72,7 @@ public struct TicTacToeRules: Rules {
} else if board.countPieces() == board.columns * board.rows { } else if board.countPieces() == board.columns * board.rows {
self.state = .Finished(winner: nil) self.state = .Finished(winner: nil)
} else { } else {
let next: Player = switch move.player { let next: PieceType = switch move.player {
case .A: .B case .A: .B
case .B: .A case .B: .A
} }

@ -32,7 +32,7 @@ final class EmptyBoardTests: XCTestCase {
func testCustomSubscript() throws { func testCustomSubscript() throws {
for r in 0..<board.rows { for r in 0..<board.rows {
for c in 0..<board.columns { for c in 0..<board.columns {
for p: Player in [.A, .B] { for p: PieceType in [.A, .B] {
try self.setUpWithError() try self.setUpWithError()
try self._testCustomSubscript(at: Coords(c, r), player: p) try self._testCustomSubscript(at: Coords(c, r), player: p)
@ -43,19 +43,19 @@ final class EmptyBoardTests: XCTestCase {
} }
} }
private func _testCustomSubscript(at: Coords, player: Player) throws { private func _testCustomSubscript(at: Coords, player: PieceType) throws {
board[at] = Piece(owner: player) board[at] = Piece(type: player)
XCTAssertEqual(board[at]?.owner, player) XCTAssertEqual(board[at]?.type, player)
} }
func testCounts() throws { func testCounts() throws {
board[1, 2] = Piece(owner: .B) board[1, 2] = Piece(type: .B)
board[0, 2] = Piece(owner: .A) board[0, 2] = Piece(type: .A)
board[1, 1] = Piece(owner: .A) board[1, 1] = Piece(type: .A)
XCTAssertEqual(board.countPieces { piece in piece.owner == .A }, 2) XCTAssertEqual(board.countPieces { piece in piece.type == .A }, 2)
XCTAssertEqual(board.countPieces { piece in piece.owner == .B }, 1) XCTAssertEqual(board.countPieces { piece in piece.type == .B }, 1)
} }
func testInsertsSides() throws { func testInsertsSides() throws {
@ -129,9 +129,9 @@ final class EmptyBoardTests: XCTestCase {
] { ] {
// ensure it works with any player // ensure it works with any player
board[Coords(pair: pos)] = if (pos.0 + pos.1) & 1 == 1 { board[Coords(pair: pos)] = if (pos.0 + pos.1) & 1 == 1 {
Piece(owner: .A) Piece(type: .A)
} else { } else {
Piece(owner: .B) Piece(type: .B)
} }
} }

@ -15,9 +15,9 @@ final class FilledBoardTests: XCTestCase {
for row in 0..<board.rows { for row in 0..<board.rows {
for col in 0..<board.columns { for col in 0..<board.columns {
board[col, row] = if (row & 1) == 1 { board[col, row] = if (row & 1) == 1 {
Piece(owner: .A) Piece(type: .A)
} else { } else {
Piece(owner: .B) Piece(type: .B)
} }
} }
} }

@ -37,7 +37,7 @@ final class FourInARowRulesTests: XCTestCase {
} }
func testMovesOfPlayerAreValid() throws { func testMovesOfPlayerAreValid() throws {
for player in Player.allCases { for player in PieceType.allCases {
try self.setUpWithError() try self.setUpWithError()
try self._testMovesOfPlayerAreValid(player: player) try self._testMovesOfPlayerAreValid(player: player)
@ -46,7 +46,7 @@ final class FourInARowRulesTests: XCTestCase {
} }
} }
private func _testMovesOfPlayerAreValid(player: Player) throws { private func _testMovesOfPlayerAreValid(player: PieceType) throws {
for action in self.rules.validMoves(board: self.board, for_player: player) { for action in self.rules.validMoves(board: self.board, for_player: player) {
rules.state = .Playing(turn: player) rules.state = .Playing(turn: player)
XCTAssertTrue(self.rules.isValid(board: board, move: Move(player: player, action: action)), "\(action)") XCTAssertTrue(self.rules.isValid(board: board, move: Move(player: player, action: action)), "\(action)")
@ -55,7 +55,7 @@ final class FourInARowRulesTests: XCTestCase {
func testOnMoveDone() { func testOnMoveDone() {
let coord = Coords(1, board.rows - 1) let coord = Coords(1, board.rows - 1)
board[coord] = Piece(owner: .A) board[coord] = Piece(type: .A)
let move = Move(player: .A, action: .InsertOnSide(side: .Top, offset: 1)) let move = Move(player: .A, action: .InsertOnSide(side: .Top, offset: 1))
self.rules.onMoveDone(move: move, board: self.board) self.rules.onMoveDone(move: move, board: self.board)
@ -64,16 +64,16 @@ final class FourInARowRulesTests: XCTestCase {
} }
func testOnMoveDoneDraw() { func testOnMoveDoneDraw() {
board[0, 0] = Piece(owner: .A) board[0, 0] = Piece(type: .A)
board[1, 0] = Piece(owner: .A) board[1, 0] = Piece(type: .A)
board[2, 0] = Piece(owner: .B) board[2, 0] = Piece(type: .B)
board[0, 1] = Piece(owner: .B) board[0, 1] = Piece(type: .B)
board[1, 1] = Piece(owner: .B) board[1, 1] = Piece(type: .B)
board[2, 1] = Piece(owner: .A) board[2, 1] = Piece(type: .A)
board[0, 2] = Piece(owner: .A) board[0, 2] = Piece(type: .A)
board[1, 2] = Piece(owner: .A) board[1, 2] = Piece(type: .A)
board[2, 2] = Piece(owner: .B) board[2, 2] = Piece(type: .B)
XCTAssertTrue(rules.isValid(board: board)) XCTAssertTrue(rules.isValid(board: board))
@ -85,15 +85,15 @@ final class FourInARowRulesTests: XCTestCase {
} }
func testOnMoveDoneWin() { func testOnMoveDoneWin() {
board[0, 0] = Piece(owner: .A) board[0, 0] = Piece(type: .A)
board[1, 0] = Piece(owner: .A) board[1, 0] = Piece(type: .A)
board[2, 0] = Piece(owner: .A) // board[2, 0] = Piece(type: .A) //
board[0, 1] = Piece(owner: .B) board[0, 1] = Piece(type: .B)
board[1, 1] = Piece(owner: .B) board[1, 1] = Piece(type: .B)
board[2, 1] = Piece(owner: .A) board[2, 1] = Piece(type: .A)
board[0, 2] = Piece(owner: .A) board[0, 2] = Piece(type: .A)
board[1, 2] = Piece(owner: .A) board[1, 2] = Piece(type: .A)
board[2, 2] = Piece(owner: .B) board[2, 2] = Piece(type: .B)
XCTAssertTrue(rules.isValid(board: board)) XCTAssertTrue(rules.isValid(board: board))
@ -118,15 +118,15 @@ final class FourInARowRulesTests: XCTestCase {
// AAA // AAA
// BAB // BAB
// BBA // BBA
board[0, 0] = Piece(owner: .A) board[0, 0] = Piece(type: .A)
board[1, 0] = Piece(owner: .A) board[1, 0] = Piece(type: .A)
board[2, 0] = Piece(owner: .A) board[2, 0] = Piece(type: .A)
board[0, 1] = Piece(owner: .B) board[0, 1] = Piece(type: .B)
board[1, 1] = Piece(owner: .A) board[1, 1] = Piece(type: .A)
board[2, 1] = Piece(owner: .B) board[2, 1] = Piece(type: .B)
board[0, 2] = Piece(owner: .B) board[0, 2] = Piece(type: .B)
board[1, 2] = Piece(owner: .B) board[1, 2] = Piece(type: .B)
board[2, 2] = Piece(owner: .A) board[2, 2] = Piece(type: .A)
self._testCountMaxRow(coords: coords, expected: expected) self._testCountMaxRow(coords: coords, expected: expected)

Loading…
Cancel
Save