chore: Refactor chess logic to MVC pattern and enhance board representation

This commit is contained in:
2026-03-21 20:37:33 +01:00
parent 9c2456e928
commit 1f1d3b670f
18 changed files with 168 additions and 146 deletions
@@ -1,5 +1,7 @@
package de.nowchess.chess
import de.nowchess.api.board.{Board, Color, File, Piece, PieceType, Rank, Square}
import de.nowchess.chess.view.unicode
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*
@@ -10,9 +12,9 @@ class ModelTest:
assertEquals(Color.White, Color.Black.opposite)
@Test def squareLabel(): Unit =
assertEquals("a1", Square(0, 0).label)
assertEquals("e4", Square(4, 3).label)
assertEquals("h8", Square(7, 7).label)
assertEquals("a1", Square(File.A, Rank.R1).toString)
assertEquals("e4", Square(File.E, Rank.R4).toString)
assertEquals("h8", Square(File.H, Rank.R8).toString)
@Test def pieceUnicode(): Unit =
assertEquals("\u2654", Piece(Color.White, PieceType.King).unicode)
@@ -24,36 +26,34 @@ class ModelTest:
assertEquals(32, Board.initial.pieces.size)
@Test def initialWhiteKingOnE1(): Unit =
val e1 = Square(4, 0)
val e1 = Square(File.E, Rank.R1)
assertEquals(Some(Piece(Color.White, PieceType.King)), Board.initial.pieceAt(e1))
@Test def initialBlackQueenOnD8(): Unit =
val d8 = Square(3, 7)
val d8 = Square(File.D, Rank.R8)
assertEquals(Some(Piece(Color.Black, PieceType.Queen)), Board.initial.pieceAt(d8))
@Test def initialWhitePawnsOnRank2(): Unit =
for file <- 0 until 8 do
val sq = Square(file, 1)
for file <- File.values do
val sq = Square(file, Rank.R2)
assertEquals(Some(Piece(Color.White, PieceType.Pawn)), Board.initial.pieceAt(sq))
@Test def withMoveMovesAndLeavesOriginEmpty(): Unit =
val e2 = Square(4, 1)
val e4 = Square(4, 3)
val e2 = Square(File.E, Rank.R2)
val e4 = Square(File.E, Rank.R4)
val (newBoard, captured) = Board.initial.withMove(e2, e4)
assertEquals(None, newBoard.pieceAt(e2))
assertEquals(Some(Piece(Color.White, PieceType.Pawn)), newBoard.pieceAt(e4))
assertEquals(None, captured)
@Test def withMoveCaptureReturnsCapture(): Unit =
// Place a black pawn on e4 and a white pawn already there via two moves
val e2 = Square(4, 1)
val e4 = Square(4, 3)
val e2 = Square(File.E, Rank.R2)
val e4 = Square(File.E, Rank.R4)
val (board2, _) = Board.initial.withMove(e2, e4)
// Place black pawn on d4 manually for capture test
val d7 = Square(3, 6)
val d4 = Square(3, 3)
val d7 = Square(File.D, Rank.R7)
val d4 = Square(File.D, Rank.R4)
val (board3, _) = board2.withMove(d7, d4)
// Now white pawn on e4 captures black pawn on d4 (diagonal — no legality check)
// White pawn on e4 captures black pawn on d4 (diagonal — no legality check)
val (board4, cap) = board3.withMove(e4, d4)
assertEquals(Some(Piece(Color.Black, PieceType.Pawn)), cap)
assertEquals(Some(Piece(Color.White, PieceType.Pawn)), board4.pieceAt(d4))
@@ -1,18 +1,20 @@
package de.nowchess.chess
import de.nowchess.api.board.{File, Rank, Square}
import de.nowchess.chess.controller.Parser
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*
class ParserTest:
@Test def parsesValidMove(): Unit =
assertEquals(Some((Square(4, 1), Square(4, 3))), Parser.parseMove("e2e4"))
assertEquals(Some((Square(File.E, Rank.R2), Square(File.E, Rank.R4))), Parser.parseMove("e2e4"))
@Test def parsesKnightMove(): Unit =
assertEquals(Some((Square(6, 0), Square(5, 2))), Parser.parseMove("g1f3"))
assertEquals(Some((Square(File.G, Rank.R1), Square(File.F, Rank.R3))), Parser.parseMove("g1f3"))
@Test def ignoresExtraWhitespace(): Unit =
assertEquals(Some((Square(4, 1), Square(4, 3))), Parser.parseMove(" e2e4 "))
assertEquals(Some((Square(File.E, Rank.R2), Square(File.E, Rank.R4))), Parser.parseMove(" e2e4 "))
@Test def rejectsShortInput(): Unit =
assertEquals(None, Parser.parseMove("e2e"))
@@ -27,5 +29,5 @@ class ParserTest:
assertEquals(None, Parser.parseMove("e9e4"))
@Test def parsesUppercaseAsInvalid(): Unit =
// uppercase files are out of range after toLowerCase — stays lowercase internally
assertEquals(Some((Square(4, 1), Square(4, 3))), Parser.parseMove("E2E4"))
// Input is lowercased before parsing, so "E2E4" -> "e2e4" -> valid
assertEquals(Some((Square(File.E, Rank.R2), Square(File.E, Rank.R4))), Parser.parseMove("E2E4"))
@@ -1,5 +1,7 @@
package de.nowchess.chess
import de.nowchess.api.board.Board
import de.nowchess.chess.view.Renderer
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*