refactor: migrate GameController to GameContext (signatures only)
Build & Test (NowChessSystems) TeamCity build finished
Build & Test (NowChessSystems) TeamCity build finished
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
package de.nowchess.chess
|
package de.nowchess.chess
|
||||||
|
|
||||||
import de.nowchess.api.board.{Board, Color}
|
import de.nowchess.api.board.Color
|
||||||
import de.nowchess.chess.controller.GameController
|
import de.nowchess.chess.controller.GameController
|
||||||
|
import de.nowchess.chess.logic.GameContext
|
||||||
|
|
||||||
object Main {
|
object Main {
|
||||||
def main(args: Array[String]): Unit =
|
def main(args: Array[String]): Unit =
|
||||||
println("NowChess TUI — type moves in coordinate notation (e.g. e2e4). Type 'quit' to exit.")
|
println("NowChess TUI — type moves in coordinate notation (e.g. e2e4). Type 'quit' to exit.")
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ import de.nowchess.chess.view.Renderer
|
|||||||
|
|
||||||
sealed trait MoveResult
|
sealed trait MoveResult
|
||||||
object MoveResult:
|
object MoveResult:
|
||||||
case object Quit extends MoveResult
|
case object Quit extends MoveResult
|
||||||
case class InvalidFormat(raw: String) extends MoveResult
|
case class InvalidFormat(raw: String) extends MoveResult
|
||||||
case object NoPiece extends MoveResult
|
case object NoPiece extends MoveResult
|
||||||
case object WrongColor extends MoveResult
|
case object WrongColor extends MoveResult
|
||||||
case object IllegalMove extends MoveResult
|
case object IllegalMove extends MoveResult
|
||||||
case class Moved(newBoard: Board, captured: Option[Piece], newTurn: Color) extends MoveResult
|
case class Moved(newCtx: GameContext, captured: Option[Piece], newTurn: Color) extends MoveResult
|
||||||
case class MovedInCheck(newBoard: Board, captured: Option[Piece], newTurn: Color) extends MoveResult
|
case class MovedInCheck(newCtx: GameContext, captured: Option[Piece], newTurn: Color) extends MoveResult
|
||||||
case class Checkmate(winner: Color) extends MoveResult
|
case class Checkmate(winner: Color) extends MoveResult
|
||||||
case object Stalemate extends MoveResult
|
case object Stalemate extends MoveResult
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Controller
|
// Controller
|
||||||
@@ -27,10 +27,10 @@ object MoveResult:
|
|||||||
|
|
||||||
object GameController:
|
object GameController:
|
||||||
|
|
||||||
/** Pure function: interprets one raw input line against the current board state.
|
/** Pure function: interprets one raw input line against the current game context.
|
||||||
* Has no I/O side effects — all output must be handled by the caller.
|
* Has no I/O side effects — all output must be handled by the caller.
|
||||||
*/
|
*/
|
||||||
def processMove(board: Board, turn: Color, raw: String): MoveResult =
|
def processMove(ctx: GameContext, turn: Color, raw: String): MoveResult =
|
||||||
raw.trim match
|
raw.trim match
|
||||||
case "quit" | "q" =>
|
case "quit" | "q" =>
|
||||||
MoveResult.Quit
|
MoveResult.Quit
|
||||||
@@ -39,61 +39,62 @@ object GameController:
|
|||||||
case None =>
|
case None =>
|
||||||
MoveResult.InvalidFormat(trimmed)
|
MoveResult.InvalidFormat(trimmed)
|
||||||
case Some((from, to)) =>
|
case Some((from, to)) =>
|
||||||
board.pieceAt(from) match
|
ctx.board.pieceAt(from) match
|
||||||
case None =>
|
case None =>
|
||||||
MoveResult.NoPiece
|
MoveResult.NoPiece
|
||||||
case Some(piece) if piece.color != turn =>
|
case Some(piece) if piece.color != turn =>
|
||||||
MoveResult.WrongColor
|
MoveResult.WrongColor
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
if !MoveValidator.isLegal(board, from, to) then
|
if !MoveValidator.isLegal(ctx, from, to) then
|
||||||
MoveResult.IllegalMove
|
MoveResult.IllegalMove
|
||||||
else
|
else
|
||||||
val (newBoard, captured) = board.withMove(from, to)
|
val (newBoard, captured) = ctx.board.withMove(from, to)
|
||||||
GameRules.gameStatus(GameContext(newBoard), turn.opposite) match
|
val newCtx = ctx.copy(board = newBoard)
|
||||||
case PositionStatus.Normal => MoveResult.Moved(newBoard, captured, turn.opposite)
|
GameRules.gameStatus(newCtx, turn.opposite) match
|
||||||
case PositionStatus.InCheck => MoveResult.MovedInCheck(newBoard, captured, turn.opposite)
|
case PositionStatus.Normal => MoveResult.Moved(newCtx, captured, turn.opposite)
|
||||||
|
case PositionStatus.InCheck => MoveResult.MovedInCheck(newCtx, captured, turn.opposite)
|
||||||
case PositionStatus.Mated => MoveResult.Checkmate(turn)
|
case PositionStatus.Mated => MoveResult.Checkmate(turn)
|
||||||
case PositionStatus.Drawn => MoveResult.Stalemate
|
case PositionStatus.Drawn => MoveResult.Stalemate
|
||||||
|
|
||||||
/** Thin I/O shell: renders the board, reads a line, delegates to processMove,
|
/** Thin I/O shell: renders the board, reads a line, delegates to processMove,
|
||||||
* prints the outcome, and recurses until the game ends.
|
* prints the outcome, and recurses until the game ends.
|
||||||
*/
|
*/
|
||||||
def gameLoop(board: Board, turn: Color): Unit =
|
def gameLoop(ctx: GameContext, turn: Color): Unit =
|
||||||
println()
|
println()
|
||||||
print(Renderer.render(board))
|
print(Renderer.render(ctx.board))
|
||||||
println(s"${turn.label}'s turn. Enter move: ")
|
println(s"${turn.label}'s turn. Enter move: ")
|
||||||
val input = Option(StdIn.readLine()).getOrElse("quit").trim
|
val input = Option(StdIn.readLine()).getOrElse("quit").trim
|
||||||
processMove(board, turn, input) match
|
processMove(ctx, turn, input) match
|
||||||
case MoveResult.Quit =>
|
case MoveResult.Quit =>
|
||||||
println("Game over. Goodbye!")
|
println("Game over. Goodbye!")
|
||||||
case MoveResult.InvalidFormat(raw) =>
|
case MoveResult.InvalidFormat(raw) =>
|
||||||
println(s"Invalid move format '$raw'. Use coordinate notation, e.g. e2e4.")
|
println(s"Invalid move format '$raw'. Use coordinate notation, e.g. e2e4.")
|
||||||
gameLoop(board, turn)
|
gameLoop(ctx, turn)
|
||||||
case MoveResult.NoPiece =>
|
case MoveResult.NoPiece =>
|
||||||
println(s"No piece on ${Parser.parseMove(input).map(_._1).fold("?")(_.toString)}.")
|
println(s"No piece on ${Parser.parseMove(input).map(_._1).fold("?")(_.toString)}.")
|
||||||
gameLoop(board, turn)
|
gameLoop(ctx, turn)
|
||||||
case MoveResult.WrongColor =>
|
case MoveResult.WrongColor =>
|
||||||
println(s"That is not your piece.")
|
println(s"That is not your piece.")
|
||||||
gameLoop(board, turn)
|
gameLoop(ctx, turn)
|
||||||
case MoveResult.IllegalMove =>
|
case MoveResult.IllegalMove =>
|
||||||
println(s"Illegal move.")
|
println(s"Illegal move.")
|
||||||
gameLoop(board, turn)
|
gameLoop(ctx, turn)
|
||||||
case MoveResult.Moved(newBoard, captured, newTurn) =>
|
case MoveResult.Moved(newCtx, captured, newTurn) =>
|
||||||
val prevTurn = newTurn.opposite
|
val prevTurn = newTurn.opposite
|
||||||
captured.foreach: cap =>
|
captured.foreach: cap =>
|
||||||
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
||||||
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
||||||
gameLoop(newBoard, newTurn)
|
gameLoop(newCtx, newTurn)
|
||||||
case MoveResult.MovedInCheck(newBoard, captured, newTurn) =>
|
case MoveResult.MovedInCheck(newCtx, captured, newTurn) =>
|
||||||
val prevTurn = newTurn.opposite
|
val prevTurn = newTurn.opposite
|
||||||
captured.foreach: cap =>
|
captured.foreach: cap =>
|
||||||
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
val toSq = Parser.parseMove(input).map(_._2).fold("?")(_.toString)
|
||||||
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
println(s"${prevTurn.label} captures ${cap.color.label} ${cap.pieceType.label} on $toSq")
|
||||||
println(s"${newTurn.label} is in check!")
|
println(s"${newTurn.label} is in check!")
|
||||||
gameLoop(newBoard, newTurn)
|
gameLoop(newCtx, newTurn)
|
||||||
case MoveResult.Checkmate(winner) =>
|
case MoveResult.Checkmate(winner) =>
|
||||||
println(s"Checkmate! ${winner.label} wins.")
|
println(s"Checkmate! ${winner.label} wins.")
|
||||||
gameLoop(Board.initial, Color.White)
|
gameLoop(GameContext.initial, Color.White)
|
||||||
case MoveResult.Stalemate =>
|
case MoveResult.Stalemate =>
|
||||||
println("Stalemate! The game is a draw.")
|
println("Stalemate! The game is a draw.")
|
||||||
gameLoop(Board.initial, Color.White)
|
gameLoop(GameContext.initial, Color.White)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package de.nowchess.chess.controller
|
package de.nowchess.chess.controller
|
||||||
|
|
||||||
import de.nowchess.api.board.*
|
import de.nowchess.api.board.*
|
||||||
|
import de.nowchess.api.game.CastlingRights
|
||||||
|
import de.nowchess.chess.logic.{GameContext, CastleSide}
|
||||||
import org.scalatest.funsuite.AnyFunSuite
|
import org.scalatest.funsuite.AnyFunSuite
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
|
||||||
@@ -9,7 +11,7 @@ import java.io.ByteArrayInputStream
|
|||||||
class GameControllerTest extends AnyFunSuite with Matchers:
|
class GameControllerTest extends AnyFunSuite with Matchers:
|
||||||
|
|
||||||
private def sq(f: File, r: Rank): Square = Square(f, r)
|
private def sq(f: File, r: Rank): Square = Square(f, r)
|
||||||
private val initial = Board.initial
|
private val initial = GameContext.initial
|
||||||
|
|
||||||
// ──── processMove ────────────────────────────────────────────────────
|
// ──── processMove ────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -39,24 +41,24 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
|
|
||||||
test("processMove: legal pawn move returns Moved with updated board and flipped turn"):
|
test("processMove: legal pawn move returns Moved with updated board and flipped turn"):
|
||||||
GameController.processMove(initial, Color.White, "e2e4") match
|
GameController.processMove(initial, Color.White, "e2e4") match
|
||||||
case MoveResult.Moved(newBoard, captured, newTurn) =>
|
case MoveResult.Moved(newCtx, captured, newTurn) =>
|
||||||
newBoard.pieceAt(sq(File.E, Rank.R4)) shouldBe Some(Piece.WhitePawn)
|
newCtx.board.pieceAt(sq(File.E, Rank.R4)) shouldBe Some(Piece.WhitePawn)
|
||||||
newBoard.pieceAt(sq(File.E, Rank.R2)) shouldBe None
|
newCtx.board.pieceAt(sq(File.E, Rank.R2)) shouldBe None
|
||||||
captured shouldBe None
|
captured shouldBe None
|
||||||
newTurn shouldBe Color.Black
|
newTurn shouldBe Color.Black
|
||||||
case other => fail(s"Expected Moved, got $other")
|
case other => fail(s"Expected Moved, got $other")
|
||||||
|
|
||||||
test("processMove: legal capture returns Moved with the captured piece"):
|
test("processMove: legal capture returns Moved with the captured piece"):
|
||||||
val captureBoard = Board(Map(
|
val captureCtx = GameContext(Board(Map(
|
||||||
sq(File.E, Rank.R5) -> Piece.WhitePawn,
|
sq(File.E, Rank.R5) -> Piece.WhitePawn,
|
||||||
sq(File.D, Rank.R6) -> Piece.BlackPawn,
|
sq(File.D, Rank.R6) -> Piece.BlackPawn,
|
||||||
sq(File.H, Rank.R1) -> Piece.BlackKing,
|
sq(File.H, Rank.R1) -> Piece.BlackKing,
|
||||||
sq(File.H, Rank.R8) -> Piece.WhiteKing
|
sq(File.H, Rank.R8) -> Piece.WhiteKing
|
||||||
))
|
)))
|
||||||
GameController.processMove(captureBoard, Color.White, "e5d6") match
|
GameController.processMove(captureCtx, Color.White, "e5d6") match
|
||||||
case MoveResult.Moved(newBoard, captured, newTurn) =>
|
case MoveResult.Moved(newCtx, captured, newTurn) =>
|
||||||
captured shouldBe Some(Piece.BlackPawn)
|
captured shouldBe Some(Piece.BlackPawn)
|
||||||
newBoard.pieceAt(sq(File.D, Rank.R6)) shouldBe Some(Piece.WhitePawn)
|
newCtx.board.pieceAt(sq(File.D, Rank.R6)) shouldBe Some(Piece.WhitePawn)
|
||||||
newTurn shouldBe Color.Black
|
newTurn shouldBe Color.Black
|
||||||
case other => fail(s"Expected Moved, got $other")
|
case other => fail(s"Expected Moved, got $other")
|
||||||
|
|
||||||
@@ -68,33 +70,33 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
|
|
||||||
test("gameLoop: 'quit' exits cleanly without exception"):
|
test("gameLoop: 'quit' exits cleanly without exception"):
|
||||||
withInput("quit\n"):
|
withInput("quit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: EOF (null readLine) exits via quit fallback"):
|
test("gameLoop: EOF (null readLine) exits via quit fallback"):
|
||||||
withInput(""):
|
withInput(""):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: invalid format prints message and recurses until quit"):
|
test("gameLoop: invalid format prints message and recurses until quit"):
|
||||||
withInput("badmove\nquit\n"):
|
withInput("badmove\nquit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: NoPiece prints message and recurses until quit"):
|
test("gameLoop: NoPiece prints message and recurses until quit"):
|
||||||
// E3 is empty in the initial position
|
// E3 is empty in the initial position
|
||||||
withInput("e3e4\nquit\n"):
|
withInput("e3e4\nquit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: WrongColor prints message and recurses until quit"):
|
test("gameLoop: WrongColor prints message and recurses until quit"):
|
||||||
// E7 has a Black pawn; it is White's turn
|
// E7 has a Black pawn; it is White's turn
|
||||||
withInput("e7e6\nquit\n"):
|
withInput("e7e6\nquit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: IllegalMove prints message and recurses until quit"):
|
test("gameLoop: IllegalMove prints message and recurses until quit"):
|
||||||
withInput("e2e5\nquit\n"):
|
withInput("e2e5\nquit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: legal non-capture move recurses with new board then quits"):
|
test("gameLoop: legal non-capture move recurses with new board then quits"):
|
||||||
withInput("e2e4\nquit\n"):
|
withInput("e2e4\nquit\n"):
|
||||||
GameController.gameLoop(Board.initial, Color.White)
|
GameController.gameLoop(GameContext.initial, Color.White)
|
||||||
|
|
||||||
test("gameLoop: capture move prints capture message then recurses and quits"):
|
test("gameLoop: capture move prints capture message then recurses and quits"):
|
||||||
val captureBoard = Board(Map(
|
val captureBoard = Board(Map(
|
||||||
@@ -104,7 +106,7 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
sq(File.H, Rank.R8) -> Piece.WhiteKing
|
sq(File.H, Rank.R8) -> Piece.WhiteKing
|
||||||
))
|
))
|
||||||
withInput("e5d6\nquit\n"):
|
withInput("e5d6\nquit\n"):
|
||||||
GameController.gameLoop(captureBoard, Color.White)
|
GameController.gameLoop(GameContext(captureBoard), Color.White)
|
||||||
|
|
||||||
// ──── helpers ────────────────────────────────────────────────────────
|
// ──── helpers ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -118,12 +120,12 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
test("processMove: legal move that delivers check returns MovedInCheck"):
|
test("processMove: legal move that delivers check returns MovedInCheck"):
|
||||||
// White Ra1, Ka3; Black Kh8 — White plays Ra1-Ra8, Ra8 attacks rank 8 putting Kh8 in check
|
// White Ra1, Ka3; Black Kh8 — White plays Ra1-Ra8, Ra8 attacks rank 8 putting Kh8 in check
|
||||||
// Kh8 can escape to g7/g8/h7 so this is InCheck, not Mated
|
// Kh8 can escape to g7/g8/h7 so this is InCheck, not Mated
|
||||||
val b = Board(Map(
|
val ctx = GameContext(Board(Map(
|
||||||
sq(File.A, Rank.R1) -> Piece.WhiteRook,
|
sq(File.A, Rank.R1) -> Piece.WhiteRook,
|
||||||
sq(File.C, Rank.R3) -> Piece.WhiteKing,
|
sq(File.C, Rank.R3) -> Piece.WhiteKing,
|
||||||
sq(File.H, Rank.R8) -> Piece.BlackKing
|
sq(File.H, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
)))
|
||||||
GameController.processMove(b, Color.White, "a1a8") match
|
GameController.processMove(ctx, Color.White, "a1a8") match
|
||||||
case MoveResult.MovedInCheck(_, _, newTurn) => newTurn shouldBe Color.Black
|
case MoveResult.MovedInCheck(_, _, newTurn) => newTurn shouldBe Color.Black
|
||||||
case other => fail(s"Expected MovedInCheck, got $other")
|
case other => fail(s"Expected MovedInCheck, got $other")
|
||||||
|
|
||||||
@@ -131,24 +133,24 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
// White Qa1, Ka6; Black Ka8 — White plays Qa1-Qh8 (diagonal a1→h8)
|
// White Qa1, Ka6; Black Ka8 — White plays Qa1-Qh8 (diagonal a1→h8)
|
||||||
// After Qh8: White Qh8 + Ka6 vs Black Ka8 = checkmate (spec-verified position)
|
// After Qh8: White Qh8 + Ka6 vs Black Ka8 = checkmate (spec-verified position)
|
||||||
// Qa1 does NOT currently attack Ka8 — path along file A is blocked by Ka6
|
// Qa1 does NOT currently attack Ka8 — path along file A is blocked by Ka6
|
||||||
val b = Board(Map(
|
val ctx = GameContext(Board(Map(
|
||||||
sq(File.A, Rank.R1) -> Piece.WhiteQueen,
|
sq(File.A, Rank.R1) -> Piece.WhiteQueen,
|
||||||
sq(File.A, Rank.R6) -> Piece.WhiteKing,
|
sq(File.A, Rank.R6) -> Piece.WhiteKing,
|
||||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
)))
|
||||||
GameController.processMove(b, Color.White, "a1h8") match
|
GameController.processMove(ctx, Color.White, "a1h8") match
|
||||||
case MoveResult.Checkmate(winner) => winner shouldBe Color.White
|
case MoveResult.Checkmate(winner) => winner shouldBe Color.White
|
||||||
case other => fail(s"Expected Checkmate(White), got $other")
|
case other => fail(s"Expected Checkmate(White), got $other")
|
||||||
|
|
||||||
test("processMove: legal move that results in stalemate returns Stalemate"):
|
test("processMove: legal move that results in stalemate returns Stalemate"):
|
||||||
// White Qb1, Kc6; Black Ka8 — White plays Qb1-Qb6
|
// White Qb1, Kc6; Black Ka8 — White plays Qb1-Qb6
|
||||||
// After Qb6: White Qb6 + Kc6 vs Black Ka8 = stalemate (spec-verified position)
|
// After Qb6: White Qb6 + Kc6 vs Black Ka8 = stalemate (spec-verified position)
|
||||||
val b = Board(Map(
|
val ctx = GameContext(Board(Map(
|
||||||
sq(File.B, Rank.R1) -> Piece.WhiteQueen,
|
sq(File.B, Rank.R1) -> Piece.WhiteQueen,
|
||||||
sq(File.C, Rank.R6) -> Piece.WhiteKing,
|
sq(File.C, Rank.R6) -> Piece.WhiteKing,
|
||||||
sq(File.A, Rank.R8) -> Piece.BlackKing
|
sq(File.A, Rank.R8) -> Piece.BlackKing
|
||||||
))
|
)))
|
||||||
GameController.processMove(b, Color.White, "b1b6") match
|
GameController.processMove(ctx, Color.White, "b1b6") match
|
||||||
case MoveResult.Stalemate => succeed
|
case MoveResult.Stalemate => succeed
|
||||||
case other => fail(s"Expected Stalemate, got $other")
|
case other => fail(s"Expected Stalemate, got $other")
|
||||||
|
|
||||||
@@ -163,7 +165,7 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("a1h8\nquit\n"):
|
withInput("a1h8\nquit\n"):
|
||||||
GameController.gameLoop(b, Color.White)
|
GameController.gameLoop(GameContext(b), Color.White)
|
||||||
output should include("Checkmate! White wins.")
|
output should include("Checkmate! White wins.")
|
||||||
|
|
||||||
test("gameLoop: stalemate prints draw message and resets to new game"):
|
test("gameLoop: stalemate prints draw message and resets to new game"):
|
||||||
@@ -174,7 +176,7 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("b1b6\nquit\n"):
|
withInput("b1b6\nquit\n"):
|
||||||
GameController.gameLoop(b, Color.White)
|
GameController.gameLoop(GameContext(b), Color.White)
|
||||||
output should include("Stalemate! The game is a draw.")
|
output should include("Stalemate! The game is a draw.")
|
||||||
|
|
||||||
test("gameLoop: MovedInCheck without capture prints check message"):
|
test("gameLoop: MovedInCheck without capture prints check message"):
|
||||||
@@ -185,7 +187,7 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("a1a8\nquit\n"):
|
withInput("a1a8\nquit\n"):
|
||||||
GameController.gameLoop(b, Color.White)
|
GameController.gameLoop(GameContext(b), Color.White)
|
||||||
output should include("Black is in check!")
|
output should include("Black is in check!")
|
||||||
|
|
||||||
test("gameLoop: MovedInCheck with capture prints both capture and check message"):
|
test("gameLoop: MovedInCheck with capture prints both capture and check message"):
|
||||||
@@ -198,6 +200,6 @@ class GameControllerTest extends AnyFunSuite with Matchers:
|
|||||||
))
|
))
|
||||||
val output = captureOutput:
|
val output = captureOutput:
|
||||||
withInput("a1a8\nquit\n"):
|
withInput("a1a8\nquit\n"):
|
||||||
GameController.gameLoop(b, Color.White)
|
GameController.gameLoop(GameContext(b), Color.White)
|
||||||
output should include("captures")
|
output should include("captures")
|
||||||
output should include("Black is in check!")
|
output should include("Black is in check!")
|
||||||
|
|||||||
Reference in New Issue
Block a user