Repository: jhlywa/chess.js (TypeScript)

Issue:
[Feature Request] (Bug?) moves() does not filter by specified piece
chess.js@1.0.0-beta.3

moves() currently returns the legal moves for all pieces when attempting to filter by a specific type of piece.

This is listed in the README as a feature, however moves() doesn't actually look for a 'piece' property in the passed object.

Test Code:
```
async function test(){
  let Chess = await import('chess.js');
  const chess = new Chess.Chess();
  
  let move = 'bc4';
  console.log(chess.ascii());
  console.log(chess.moves({piece: 'P'}));
  
  console.log(chess.moves({ piece: 'n' })
  );
}

test();
```

Result:
```

   +------------------------+
 8 | r  n  b  q  k  b  n  r |
 7 | p  p  p  p  p  p  p  p |
 6 | .  .  .  .  .  .  .  . |
 5 | .  .  .  .  .  .  .  . |
 4 | .  .  .  .  .  .  .  . |
 3 | .  .  .  .  .  .  .  . |
 2 | P  P  P  P  P  P  P  P |
 1 | R  N  B  Q  K  B  N  R |
   +------------------------+
     a  b  c  d  e  f  g  h
[
  'a3',  'a4',  'b3',  'b4',
  'c3',  'c4',  'd3',  'd4',
  'e3',  'e4',  'f3',  'f4',
  'g3',  'g4',  'h3',  'h4',
  'Na3', 'Nc3', 'Nf3', 'Nh3'
]
[
  'a3',  'a4',  'b3',  'b4',
  'c3',  'c4',  'd3',  'd4',
  'e3',  'e4',  'f3',  'f4',
  'g3',  'g4',  'h3',  'h4',
  'Na3', 'Nc3', 'Nf3', 'Nh3'
]
```
move() in chess.ts:
```
moves(): string[]
  moves({ square }: { square: Square }): string[]
  moves({ verbose, square }: { verbose: true; square?: Square }): Move[]
  moves({ verbose, square }: { verbose: false; square?: Square }): string[]
  moves({
    verbose,
    square,
  }: {
    verbose?: boolean
    square?: Square
  }): string[] | Move[]
  moves({
    verbose = false,
    square = undefined,
  }: { verbose?: boolean; square?: Square } = {}) {
    const moves = this._moves({ square })

    if (verbose) {
      return moves.map((move) => this._makePretty(move))
    } else {
      return moves.map((move) => this._moveToSan(move, moves))
    }
  }
```

_moves() does filter by piece but is obviously more geared towards internal use:
`  console.log(chess._moves({piece: 'n'}));
`
```
   +------------------------+
 8 | r  n  b  q  k  b  n  r |
 7 | p  p  p  p  p  p  p  p |
 6 | .  .  .  .  .  .  .  . |
 5 | .  .  .  .  .  .  .  . |
 4 | .  .  .  .  .  .  .  . |
 3 | .  .  .  .  .  .  .  . |
 2 | P  P  P  P  P  P  P  P |
 1 | R  N  B  Q  K  B  N  R |
   +------------------------+
     a  b  c  d  e  f  g  h
[
  {
    color: 'w',
    from: 113,
    to: 80,
    piece: 'n',
    captured: undefined,
    flags: 1
  },
  etc...
```


Discussion:

Patch:
diff --git a/src/chess.ts b/src/chess.ts
index cc265344..b21f7740 100644
--- a/src/chess.ts
+++ b/src/chess.ts
@@ -960,20 +960,30 @@ export class Chess {
 
   moves(): string[]
   moves({ square }: { square: Square }): string[]
+  moves({ piece }: { piece: PieceSymbol }): string[]
+
+  moves({ square, piece }: { square: Square; piece: PieceSymbol }): string[]
+
   moves({ verbose, square }: { verbose: true; square?: Square }): Move[]
   moves({ verbose, square }: { verbose: false; square?: Square }): string[]
-  moves({
-    verbose,
-    square,
-  }: {
-    verbose?: boolean
-    square?: Square
-  }): string[] | Move[]
+  moves({ verbose, square }: { verbose?: boolean;  square?: Square}): string[] | Move[]
+
+  moves({ verbose, piece }: { verbose: true; piece?: PieceSymbol }): Move[]
+  moves({ verbose, piece }: { verbose: false; piece?: PieceSymbol }): string[]
+  moves({ verbose, piece }: { verbose?: boolean;  piece?: PieceSymbol}): string[] | Move[]
+
+  moves({ verbose, square, piece }: { verbose: true; square?: Square; piece?: PieceSymbol }): Move[]
+  moves({ verbose, square, piece }: { verbose: false; square?: Square; piece?: PieceSymbol }): string[]
+  moves({ verbose, square, piece }: { verbose?: boolean; square?: Square; piece?: PieceSymbol }): string[] | Move[]
+  
+  moves({ square, piece }: { square?: Square; piece?: PieceSymbol }): Move[]
+
   moves({
     verbose = false,
     square = undefined,
-  }: { verbose?: boolean; square?: Square } = {}) {
-    const moves = this._moves({ square })
+    piece = undefined,
+  }: { verbose?: boolean; square?: Square, piece?: PieceSymbol } = {}) {
+    const moves = this._moves({ square, piece })
 
     if (verbose) {
       return moves.map((move) => this._makePretty(move))


Test patch:
diff --git a/__tests__/moves.test.ts b/__tests__/moves.test.ts
index b4de61d5..16dac405 100644
--- a/__tests__/moves.test.ts
+++ b/__tests__/moves.test.ts
@@ -105,3 +105,108 @@ test('moves - single square - verbose', () => {
     moves
   )
 })
+
+test('moves - piece', () => {
+  const chess = new Chess()
+  const moves = 'Na3 Nc3 Nf3 Nh3'
+  expect(chess.moves({ piece: 'n' })).toIncludeSameMembers(split(moves))
+})
+
+test('moves - piece - en passante', () => {
+  const chess = new Chess('rnbq1rk1/4bpp1/p2p1n1p/Ppp1p3/2B1P3/2NP1N1P/1PP2PP1/R1BQ1RK1 w - b6 0 10')
+  const moves = 'axb6 b3 b4 d4 g3 g4 h4'
+  expect(chess.moves({ piece: 'p' })).toIncludeSameMembers(split(moves))
+})
+
+test('moves - piece - no such piece', () => {
+  const chess = new Chess('r1bq1rk1/1pp2ppp/p1np1n2/2b1p3/4P3/2NP1N2/PPP1QPPP/R3K2R w KQ - 0 8')
+  const moves: string[] = []
+  expect(chess.moves({piece: 'b' })).toEqual(moves)
+})
+test('moves - piece - verbose', () => {
+  const chess = new Chess('r4rk1/1p4p1/p1n1p2p/2p1p1q1/4P1N1/P1pP3P/1P2QPP1/R1R3K1 w - - 0 19')
+  const moves = [
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'a1',
+      lan: 'a1a2',
+      piece: 'r',
+      san: 'Ra2',
+      to: 'a2'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'a1',
+      lan: 'a1b1',
+      piece: 'r',
+      san: 'Rab1',
+      to: 'b1'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'c1',
+      lan: 'c1c2',
+      piece: 'r',
+      san: 'Rc2',
+      to: 'c2'
+    },
+    {
+      captured: 'p',
+      color: 'w',
+      flags: 'c',
+      from: 'c1',
+      lan: 'c1c3',
+      piece: 'r',
+      san: 'Rxc3',
+      to: 'c3'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'c1',
+      lan: 'c1d1',
+      piece: 'r',
+      san: 'Rd1',
+      to: 'd1'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'c1',
+      lan: 'c1e1',
+      piece: 'r',
+      san: 'Re1',
+      to: 'e1'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'c1',
+      lan: 'c1f1',
+      piece: 'r',
+      san: 'Rf1',
+      to: 'f1'
+    },
+    {
+      color: 'w',
+      flags: 'n',
+      from: 'c1',
+      lan: 'c1b1',
+      piece: 'r',
+      san: 'Rcb1',
+      to: 'b1'
+    }
+  ]
+  expect(chess.moves({piece: 'r', verbose: true })).toIncludeSameMembers(moves)
+})
+
+test('moves - square and piece', () => {
+  const chess = new Chess('5rk1/1p3rp1/p1n1p3/2p1p2p/2PpP1qP/P2P2P1/1P2QP1K/3R1R2 w - - 0 23')
+  const moves = 'Qd2 Qc2 Qe1 Qe3 Qf3 Qxg4'
+  expect(chess.moves({ square: 'e2', piece: 'q', })).toIncludeSameMembers(split(moves))
+})
+
+