From 5554b8688a75d018c8e7947be26eeaf0108e562f Mon Sep 17 00:00:00 2001 From: eeoooue Date: Thu, 8 Jun 2023 17:44:08 +0100 Subject: [PATCH 1/6] added a screenshot to the README --- README.md | 9 +++------ chessboard.png | Bin 0 -> 73079 bytes 2 files changed, 3 insertions(+), 6 deletions(-) create mode 100644 chessboard.png diff --git a/README.md b/README.md index 3ad9012..d0edf6a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ -# [chessboard](https://eeoooue.github.io/chessboard/) - -moveable chess pieces on a chess board - -attempt to mimic [chess.com](http://chess.com) UI, using [Cburnett's chess pieces](https://commons.wikimedia.org/wiki/Category:SVG_chess_pieces) - +# [Chess](https://eeoooue.github.io/chessboard/) +A plain implementation of Chess in TypeScript, based on the [chess.com](http://chess.com) UI, using [Cburnett's chess pieces](https://commons.wikimedia.org/wiki/Category:SVG_chess_pieces). +![Chess Board](chessboard.png) diff --git a/chessboard.png b/chessboard.png new file mode 100644 index 0000000000000000000000000000000000000000..4384e7c476dde99e651bfd8578cc9ed8e7f780ef GIT binary patch literal 73079 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 Date: Thu, 8 Jun 2023 18:01:28 +0100 Subject: [PATCH 2/6] Pieces are no longer Observers, but BoardElement observers the ChessGame --- docs/board_element.js | 3 +++ docs/chess_game.js | 25 ++++++++++++++----------- docs/piece.js | 3 +-- docs/pieces/pawn.js | 4 ++-- docs/web_chess_game.js | 1 + src/board_element.ts | 9 +++++++-- src/chess_game.ts | 32 +++++++++++++++++++------------- src/piece.ts | 7 ++----- src/pieces/pawn.ts | 5 ++--- src/web_chess_game.ts | 3 +++ 10 files changed, 54 insertions(+), 38 deletions(-) diff --git a/docs/board_element.js b/docs/board_element.js index 6db8bd1..9175376 100644 --- a/docs/board_element.js +++ b/docs/board_element.js @@ -11,6 +11,9 @@ export class BoardElement { this.paintPieces(this.game.getPieces()); } update(subject) { + this.refresh(); + } + refresh() { this.clearPreviousBoard(); this.paintPieces(this.game.getPieces()); } diff --git a/docs/chess_game.js b/docs/chess_game.js index 79633ee..112f2df 100644 --- a/docs/chess_game.js +++ b/docs/chess_game.js @@ -12,13 +12,13 @@ export class ChessGame { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.notify(); + this.updateState(); } submitPromotionChoice(choice) { const pawn = this.getPromotingPawn(); pawn.promoteTo(choice); this.state = "ongoing"; - this.notify(); + this.updateState(); } getPromotingPawn() { const i = (this.getTurnPlayer() == "b") ? 0 : 7; @@ -57,6 +57,13 @@ export class ChessGame { piece.threatened = false; }); } + rebuildMoveOptions() { + const pieces = this.getPieces(); + this.possibleMoves = 0; + pieces.forEach((piece) => { + piece.populateMoveOptions(); + }); + } attach(observer) { this.observers.push(observer); } @@ -70,7 +77,6 @@ export class ChessGame { } } notify() { - this.possibleMoves = 0; this.observers.forEach((observer) => { observer.update(this); }); @@ -83,7 +89,11 @@ export class ChessGame { } concludeTurn() { this.turncount += 1; + this.updateState(); + } + updateState() { this.resetThreats(); + this.rebuildMoveOptions(); this.notify(); this.checkGameOver(); } @@ -95,7 +105,7 @@ export class ChessGame { } } makeMove(movingPiece, end) { - this.removePiece(end.i, end.j); + this.clearSquare(end.i, end.j); movingPiece.moveTo(end); this.concludeTurn(); if (movingPiece instanceof Pawn) { @@ -107,13 +117,6 @@ export class ChessGame { clearSquare(i, j) { this.boardState[i][j] = new EmptyPiece(this, i, j); } - removePiece(i, j) { - if (this.validCoordinates(i, j)) { - const piece = this.boardState[i][j]; - this.detach(piece); - this.clearSquare(i, j); - } - } legalPosition(i, j, colour) { if (this.validCoordinates(i, j)) { const piece = this.boardState[i][j]; diff --git a/docs/piece.js b/docs/piece.js index d93cb63..d327af4 100644 --- a/docs/piece.js +++ b/docs/piece.js @@ -11,9 +11,8 @@ export class Piece { this.i = i; this.j = j; this.threatened = false; - game.attach(this); } - update(subject) { + populateMoveOptions() { this.possibleMoves = []; this.moveOptions(this.i, this.j); if (this.colour == this.game.getTurnPlayer()) { diff --git a/docs/pieces/pawn.js b/docs/pieces/pawn.js index d6d8fc5..ffc0f05 100644 --- a/docs/pieces/pawn.js +++ b/docs/pieces/pawn.js @@ -36,7 +36,7 @@ export class Pawn extends Piece { if (this.j != end.j && targetPiece instanceof EmptyPiece) { const victim = this.boardState[this.i][end.j]; if (victim instanceof Pawn && victim.enPassantTurn == this.game.turncount) { - this.game.removePiece(this.i, end.j); + this.game.clearSquare(this.i, end.j); } } } @@ -105,7 +105,7 @@ export class Pawn extends Piece { } promoteTo(choice) { const newPiece = this.getPromotionPiece(choice); - this.game.removePiece(this.i, this.j); + this.game.clearSquare(this.i, this.j); this.boardState[this.i][this.j] = newPiece; } getPromotionPiece(choice) { diff --git a/docs/web_chess_game.js b/docs/web_chess_game.js index 252d3eb..d4be301 100644 --- a/docs/web_chess_game.js +++ b/docs/web_chess_game.js @@ -19,6 +19,7 @@ export class WebChessGame { const move = new BoardPosition(i, j); if (move) { this.game.submitSelection(move); + // this.boardElement.refresh(); if (this.game.moveTracker.active) { const piece = this.game.boardState[move.i][move.j]; const tile = this.boardElement.grid[move.i][move.j]; diff --git a/src/board_element.ts b/src/board_element.ts index 5c0f1b3..e583cde 100644 --- a/src/board_element.ts +++ b/src/board_element.ts @@ -28,6 +28,11 @@ export class BoardElement implements Observer { update(subject: Subject): void { + this.refresh(); + } + + refresh(): void { + this.clearPreviousBoard() this.paintPieces(this.game.getPieces()) } @@ -111,7 +116,7 @@ export class BoardElement implements Observer { } } - paintTile(list: HTMLElement[], i: number, j: number, paint: string){ + paintTile(list: HTMLElement[], i: number, j: number, paint: string) { const tile = this.createTile(paint); tile.addEventListener("click", () => { @@ -138,7 +143,7 @@ export class BoardElement implements Observer { }) } - illustrateMoveOption(position: BoardPosition){ + illustrateMoveOption(position: BoardPosition) { const piece: Piece = this.game.boardState[position.i][position.j] if (piece instanceof EmptyPiece) { diff --git a/src/chess_game.ts b/src/chess_game.ts index 5e1a1c5..a311582 100644 --- a/src/chess_game.ts +++ b/src/chess_game.ts @@ -24,7 +24,7 @@ export class ChessGame implements Subject { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.notify(); + this.updateState(); } submitPromotionChoice(choice: string) { @@ -33,7 +33,7 @@ export class ChessGame implements Subject { pawn.promoteTo(choice); this.state = "ongoing"; - this.notify(); + this.updateState(); } getPromotingPawn(): Pawn { @@ -86,6 +86,16 @@ export class ChessGame implements Subject { }) } + rebuildMoveOptions(){ + + const pieces = this.getPieces(); + this.possibleMoves = 0; + + pieces.forEach((piece) => { + piece.populateMoveOptions(); + }) + } + attach(observer: Observer): void { this.observers.push(observer); @@ -104,7 +114,6 @@ export class ChessGame implements Subject { notify(): void { - this.possibleMoves = 0; this.observers.forEach((observer) => { observer.update(this); }) @@ -123,7 +132,13 @@ export class ChessGame implements Subject { concludeTurn(): void { this.turncount += 1; + this.updateState(); + } + + updateState(){ + this.resetThreats(); + this.rebuildMoveOptions(); this.notify(); this.checkGameOver(); } @@ -139,7 +154,7 @@ export class ChessGame implements Subject { makeMove(movingPiece: Piece, end: BoardPosition) { - this.removePiece(end.i, end.j); + this.clearSquare(end.i, end.j); movingPiece.moveTo(end); this.concludeTurn(); @@ -155,15 +170,6 @@ export class ChessGame implements Subject { this.boardState[i][j] = new EmptyPiece(this, i, j); } - removePiece(i: number, j: number) { - - if (this.validCoordinates(i, j)) { - const piece: Piece = this.boardState[i][j]; - this.detach(piece); - this.clearSquare(i, j); - } - } - legalPosition(i: number, j: number, colour: string): boolean { if (this.validCoordinates(i, j)) { diff --git a/src/piece.ts b/src/piece.ts index 175e7d8..8c26e11 100644 --- a/src/piece.ts +++ b/src/piece.ts @@ -1,11 +1,9 @@ import { ChessGame } from './chess_game.js'; import { BoardPosition } from './board_position.js'; -import { Observer } from './observer.js'; -import { Subject } from "./subject.js"; import { AnalysisBoard } from './analysis_board.js'; -export class Piece implements Observer { +export class Piece { public boardState: Piece[][]; public game: ChessGame; @@ -26,10 +24,9 @@ export class Piece implements Observer { this.i = i; this.j = j; this.threatened = false; - game.attach(this); } - update(subject: Subject): void { + populateMoveOptions(): void { this.possibleMoves = []; this.moveOptions(this.i, this.j); diff --git a/src/pieces/pawn.ts b/src/pieces/pawn.ts index e01f3a8..a621957 100644 --- a/src/pieces/pawn.ts +++ b/src/pieces/pawn.ts @@ -3,7 +3,6 @@ import { BoardPosition } from '../board_position.js'; import { ChessGame } from '../chess_game.js'; import { Piece } from "../piece.js"; import { EmptyPiece } from './empty_piece.js'; - import { Bishop } from './bishop.js'; import { Knight } from './knight.js'; import { Rook } from './rook.js'; @@ -54,7 +53,7 @@ export class Pawn extends Piece { const victim = this.boardState[this.i][end.j] if (victim instanceof Pawn && victim.enPassantTurn == this.game.turncount){ - this.game.removePiece(this.i, end.j); + this.game.clearSquare(this.i, end.j); } } } @@ -138,7 +137,7 @@ export class Pawn extends Piece { promoteTo(choice: string){ const newPiece = this.getPromotionPiece(choice); - this.game.removePiece(this.i, this.j); + this.game.clearSquare(this.i, this.j); this.boardState[this.i][this.j] = newPiece; } diff --git a/src/web_chess_game.ts b/src/web_chess_game.ts index 886f746..c1d5c42 100644 --- a/src/web_chess_game.ts +++ b/src/web_chess_game.ts @@ -35,6 +35,8 @@ export class WebChessGame { if (move) { this.game.submitSelection(move); + // this.boardElement.refresh(); + if (this.game.moveTracker.active){ const piece : Piece = this.game.boardState[move.i][move.j] const tile = this.boardElement.grid[move.i][move.j] @@ -42,6 +44,7 @@ export class WebChessGame { const options: BoardPosition[] = piece.possibleMoves; this.boardElement.paintMoveOptions(options); } + if (this.game.state == "checkmate" || this.game.state == "stalemate"){ this.showEndCard(); From 1e6113a04808caffee606ff380ad8b1bd10229f4 Mon Sep 17 00:00:00 2001 From: eeoooue Date: Thu, 8 Jun 2023 19:38:32 +0100 Subject: [PATCH 3/6] Revert "Pieces are no longer Observers, but BoardElement observers the ChessGame" This reverts commit 783bc790f11295293f10c72b383c584fe3d96b0e. --- docs/board_element.js | 3 --- docs/chess_game.js | 25 +++++++++++-------------- docs/piece.js | 3 ++- docs/pieces/pawn.js | 4 ++-- docs/web_chess_game.js | 1 - src/board_element.ts | 9 ++------- src/chess_game.ts | 32 +++++++++++++------------------- src/piece.ts | 7 +++++-- src/pieces/pawn.ts | 5 +++-- src/web_chess_game.ts | 3 --- 10 files changed, 38 insertions(+), 54 deletions(-) diff --git a/docs/board_element.js b/docs/board_element.js index 9175376..6db8bd1 100644 --- a/docs/board_element.js +++ b/docs/board_element.js @@ -11,9 +11,6 @@ export class BoardElement { this.paintPieces(this.game.getPieces()); } update(subject) { - this.refresh(); - } - refresh() { this.clearPreviousBoard(); this.paintPieces(this.game.getPieces()); } diff --git a/docs/chess_game.js b/docs/chess_game.js index 112f2df..79633ee 100644 --- a/docs/chess_game.js +++ b/docs/chess_game.js @@ -12,13 +12,13 @@ export class ChessGame { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.updateState(); + this.notify(); } submitPromotionChoice(choice) { const pawn = this.getPromotingPawn(); pawn.promoteTo(choice); this.state = "ongoing"; - this.updateState(); + this.notify(); } getPromotingPawn() { const i = (this.getTurnPlayer() == "b") ? 0 : 7; @@ -57,13 +57,6 @@ export class ChessGame { piece.threatened = false; }); } - rebuildMoveOptions() { - const pieces = this.getPieces(); - this.possibleMoves = 0; - pieces.forEach((piece) => { - piece.populateMoveOptions(); - }); - } attach(observer) { this.observers.push(observer); } @@ -77,6 +70,7 @@ export class ChessGame { } } notify() { + this.possibleMoves = 0; this.observers.forEach((observer) => { observer.update(this); }); @@ -89,11 +83,7 @@ export class ChessGame { } concludeTurn() { this.turncount += 1; - this.updateState(); - } - updateState() { this.resetThreats(); - this.rebuildMoveOptions(); this.notify(); this.checkGameOver(); } @@ -105,7 +95,7 @@ export class ChessGame { } } makeMove(movingPiece, end) { - this.clearSquare(end.i, end.j); + this.removePiece(end.i, end.j); movingPiece.moveTo(end); this.concludeTurn(); if (movingPiece instanceof Pawn) { @@ -117,6 +107,13 @@ export class ChessGame { clearSquare(i, j) { this.boardState[i][j] = new EmptyPiece(this, i, j); } + removePiece(i, j) { + if (this.validCoordinates(i, j)) { + const piece = this.boardState[i][j]; + this.detach(piece); + this.clearSquare(i, j); + } + } legalPosition(i, j, colour) { if (this.validCoordinates(i, j)) { const piece = this.boardState[i][j]; diff --git a/docs/piece.js b/docs/piece.js index d327af4..d93cb63 100644 --- a/docs/piece.js +++ b/docs/piece.js @@ -11,8 +11,9 @@ export class Piece { this.i = i; this.j = j; this.threatened = false; + game.attach(this); } - populateMoveOptions() { + update(subject) { this.possibleMoves = []; this.moveOptions(this.i, this.j); if (this.colour == this.game.getTurnPlayer()) { diff --git a/docs/pieces/pawn.js b/docs/pieces/pawn.js index ffc0f05..d6d8fc5 100644 --- a/docs/pieces/pawn.js +++ b/docs/pieces/pawn.js @@ -36,7 +36,7 @@ export class Pawn extends Piece { if (this.j != end.j && targetPiece instanceof EmptyPiece) { const victim = this.boardState[this.i][end.j]; if (victim instanceof Pawn && victim.enPassantTurn == this.game.turncount) { - this.game.clearSquare(this.i, end.j); + this.game.removePiece(this.i, end.j); } } } @@ -105,7 +105,7 @@ export class Pawn extends Piece { } promoteTo(choice) { const newPiece = this.getPromotionPiece(choice); - this.game.clearSquare(this.i, this.j); + this.game.removePiece(this.i, this.j); this.boardState[this.i][this.j] = newPiece; } getPromotionPiece(choice) { diff --git a/docs/web_chess_game.js b/docs/web_chess_game.js index d4be301..252d3eb 100644 --- a/docs/web_chess_game.js +++ b/docs/web_chess_game.js @@ -19,7 +19,6 @@ export class WebChessGame { const move = new BoardPosition(i, j); if (move) { this.game.submitSelection(move); - // this.boardElement.refresh(); if (this.game.moveTracker.active) { const piece = this.game.boardState[move.i][move.j]; const tile = this.boardElement.grid[move.i][move.j]; diff --git a/src/board_element.ts b/src/board_element.ts index e583cde..5c0f1b3 100644 --- a/src/board_element.ts +++ b/src/board_element.ts @@ -28,11 +28,6 @@ export class BoardElement implements Observer { update(subject: Subject): void { - this.refresh(); - } - - refresh(): void { - this.clearPreviousBoard() this.paintPieces(this.game.getPieces()) } @@ -116,7 +111,7 @@ export class BoardElement implements Observer { } } - paintTile(list: HTMLElement[], i: number, j: number, paint: string) { + paintTile(list: HTMLElement[], i: number, j: number, paint: string){ const tile = this.createTile(paint); tile.addEventListener("click", () => { @@ -143,7 +138,7 @@ export class BoardElement implements Observer { }) } - illustrateMoveOption(position: BoardPosition) { + illustrateMoveOption(position: BoardPosition){ const piece: Piece = this.game.boardState[position.i][position.j] if (piece instanceof EmptyPiece) { diff --git a/src/chess_game.ts b/src/chess_game.ts index a311582..5e1a1c5 100644 --- a/src/chess_game.ts +++ b/src/chess_game.ts @@ -24,7 +24,7 @@ export class ChessGame implements Subject { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.updateState(); + this.notify(); } submitPromotionChoice(choice: string) { @@ -33,7 +33,7 @@ export class ChessGame implements Subject { pawn.promoteTo(choice); this.state = "ongoing"; - this.updateState(); + this.notify(); } getPromotingPawn(): Pawn { @@ -86,16 +86,6 @@ export class ChessGame implements Subject { }) } - rebuildMoveOptions(){ - - const pieces = this.getPieces(); - this.possibleMoves = 0; - - pieces.forEach((piece) => { - piece.populateMoveOptions(); - }) - } - attach(observer: Observer): void { this.observers.push(observer); @@ -114,6 +104,7 @@ export class ChessGame implements Subject { notify(): void { + this.possibleMoves = 0; this.observers.forEach((observer) => { observer.update(this); }) @@ -132,13 +123,7 @@ export class ChessGame implements Subject { concludeTurn(): void { this.turncount += 1; - this.updateState(); - } - - updateState(){ - this.resetThreats(); - this.rebuildMoveOptions(); this.notify(); this.checkGameOver(); } @@ -154,7 +139,7 @@ export class ChessGame implements Subject { makeMove(movingPiece: Piece, end: BoardPosition) { - this.clearSquare(end.i, end.j); + this.removePiece(end.i, end.j); movingPiece.moveTo(end); this.concludeTurn(); @@ -170,6 +155,15 @@ export class ChessGame implements Subject { this.boardState[i][j] = new EmptyPiece(this, i, j); } + removePiece(i: number, j: number) { + + if (this.validCoordinates(i, j)) { + const piece: Piece = this.boardState[i][j]; + this.detach(piece); + this.clearSquare(i, j); + } + } + legalPosition(i: number, j: number, colour: string): boolean { if (this.validCoordinates(i, j)) { diff --git a/src/piece.ts b/src/piece.ts index 8c26e11..175e7d8 100644 --- a/src/piece.ts +++ b/src/piece.ts @@ -1,9 +1,11 @@ import { ChessGame } from './chess_game.js'; import { BoardPosition } from './board_position.js'; +import { Observer } from './observer.js'; +import { Subject } from "./subject.js"; import { AnalysisBoard } from './analysis_board.js'; -export class Piece { +export class Piece implements Observer { public boardState: Piece[][]; public game: ChessGame; @@ -24,9 +26,10 @@ export class Piece { this.i = i; this.j = j; this.threatened = false; + game.attach(this); } - populateMoveOptions(): void { + update(subject: Subject): void { this.possibleMoves = []; this.moveOptions(this.i, this.j); diff --git a/src/pieces/pawn.ts b/src/pieces/pawn.ts index a621957..e01f3a8 100644 --- a/src/pieces/pawn.ts +++ b/src/pieces/pawn.ts @@ -3,6 +3,7 @@ import { BoardPosition } from '../board_position.js'; import { ChessGame } from '../chess_game.js'; import { Piece } from "../piece.js"; import { EmptyPiece } from './empty_piece.js'; + import { Bishop } from './bishop.js'; import { Knight } from './knight.js'; import { Rook } from './rook.js'; @@ -53,7 +54,7 @@ export class Pawn extends Piece { const victim = this.boardState[this.i][end.j] if (victim instanceof Pawn && victim.enPassantTurn == this.game.turncount){ - this.game.clearSquare(this.i, end.j); + this.game.removePiece(this.i, end.j); } } } @@ -137,7 +138,7 @@ export class Pawn extends Piece { promoteTo(choice: string){ const newPiece = this.getPromotionPiece(choice); - this.game.clearSquare(this.i, this.j); + this.game.removePiece(this.i, this.j); this.boardState[this.i][this.j] = newPiece; } diff --git a/src/web_chess_game.ts b/src/web_chess_game.ts index c1d5c42..886f746 100644 --- a/src/web_chess_game.ts +++ b/src/web_chess_game.ts @@ -35,8 +35,6 @@ export class WebChessGame { if (move) { this.game.submitSelection(move); - // this.boardElement.refresh(); - if (this.game.moveTracker.active){ const piece : Piece = this.game.boardState[move.i][move.j] const tile = this.boardElement.grid[move.i][move.j] @@ -44,7 +42,6 @@ export class WebChessGame { const options: BoardPosition[] = piece.possibleMoves; this.boardElement.paintMoveOptions(options); } - if (this.game.state == "checkmate" || this.game.state == "stalemate"){ this.showEndCard(); From c8cb7b3e2596ebd33c86e63352cfe5fd8f1c508d Mon Sep 17 00:00:00 2001 From: eeoooue Date: Thu, 8 Jun 2023 19:41:50 +0100 Subject: [PATCH 4/6] BoardElement no longer implements Observer --- src/board_element.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/board_element.ts b/src/board_element.ts index 5c0f1b3..0381f5d 100644 --- a/src/board_element.ts +++ b/src/board_element.ts @@ -5,10 +5,9 @@ import { BoardPosition } from "./board_position.js"; import { Piece } from "./piece.js"; import { EmptyPiece } from "./pieces/empty_piece.js"; import { King } from "./pieces/king.js"; -import { Observer } from "./observer.js"; import { Subject } from "./subject.js"; -export class BoardElement implements Observer { +export class BoardElement { public boardContainer: HTMLElement; public grid: HTMLElement[][] = []; @@ -20,13 +19,12 @@ export class BoardElement implements Observer { this.parent = parent; this.boardContainer = boardContainer; this.game = game; - this.game.attach(this); this.paintTiles() this.paintPieces(this.game.getPieces()) } - update(subject: Subject): void { + repaint(): void { this.clearPreviousBoard() this.paintPieces(this.game.getPieces()) From 99f5528a0db5b196293a2aa0e7667ff739e6218b Mon Sep 17 00:00:00 2001 From: eeoooue Date: Thu, 8 Jun 2023 19:51:20 +0100 Subject: [PATCH 5/6] now using a refresh() method in WebChessGame with Pieces that implement Observer --- docs/board_element.js | 3 +-- docs/chess_game.js | 7 +++++-- docs/promotion_card.js | 1 + docs/web_chess_game.js | 4 ++++ src/chess_game.ts | 9 +++++++-- src/promotion_card.ts | 1 + src/web_chess_game.ts | 7 +++++++ 7 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/board_element.js b/docs/board_element.js index 6db8bd1..25bff25 100644 --- a/docs/board_element.js +++ b/docs/board_element.js @@ -6,11 +6,10 @@ export class BoardElement { this.parent = parent; this.boardContainer = boardContainer; this.game = game; - this.game.attach(this); this.paintTiles(); this.paintPieces(this.game.getPieces()); } - update(subject) { + repaint() { this.clearPreviousBoard(); this.paintPieces(this.game.getPieces()); } diff --git a/docs/chess_game.js b/docs/chess_game.js index 79633ee..4609b0f 100644 --- a/docs/chess_game.js +++ b/docs/chess_game.js @@ -12,13 +12,13 @@ export class ChessGame { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.notify(); + this.updateState(); } submitPromotionChoice(choice) { const pawn = this.getPromotingPawn(); pawn.promoteTo(choice); this.state = "ongoing"; - this.notify(); + this.updateState(); } getPromotingPawn() { const i = (this.getTurnPlayer() == "b") ? 0 : 7; @@ -83,6 +83,9 @@ export class ChessGame { } concludeTurn() { this.turncount += 1; + this.updateState(); + } + updateState() { this.resetThreats(); this.notify(); this.checkGameOver(); diff --git a/docs/promotion_card.js b/docs/promotion_card.js index 1c0080b..c6956f5 100644 --- a/docs/promotion_card.js +++ b/docs/promotion_card.js @@ -39,5 +39,6 @@ export class PromotionCard { submitChoice(text) { this.game.submitPromotionChoice(text); this.element.remove(); + this.parent.refresh(); } } diff --git a/docs/web_chess_game.js b/docs/web_chess_game.js index 252d3eb..cc0e662 100644 --- a/docs/web_chess_game.js +++ b/docs/web_chess_game.js @@ -19,6 +19,7 @@ export class WebChessGame { const move = new BoardPosition(i, j); if (move) { this.game.submitSelection(move); + this.refresh(); if (this.game.moveTracker.active) { const piece = this.game.boardState[move.i][move.j]; const tile = this.boardElement.grid[move.i][move.j]; @@ -34,6 +35,9 @@ export class WebChessGame { } } } + refresh() { + this.boardElement.repaint(); + } askPromotionOption() { const promotionCard = new PromotionCard(this, this.game); this.boardContainer.appendChild(promotionCard.element); diff --git a/src/chess_game.ts b/src/chess_game.ts index 5e1a1c5..972eb5b 100644 --- a/src/chess_game.ts +++ b/src/chess_game.ts @@ -24,7 +24,7 @@ export class ChessGame implements Subject { this.moveTracker = new MoveTracker(this); this.boardBuilder = new BoardBuilder(this); this.state = "ongoing"; - this.notify(); + this.updateState(); } submitPromotionChoice(choice: string) { @@ -33,7 +33,7 @@ export class ChessGame implements Subject { pawn.promoteTo(choice); this.state = "ongoing"; - this.notify(); + this.updateState(); } getPromotingPawn(): Pawn { @@ -123,6 +123,11 @@ export class ChessGame implements Subject { concludeTurn(): void { this.turncount += 1; + this.updateState(); + } + + updateState(): void { + this.resetThreats(); this.notify(); this.checkGameOver(); diff --git a/src/promotion_card.ts b/src/promotion_card.ts index 6692a56..973d48a 100644 --- a/src/promotion_card.ts +++ b/src/promotion_card.ts @@ -66,5 +66,6 @@ export class PromotionCard { this.game.submitPromotionChoice(text); this.element.remove(); + this.parent.refresh(); } } \ No newline at end of file diff --git a/src/web_chess_game.ts b/src/web_chess_game.ts index 886f746..143a785 100644 --- a/src/web_chess_game.ts +++ b/src/web_chess_game.ts @@ -35,6 +35,8 @@ export class WebChessGame { if (move) { this.game.submitSelection(move); + this.refresh(); + if (this.game.moveTracker.active){ const piece : Piece = this.game.boardState[move.i][move.j] const tile = this.boardElement.grid[move.i][move.j] @@ -53,6 +55,11 @@ export class WebChessGame { } } + refresh(): void { + + this.boardElement.repaint(); + } + askPromotionOption(): void { const promotionCard = new PromotionCard(this, this.game); From 439be0428462ea41ed667a6dfd359c16f5189ed3 Mon Sep 17 00:00:00 2001 From: eeoooue Date: Thu, 8 Jun 2023 19:57:34 +0100 Subject: [PATCH 6/6] moved more code into Refresh() method & simplified processMove() --- docs/web_chess_game.js | 30 ++++++++++++++---------------- src/web_chess_game.ts | 36 +++++++++++++++++------------------- 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/docs/web_chess_game.js b/docs/web_chess_game.js index cc0e662..19dd89d 100644 --- a/docs/web_chess_game.js +++ b/docs/web_chess_game.js @@ -17,26 +17,24 @@ export class WebChessGame { } processMove(i, j) { const move = new BoardPosition(i, j); - if (move) { - this.game.submitSelection(move); - this.refresh(); - if (this.game.moveTracker.active) { - const piece = this.game.boardState[move.i][move.j]; - const tile = this.boardElement.grid[move.i][move.j]; - tile.classList.add("highlighted"); - const options = piece.possibleMoves; - this.boardElement.paintMoveOptions(options); - } - if (this.game.state == "checkmate" || this.game.state == "stalemate") { - this.showEndCard(); - } - if (this.game.state == "promotion") { - this.askPromotionOption(); - } + this.game.submitSelection(move); + this.refresh(); + if (this.game.moveTracker.active) { + const piece = this.game.boardState[move.i][move.j]; + const tile = this.boardElement.grid[move.i][move.j]; + tile.classList.add("highlighted"); + const options = piece.possibleMoves; + this.boardElement.paintMoveOptions(options); } } refresh() { this.boardElement.repaint(); + if (this.game.state == "checkmate" || this.game.state == "stalemate") { + this.showEndCard(); + } + if (this.game.state == "promotion") { + this.askPromotionOption(); + } } askPromotionOption() { const promotionCard = new PromotionCard(this, this.game); diff --git a/src/web_chess_game.ts b/src/web_chess_game.ts index 143a785..de3e97c 100644 --- a/src/web_chess_game.ts +++ b/src/web_chess_game.ts @@ -33,31 +33,29 @@ export class WebChessGame { const move: BoardPosition = new BoardPosition(i, j); - if (move) { - this.game.submitSelection(move); - this.refresh(); - - if (this.game.moveTracker.active){ - const piece : Piece = this.game.boardState[move.i][move.j] - const tile = this.boardElement.grid[move.i][move.j] - tile.classList.add("highlighted") - const options: BoardPosition[] = piece.possibleMoves; - this.boardElement.paintMoveOptions(options); - } - - if (this.game.state == "checkmate" || this.game.state == "stalemate"){ - this.showEndCard(); - } - - if (this.game.state == "promotion"){ - this.askPromotionOption(); - } + this.game.submitSelection(move); + this.refresh(); + + if (this.game.moveTracker.active){ + const piece : Piece = this.game.boardState[move.i][move.j] + const tile = this.boardElement.grid[move.i][move.j] + tile.classList.add("highlighted") + const options: BoardPosition[] = piece.possibleMoves; + this.boardElement.paintMoveOptions(options); } } refresh(): void { this.boardElement.repaint(); + + if (this.game.state == "checkmate" || this.game.state == "stalemate"){ + this.showEndCard(); + } + + if (this.game.state == "promotion"){ + this.askPromotionOption(); + } } askPromotionOption(): void {