ddd-team1 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ddd-team1",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "ddd-team1": "./src/infrastructure/tui/index.tsx"
@@ -1,56 +1,56 @@
1
1
  import type { StandardAlgebraicNotationMove } from "./StandardAlgebraicNotationMove.ts";
2
- import { Piece } from "./Piece.ts";
3
2
  import { Position } from "./Position.ts";
4
3
  import { ValueObject } from "../shared";
5
- import { Rook } from "./pieces/Rook.ts";
6
- import type { PieceV2 } from "./PieceV2.ts";
4
+ import { Piece } from "./Piece.ts";
5
+ import { Rook, Knight, Bishop, King, Queen, Pawn } from "./pieces/index.ts";
6
+
7
7
 
8
- type BoardState = (Piece | PieceV2 | null)[][];
8
+ type BoardState = (Piece | null)[][];
9
9
 
10
10
  export class Board extends ValueObject {
11
11
  static initialBoardState: BoardState = [
12
12
  [
13
13
  new Rook("white"),
14
- Piece.WhiteKnight,
15
- Piece.WhiteBishop,
16
- Piece.WhiteQueen,
17
- Piece.WhiteKing,
18
- Piece.WhiteBishop,
19
- Piece.WhiteKnight,
14
+ new Knight("white"),
15
+ new Bishop("white"),
16
+ new Queen("white"),
17
+ new King("white"),
18
+ new Bishop("white"),
19
+ new Knight("white"),
20
20
  new Rook("white"),
21
21
  ],
22
22
  [
23
- Piece.WhitePawn,
24
- Piece.WhitePawn,
25
- Piece.WhitePawn,
26
- Piece.WhitePawn,
27
- Piece.WhitePawn,
28
- Piece.WhitePawn,
29
- Piece.WhitePawn,
30
- Piece.WhitePawn,
23
+ new Pawn("white"),
24
+ new Pawn("white"),
25
+ new Pawn("white"),
26
+ new Pawn("white"),
27
+ new Pawn("white"),
28
+ new Pawn("white"),
29
+ new Pawn("white"),
30
+ new Pawn("white"),
31
31
  ],
32
32
  [null, null, null, null, null, null, null, null],
33
33
  [null, null, null, null, null, null, null, null],
34
34
  [null, null, null, null, null, null, null, null],
35
35
  [null, null, null, null, null, null, null, null],
36
36
  [
37
- Piece.BlackPawn,
38
- Piece.BlackPawn,
39
- Piece.BlackPawn,
40
- Piece.BlackPawn,
41
- Piece.BlackPawn,
42
- Piece.BlackPawn,
43
- Piece.BlackPawn,
44
- Piece.BlackPawn,
37
+ new Pawn("black"),
38
+ new Pawn("black"),
39
+ new Pawn("black"),
40
+ new Pawn("black"),
41
+ new Pawn("black"),
42
+ new Pawn("black"),
43
+ new Pawn("black"),
44
+ new Pawn("black"),
45
45
  ],
46
46
  [
47
47
  new Rook("black"),
48
- Piece.BlackKnight,
49
- Piece.BlackBishop,
50
- Piece.BlackQueen,
51
- Piece.BlackKing,
52
- Piece.BlackBishop,
53
- Piece.BlackKnight,
48
+ new Knight("black"),
49
+ new Bishop("black"),
50
+ new Queen("black"),
51
+ new King("black"),
52
+ new Bishop("black"),
53
+ new Knight("black"),
54
54
  new Rook("black"),
55
55
  ],
56
56
  ];
@@ -110,55 +110,7 @@ export class Board extends ValueObject {
110
110
  if (capturedPiece?.color == this.color) {
111
111
  throw new Error("You cannot capture yourself");
112
112
  }
113
- if (move.piece instanceof Piece) {
114
- if (move.piece?.type === "pawn" && this.color === "white") {
115
- if (capturedPiece !== null) {
116
- if (position.file > 0) rulesToCheck.push([position.offset(-1, -1)]);
117
- if (position.file < 7) rulesToCheck.push([position.offset(1, -1)]);
118
- } else {
119
- let forwardMoves = [position.offset(0, -1)];
120
- if (position.rank === 3) {
121
- forwardMoves.push(position.offset(0, -2));
122
- }
123
- rulesToCheck.push(forwardMoves);
124
- }
125
- }
126
-
127
- if (move.piece?.type === "pawn" && this.color === "black") {
128
- if (capturedPiece !== null) {
129
- if (position.file > 0) rulesToCheck.push([position.offset(-1, 1)]);
130
- if (position.file < 7) rulesToCheck.push([position.offset(1, 1)]);
131
- } else {
132
- let forwardMoves = [position.offset(0, 1)];
133
- if (position.rank === 4) {
134
- forwardMoves.push(position.offset(0, 2));
135
- }
136
- rulesToCheck.push(forwardMoves);
137
- }
138
- }
139
-
140
- if (move.piece?.type === "bishop") {
141
- rulesToCheck = position.diagonalMask;
142
- }
143
-
144
- if (move.piece?.type === "knight") {
145
- rulesToCheck = position.jumpMask;
146
- }
147
-
148
- if (move.piece?.type === "queen") {
149
- rulesToCheck = position.straightMask.concat(position.diagonalMask);
150
- }
151
-
152
- if (move.piece?.type === "king") {
153
- rulesToCheck = position.straightMask
154
- .slice(0, 1)
155
- .concat(position.diagonalMask.slice(0, 1));
156
- }
157
- } else {
158
- if (move.piece instanceof Rook) {
159
- rulesToCheck = move.piece.getRulesToCheck(position);
160
- }
161
- }
113
+ rulesToCheck = move.piece?.getRulesToCheck(position, capturedPiece) ?? [];
162
114
 
163
115
  /*
164
116
  * checks each position in the rules to see if the piece at that position matches the move's piece, and returns
@@ -1,91 +1,85 @@
1
- import { ValueObject } from '../shared';
1
+ import { ValueObject } from "../shared";
2
+ import { Position } from "./Position.ts";
2
3
 
3
- export type PieceColor = 'white' | 'black';
4
- export type PieceType = 'king' | 'queen' | 'rook' | 'bishop' | 'knight' | 'pawn';
4
+ export type PieceColor = "white" | "black";
5
+ export type PieceType =
6
+ | "king"
7
+ | "queen"
8
+ | "rook"
9
+ | "bishop"
10
+ | "knight"
11
+ | "pawn";
5
12
 
6
13
  const ICONS: Record<PieceColor, Record<PieceType, string>> = {
7
- black: { king: '♔', queen: '♕', rook: '♖', bishop: '♗', knight: '♘', pawn: '♙' },
8
- white: { king: '♚', queen: '♛', rook: '♜', bishop: '♝', knight: '♞', pawn: '♟' },
14
+ black: {
15
+ king: "♔",
16
+ queen: "♕",
17
+ rook: "♖",
18
+ bishop: "♗",
19
+ knight: "♘",
20
+ pawn: "♙",
21
+ },
22
+ white: {
23
+ king: "♚",
24
+ queen: "♛",
25
+ rook: "♜",
26
+ bishop: "♝",
27
+ knight: "♞",
28
+ pawn: "♟",
29
+ },
9
30
  };
10
31
 
11
32
  const PIECE_LETTER: Record<string, PieceType> = {
12
- K: 'king',
13
- Q: 'queen',
14
- R: 'rook',
15
- B: 'bishop',
16
- N: 'knight',
17
- '': 'pawn',
33
+ K: "king",
34
+ Q: "queen",
35
+ R: "rook",
36
+ B: "bishop",
37
+ N: "knight",
38
+ "": "pawn",
18
39
  };
19
40
 
20
41
  const LETTER_PIECE: Record<PieceType, string> = {
21
- king: 'K',
22
- queen: 'Q',
23
- rook: 'R',
24
- bishop: 'B',
25
- knight: 'N',
26
- pawn: '',
27
- }
42
+ king: "K",
43
+ queen: "Q",
44
+ rook: "R",
45
+ bishop: "B",
46
+ knight: "N",
47
+ pawn: "",
48
+ };
28
49
 
29
- export class Piece extends ValueObject {
30
- private constructor(
31
- public readonly color: PieceColor,
32
- public readonly type: PieceType,
33
- ) {
34
- super();
35
- }
50
+ export abstract class Piece extends ValueObject {
51
+ private static registry = new Map<PieceType, new (color: PieceColor) => Piece>();
36
52
 
37
- get icon(): string {
38
- return ICONS[this.color][this.type];
53
+ static register(type: PieceType, constructor: new (color: PieceColor) => Piece) {
54
+ this.registry.set(type, constructor);
39
55
  }
40
56
 
41
- override toString(): string {
42
- return `${this.icon} (${this.color} ${this.type})`;
57
+ constructor(public readonly color: PieceColor) {
58
+ super();
43
59
  }
44
60
 
45
- toIcon(): string {
46
- return this.icon;
47
- }
61
+ abstract readonly icon: string;
62
+ abstract readonly char: string;
63
+ abstract getRulesToCheck(position: Position, getCapturedPiece?: any): Position[][];
48
64
 
49
- toChar(): string {
50
- return LETTER_PIECE[this.type];
65
+ override toString(): string {
66
+ return `${this.icon} (${this.color} ${this.constructor.name})`;
51
67
  }
52
68
 
53
69
  protected getAtomicValues(): any[] {
54
- return [this.color, this.type];
70
+ return [this.color, this.constructor.name];
55
71
  }
56
72
 
57
- static fromIcon(icon: string): Piece | null {
58
- for (const color in ICONS) {
59
- for (const type in ICONS[color as PieceColor]) {
60
- if (ICONS[color as PieceColor][type as PieceType] === icon) {
61
- return new Piece(color as PieceColor, type as PieceType);
62
- }
63
- }
64
- }
65
- return null;
66
- }
67
-
68
- static fromLetter(letter: string, color: 'white' | 'black'): Piece | null {
73
+ static fromLetter(letter: string, color: "white" | "black"): Piece | null {
69
74
  const pieceType = PIECE_LETTER[letter.toUpperCase()];
70
75
  if (!pieceType) {
71
76
  return null;
72
77
  }
73
- return new Piece(color, pieceType);
74
- }
75
-
76
- // White pieces
77
- static readonly WhiteKing = new Piece('white', 'king');
78
- static readonly WhiteQueen = new Piece('white', 'queen');
79
- static readonly WhiteRook = new Piece('white', 'rook');
80
- static readonly WhiteBishop = new Piece('white', 'bishop');
81
- static readonly WhiteKnight = new Piece('white', 'knight');
82
- static readonly WhitePawn = new Piece('white', 'pawn');
78
+ const PieceConstructor = this.registry.get(pieceType);
79
+ if (!PieceConstructor) {
80
+ throw new Error(`Piece type ${pieceType} not registered`);
81
+ }
83
82
 
84
- // Black pieces
85
- static readonly BlackKing = new Piece('black', 'king');
86
- static readonly BlackQueen = new Piece('black', 'queen');
87
- static readonly BlackRook = new Piece('black', 'rook');
88
- static readonly BlackBishop = new Piece('black', 'bishop');
89
- static readonly BlackKnight = new Piece('black', 'knight');
90
- static readonly BlackPawn = new Piece('black', 'pawn');
83
+ return new PieceConstructor(color);
84
+ }
91
85
  }
@@ -1,7 +1,6 @@
1
- import { Piece, type PieceType } from "./Piece.ts";
2
1
  import { Position } from "./Position.ts";
3
2
  import { ValueObject } from "../shared";
4
- import type { PieceV2 } from "./PieceV2.ts";
3
+ import { Piece } from "./Piece.ts";
5
4
  import { Rook } from "./pieces/Rook.ts";
6
5
 
7
6
  const SAN_REGEX =
@@ -24,7 +23,7 @@ export class StandardAlgebraicNotationMove extends ValueObject {
24
23
  private constructor(
25
24
  public readonly turn: number,
26
25
  public readonly destination: Position | null,
27
- public readonly piece: Piece | PieceV2 | null,
26
+ public readonly piece: Piece | null,
28
27
  public readonly isCapture: boolean,
29
28
  public readonly fromFile: number | null,
30
29
  public readonly fromRank: number | null,
@@ -65,10 +64,8 @@ export class StandardAlgebraicNotationMove extends ValueObject {
65
64
  }
66
65
 
67
66
  const destination = Position.fromAlgebraicNotation(g.toFile! + g.toRank!);
68
- let piece: Piece | PieceV2 | null = Piece.fromLetter(g.piece ?? "", color);
69
- if (g.piece == "R") {
70
- piece = new Rook(color);
71
- }
67
+ let piece: Piece | null = Piece.fromLetter(g.piece ?? "", color);
68
+
72
69
  const isCapture = g.capture === "x";
73
70
 
74
71
  // Disambiguation: fromFile/fromRank only count when toFile is also present
@@ -91,6 +88,7 @@ export class StandardAlgebraicNotationMove extends ValueObject {
91
88
  const promotion = g.promotion
92
89
  ? Piece.fromLetter(g.promotion!, color)
93
90
  : null;
91
+
94
92
  const check = (g.check as "+" | "#") ?? null;
95
93
 
96
94
  return new StandardAlgebraicNotationMove(
@@ -116,7 +114,7 @@ export class StandardAlgebraicNotationMove extends ValueObject {
116
114
  }
117
115
 
118
116
  if (this.piece) {
119
- result += this.piece.toChar();
117
+ result += this.piece.char;
120
118
  }
121
119
 
122
120
  if (this.fromFile !== null) {
@@ -134,7 +132,7 @@ export class StandardAlgebraicNotationMove extends ValueObject {
134
132
  result += this.destination!.toString();
135
133
 
136
134
  if (this.promotion) {
137
- result += `=${this.promotion.toChar()}`;
135
+ result += `=${this.promotion.char}`;
138
136
  }
139
137
 
140
138
  if (this.check) {
@@ -0,0 +1,31 @@
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
+ import { Position } from "../Position.ts";
3
+
4
+ export class Bishop extends Piece {
5
+ constructor(color: PieceColor) {
6
+ super(color);
7
+ }
8
+
9
+ get icon(): string {
10
+ if (this.color === "white") {
11
+ return "♝";
12
+ }
13
+ return "♗";
14
+ }
15
+
16
+ get char(): string {
17
+ return "B";
18
+ }
19
+
20
+ override toString(): string {
21
+ return `${this.icon} (${this.color} Bishop)`;
22
+ }
23
+
24
+ getRulesToCheck(position: Position) {
25
+ return position.diagonalMask;
26
+ }
27
+ }
28
+
29
+ Piece.register("bishop", Bishop);
30
+
31
+
@@ -0,0 +1,33 @@
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
+ import { Position } from "../Position.ts";
3
+
4
+ export class King extends Piece {
5
+ constructor(color: PieceColor) {
6
+ super(color);
7
+ }
8
+
9
+ get icon(): string {
10
+ if (this.color === "white") {
11
+ return "♚";
12
+ }
13
+ return "♔";
14
+ }
15
+
16
+ get char(): string {
17
+ return "K";
18
+ }
19
+
20
+ override toString(): string {
21
+ return `${this.icon} (${this.color} King)`;
22
+ }
23
+
24
+ getRulesToCheck(position: Position) {
25
+ return position.straightMask
26
+ .slice(0, 1)
27
+ .concat(position.diagonalMask.slice(0, 1));
28
+ }
29
+ }
30
+
31
+ Piece.register("king", King);
32
+
33
+
@@ -0,0 +1,31 @@
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
+ import { Position } from "../Position.ts";
3
+
4
+ export class Knight extends Piece {
5
+ constructor(color: PieceColor) {
6
+ super(color);
7
+ }
8
+
9
+ get icon(): string {
10
+ if (this.color === "white") {
11
+ return "♞";
12
+ }
13
+ return "♘";
14
+ }
15
+
16
+ get char(): string {
17
+ return "N";
18
+ }
19
+
20
+ override toString(): string {
21
+ return `${this.icon} (${this.color} Knight)`;
22
+ }
23
+
24
+ getRulesToCheck(position: Position) {
25
+ return position.jumpMask;
26
+ }
27
+ }
28
+
29
+ Piece.register("knight", Knight);
30
+
31
+
@@ -0,0 +1,53 @@
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
+ import { Position } from "../Position.ts";
3
+
4
+ export class Pawn extends Piece {
5
+ constructor(color: PieceColor) {
6
+ super(color);
7
+ }
8
+
9
+ get icon(): string {
10
+ if (this.color === "white") {
11
+ return "♟";
12
+ }
13
+ return "♙";
14
+ }
15
+
16
+ get char(): string {
17
+ return "";
18
+ }
19
+
20
+ override toString(): string {
21
+ return `${this.icon} (${this.color} Pawn)`;
22
+ }
23
+
24
+ getRulesToCheck(position: Position, capturedPiece: any = null) {
25
+ let rulesToCheck: Position[][] = [];
26
+
27
+ const colorRules = {
28
+ "white": {
29
+ direction: -1,
30
+ rank: 3
31
+ },
32
+ "black": {
33
+ direction: 1,
34
+ rank: 4
35
+ }
36
+ }
37
+
38
+ if (capturedPiece !== null) {
39
+ if (position.file > 0) rulesToCheck.push([position.offset(-1, colorRules[this.color].direction)]);
40
+ if (position.file < 7) rulesToCheck.push([position.offset(1, colorRules[this.color].direction)]);
41
+ } else {
42
+ let forwardMoves = [position.offset(0, colorRules[this.color].direction)];
43
+ if (position.rank === colorRules[this.color].rank) {
44
+ forwardMoves.push(position.offset(0, 2 * colorRules[this.color].direction));
45
+ }
46
+ rulesToCheck.push(forwardMoves);
47
+ }
48
+ return rulesToCheck;
49
+ }
50
+ }
51
+
52
+ Piece.register("pawn", Pawn);
53
+
@@ -0,0 +1,29 @@
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
+ import { Position } from "../Position.ts";
3
+
4
+ export class Queen extends Piece {
5
+ constructor(color: PieceColor) {
6
+ super(color);
7
+ }
8
+
9
+ get icon(): string {
10
+ if (this.color === "white") {
11
+ return "♛";
12
+ }
13
+ return "♕";
14
+ }
15
+
16
+ get char(): string {
17
+ return "Q";
18
+ }
19
+
20
+ override toString(): string {
21
+ return `${this.icon} (${this.color} Queen)`;
22
+ }
23
+
24
+ getRulesToCheck(position: Position) {
25
+ return position.straightMask.concat(position.diagonalMask);
26
+ }
27
+ }
28
+
29
+ Piece.register("queen", Queen);
@@ -1,7 +1,7 @@
1
- import { PieceV2, type PieceColor } from "../PieceV2";
1
+ import { Piece, type PieceColor } from "../Piece.ts";
2
2
  import { Position } from "../Position.ts";
3
3
 
4
- export class Rook extends PieceV2 {
4
+ export class Rook extends Piece {
5
5
  constructor(color: PieceColor) {
6
6
  super(color);
7
7
  }
@@ -17,10 +17,6 @@ export class Rook extends PieceV2 {
17
17
  return "R";
18
18
  }
19
19
 
20
- toChar(): string {
21
- return "R";
22
- }
23
-
24
20
  override toString(): string {
25
21
  return `${this.icon} (${this.color} Rook)`;
26
22
  }
@@ -29,3 +25,6 @@ export class Rook extends PieceV2 {
29
25
  return position.straightMask;
30
26
  }
31
27
  }
28
+
29
+ Piece.register("rook", Rook);
30
+
@@ -0,0 +1,7 @@
1
+ export { Bishop } from "./Bishop.ts";
2
+ export { King } from "./King.ts";
3
+ export { Knight } from "./Knight.ts";
4
+ export { Pawn } from "./Pawn.ts";
5
+ export { Queen } from "./Queen.ts";
6
+ export { Rook } from "./Rook.ts";
7
+
@@ -1,79 +0,0 @@
1
- import { ValueObject } from "../shared";
2
- import { Rook } from "./pieces/Rook";
3
-
4
- export type PieceColor = "white" | "black";
5
- export type PieceType =
6
- | "king"
7
- | "queen"
8
- | "rook"
9
- | "bishop"
10
- | "knight"
11
- | "pawn";
12
-
13
- const ICONS: Record<PieceColor, Record<PieceType, string>> = {
14
- black: {
15
- king: "♔",
16
- queen: "♕",
17
- rook: "♖",
18
- bishop: "♗",
19
- knight: "♘",
20
- pawn: "♙",
21
- },
22
- white: {
23
- king: "♚",
24
- queen: "♛",
25
- rook: "♜",
26
- bishop: "♝",
27
- knight: "♞",
28
- pawn: "♟",
29
- },
30
- };
31
-
32
- const PIECE_LETTER: Record<string, PieceType> = {
33
- K: "king",
34
- Q: "queen",
35
- R: "rook",
36
- B: "bishop",
37
- N: "knight",
38
- "": "pawn",
39
- };
40
-
41
- const LETTER_PIECE: Record<PieceType, string> = {
42
- king: "K",
43
- queen: "Q",
44
- rook: "R",
45
- bishop: "B",
46
- knight: "N",
47
- pawn: "",
48
- };
49
-
50
- export abstract class PieceV2 extends ValueObject {
51
- constructor(public readonly color: PieceColor) {
52
- super();
53
- }
54
-
55
- abstract readonly icon: string;
56
- abstract readonly char: string;
57
- abstract toChar(): string;
58
-
59
- override toString(): string {
60
- return `${this.icon} (${this.color} ${this.constructor.name})`;
61
- }
62
-
63
- protected getAtomicValues(): any[] {
64
- return [this.color, this.constructor.name];
65
- }
66
-
67
- static fromLetter(letter: string, color: "white" | "black"): PieceV2 | null {
68
- const pieceType = PIECE_LETTER[letter.toUpperCase()];
69
- if (!pieceType) {
70
- return null;
71
- }
72
- switch (pieceType) {
73
- case "rook":
74
- return new Rook(color);
75
- default:
76
- throw new Error(`Unknown letter ${letter}`);
77
- }
78
- }
79
- }