Check, fix, check ser-de

Persistance
Mathieu GROUSSEAU 2 months ago
parent 8770d1f423
commit 2f7ff9bbdc

@ -31,11 +31,7 @@ enum PlayerType: String, CaseIterable {
case Human = "Player"
}
func createPlayer(type: PlayerType, playing pieces: PieceType, named name: String) -> Player {
switch type {
case .Human:
HumanPlayer(name: name, piece_type: pieces, callback: {
allowed_moves, board in
func playerPrompt(allowed_moves: [Move.Action], board: Board) -> Move.Action {
for (i, action) in allowed_moves.enumerated() {
let text = switch action {
case .InsertAt(let at): "Place piece at \(at.col):\(at.row)"
@ -51,7 +47,12 @@ func createPlayer(type: PlayerType, playing pieces: PieceType, named name: Strin
}
return allowed_moves[index - 1]
})
}
func createPlayer(type: PlayerType, playing pieces: PieceType, named name: String) -> Player {
switch type {
case .Human:
HumanPlayer(name: name, piece_type: pieces, callback: playerPrompt)
case .AIRandom:
RandomPlayer(name: name, piece_type: pieces)
}
@ -68,7 +69,7 @@ let players: [Player] = PieceType.allCases.map { type in
return createPlayer(type: ptype, playing: type, named: playerName)
}
let rules: Rules = switch gameType {
let rules: any Rules = switch gameType {
case .FourInARow: FourInARowRules(players: players)!
case .TicTacToe: TicTacToeRules(players: players)!
}
@ -104,3 +105,9 @@ encoder.userInfo[.gameDecodingContext] = CodableContext()
let data = try encoder.encode(CodableGameWrapper(of: game))
print(String(data: data, encoding: .utf8)!)
var decoder = JSONDecoder()
decoder.userInfo[.gameDecodingContext] = CodableContext(creatingCallbacks: { name, type in playerPrompt })
let game2 = (try decoder.decode(CodableGameWrapper.self, from: data)).game
assert(game == game2, "Games are not equals!")

@ -42,10 +42,13 @@ public struct Board: Equatable {
}
}
/// Iterate in the same order as coords
public var cells: any Sequence<Piece?> {
self.grid.lazy.flatMap { (row: [Piece?]) -> LazySequence<[Piece?]> in row.lazy }
// self.grid.lazy.flatMap { (row: [Piece?]) -> LazySequence<[Piece?]> in row.lazy }
self.coords.map { self[$0] }
}
/// Iterate row by row, from 0 to width
public var coords: any Sequence<Coords> {
(0..<self.rows).lazy.flatMap { (row: Int) in
(0..<self.columns).lazy.map { (column: Int) in

@ -1,20 +1,20 @@
public typealias BoardChangedListener = (Board) -> Void
public typealias GameStateChangedListener = (GameState) -> Void
public class Game {
public class Game: Equatable {
public var boardChanged = Event<Board>()
public var gameStateChanged = Event<GameState>()
public var moveIsInvalid = Event<Move>()
public let players: [Player]
public let rules: Rules
public let rules: any Rules
/// Has to be public for serialization purposes
public var board: Board
/// Has to be public for serialization purposes
public var state: GameState
public init(players: [Player], rules: Rules) {
public init(players: [Player], rules: any Rules) {
self.players = players
self.rules = rules
@ -23,7 +23,7 @@ public class Game {
self.state = rules.gameState(board: board, last_turn: nil)
}
public init?(players: [Player], rules: Rules, board: Board, state: GameState?) {
public init?(players: [Player], rules: any Rules, board: Board, state: GameState?) {
guard rules.isValid(board: board) else { return nil }
self.state = state ?? rules.gameState(board: board, last_turn: nil)
@ -96,6 +96,13 @@ public class Game {
board[finalCoords] = Piece(owner: move.player)
}
public static func == (lhs: Game, rhs: Game) -> Bool {
lhs.players == rhs.players
&& RulesUtils.equals(lhs: lhs.rules, rhs: rhs.rules)
&& lhs.board == rhs.board
&& lhs.state == rhs.state
}
}
@dynamicCallable

@ -19,8 +19,7 @@ public class Player : Equatable {
}
public static func == (lhs: Player, rhs: Player) -> Bool {
// TODO: name equality or reference equality?
lhs === rhs
lhs === rhs || (lhs.type == rhs.type && lhs.name == rhs.name && lhs.piece_type == rhs.piece_type)
}
}

@ -1,4 +1,4 @@
public protocol Rules {
public protocol Rules: Equatable {
var type: RulesTypes { get }
func createBoard() -> Board
@ -14,6 +14,22 @@ public protocol Rules {
func gameState(board: Board, last_turn: Player?) -> GameState
}
public struct RulesUtils {
public static func equals(lhs: any Rules, rhs: any Rules) -> Bool {
let t1 = lhs.type
let t2 = rhs.type
if t1 != t2 { return false }
return switch t1 {
case .FourInARow:
(lhs as! FourInARowRules) == (rhs as! FourInARowRules)
case .TicTacToe:
(lhs as! TicTacToeRules) == (rhs as! TicTacToeRules)
}
}
}
public enum GameState: Equatable {
case Playing(turn: Player)
case Win(winner: Player, board: Board, cells: [Coords])

@ -1,9 +1,9 @@
import Model
public struct CodableRulesWrapper: Codable {
public let rules: Rules
public let rules: any Rules
public init(of rules: Rules) {
public init(of rules: any Rules) {
self.rules = rules
}
@ -30,7 +30,7 @@ extension RulesTypes: CodingKey, Codable {
try CodableEnum(of: self).encode(to: encoder)
}
public func decodeRules(from decoder: any Decoder) throws -> Rules {
public func decodeRules(from decoder: any Decoder) throws -> any Rules {
switch self {
case .FourInARow: try FourInARowRules(from: decoder)
case .TicTacToe: try TicTacToeRules(from: decoder)

Loading…
Cancel
Save