chess-tactics 0.0.5 → 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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TacticFactory = void 0;
4
4
  const _tactics_1 = require("./tactics/index");
5
5
  const _utils_1 = require("./utils/index");
6
+ const SequenceInterpreter_1 = require("./utils/SequenceInterpreter");
6
7
  class TacticFactory {
7
8
  static create(type) {
8
9
  const sequenceInterpreter = new _utils_1.SequenceInterpreter();
@@ -16,7 +17,8 @@ class TacticFactory {
16
17
  case "sacrifice":
17
18
  return new _tactics_1.SacrificeTactics(sequenceInterpreter);
18
19
  case "trap":
19
- return new _tactics_1.TrapTactics(sequenceInterpreter);
20
+ const trapInterpreter = new SequenceInterpreter_1.TrapTacticsSequenceInterpreter();
21
+ return new _tactics_1.TrapTactics(trapInterpreter);
20
22
  case "hanging":
21
23
  return new _tactics_1.HangingPieceTactics(sequenceInterpreter);
22
24
  }
@@ -14,11 +14,14 @@ class BaseTactic {
14
14
  const chess = new chess_js_1.Chess(context.position);
15
15
  let isForcing = true;
16
16
  let i = 0;
17
- while (isForcing && i < sequence.length - 2) {
17
+ while (isForcing && i < Math.min(sequence.length - 2, 4)) {
18
18
  const newContext = this.contextAtState(context, chess.fen(), sequence, i);
19
19
  this.sequenceInterpreter.setContext(newContext);
20
20
  const tactic = this.isTactic(newContext);
21
21
  if (tactic) {
22
+ if (tactic.type === "hanging" && i > 0) {
23
+ return null;
24
+ }
22
25
  return this.wrapTactic(tactic, context, sequence, i);
23
26
  }
24
27
  // Play your move and opponent's response
@@ -6,14 +6,14 @@ const _utils_1 = require("../utils/index");
6
6
  const _tactics_1 = require("./index");
7
7
  class HangingPieceTactics extends _tactics_1.BaseTactic {
8
8
  isTactic(context) {
9
- const { position, evaluation, prevMove } = context;
9
+ const { position, evaluation, prevMove, prevPosition } = context;
10
+ const prevChess = new chess_js_1.Chess(prevPosition);
10
11
  const chess = new chess_js_1.Chess(position);
11
12
  const currentMove = evaluation.sequence[0];
12
- if (!currentMove.captured) {
13
+ if (!currentMove.captured || currentMove.captured === "p") {
13
14
  return null;
14
15
  }
15
- if (prevMove.captured &&
16
- _utils_1.PIECE_VALUES[prevMove.captured] >= _utils_1.PIECE_VALUES[currentMove.captured]) {
16
+ if (prevChess.inCheck() || (prevMove.captured && prevMove.captured !== "p")) {
17
17
  return null;
18
18
  }
19
19
  chess.load(position);
@@ -21,7 +21,16 @@ class HangingPieceTactics extends _tactics_1.BaseTactic {
21
21
  const tacticalSequence = this.sequenceInterpreter.identifyWinningSequence(attackers, [
22
22
  currentMove.to,
23
23
  ]);
24
- if (tacticalSequence) {
24
+ this.sequenceInterpreter.setContext({
25
+ evaluation: context.prevEvaluation,
26
+ position: context.prevPosition,
27
+ });
28
+ const prevSequence = this.sequenceInterpreter.identifyWinningSequence(attackers, [
29
+ currentMove.to,
30
+ ]);
31
+ if (tacticalSequence &&
32
+ tacticalSequence.materialChange >= _utils_1.PIECE_VALUES[currentMove.captured] &&
33
+ (!prevSequence || prevSequence.materialChange < _utils_1.PIECE_VALUES[currentMove.captured])) {
25
34
  return {
26
35
  type: "hanging",
27
36
  attackedPieces: [{ square: currentMove.to, piece: chess.get(currentMove.to) }],
@@ -72,12 +72,16 @@ class TrapTactics extends _tactics_1.BaseTactic {
72
72
  getCapturablePieces(currentMove, position) {
73
73
  // A capturable piece is one that can be taken. No other assumptions
74
74
  // game must be the initial position
75
+ const chess = new chess_js_1.Chess(position);
76
+ const originalMoves = chess.moves({ verbose: true });
75
77
  const chessCopy = new chess_js_1.Chess(position);
76
78
  chessCopy.move(currentMove);
77
79
  (0, _utils_1.invertTurn)(chessCopy);
78
80
  const possibleMoves = chessCopy.moves({ verbose: true });
81
+ // moveDiff ensures the move you made is responsible for revealing the trap, either directly or indirectly
82
+ const moveDiff = (0, _utils_1.getMoveDiff)(originalMoves, possibleMoves);
79
83
  let targetedPieces = [];
80
- for (const m of possibleMoves) {
84
+ for (const m of moveDiff) {
81
85
  if (m.captured) {
82
86
  targetedPieces.push(m);
83
87
  }
@@ -7,7 +7,10 @@ export declare class SequenceInterpreter {
7
7
  setContext(context: _TacticContext): void;
8
8
  getCaptureSequence(position: Fen, sequence: Move[]): any[];
9
9
  identifyWinningSequence(attackerSquares: Square[], attackedSquares: Square[]): SequenceInterpretation | null;
10
- private capturedAttackedPieces;
10
+ protected capturedAttackedPieces(move: Move, attackerSquares: Square[], attackedSquares: Square[]): boolean;
11
11
  private isDesparado;
12
12
  positionAfterSequence(position: Fen, sequence: string[] | Move[] | null): string;
13
13
  }
14
+ export declare class TrapTacticsSequenceInterpreter extends SequenceInterpreter {
15
+ protected capturedAttackedPieces(move: Move, attackerSquares: Square[], attackedSquares: Square[]): boolean;
16
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SequenceInterpreter = void 0;
3
+ exports.TrapTacticsSequenceInterpreter = exports.SequenceInterpreter = void 0;
4
4
  const chess_js_1 = require("chess.js");
5
5
  const _utils_1 = require("./index");
6
6
  class SequenceInterpreter {
@@ -66,7 +66,9 @@ class SequenceInterpreter {
66
66
  capturedAttackedPieces(move, attackerSquares, attackedSquares) {
67
67
  const capturedSquares = attackedSquares.filter((s) => {
68
68
  // move came from an attacker square, to an attackedSquare, and captured a piece
69
- return s === move.to && move.captured;
69
+ return (attackerSquares.filter((t) => t === move.from).length > 0 &&
70
+ s === move.to &&
71
+ move.captured);
70
72
  });
71
73
  return capturedSquares.length > 0;
72
74
  }
@@ -86,3 +88,13 @@ class SequenceInterpreter {
86
88
  }
87
89
  }
88
90
  exports.SequenceInterpreter = SequenceInterpreter;
91
+ class TrapTacticsSequenceInterpreter extends SequenceInterpreter {
92
+ capturedAttackedPieces(move, attackerSquares, attackedSquares) {
93
+ const capturedSquares = attackedSquares.filter((s) => {
94
+ // move came from an attacker square, to an attackedSquare, and captured a piece
95
+ return s === move.to && move.captured;
96
+ });
97
+ return capturedSquares.length > 0;
98
+ }
99
+ }
100
+ exports.TrapTacticsSequenceInterpreter = TrapTacticsSequenceInterpreter;
@@ -7,6 +7,13 @@ class TacticContextParser {
7
7
  static parse(context, options) {
8
8
  const evaluation = this.parseEvaluation(context.position, context.evaluation, options);
9
9
  if ("prevEvaluation" in context) {
10
+ const prevChess = new chess_js_1.Chess(context.prevPosition);
11
+ try {
12
+ prevChess.move(context.prevMove);
13
+ }
14
+ catch (e) {
15
+ throw new _chess_tactics_1.ChessTacticsParserError(`prevMove ${context.prevMove.san} is not playable in prevPosition ${context.prevPosition}`, "INVALID_MOVE", { cause: e });
16
+ }
10
17
  const prevEvaluation = this.parseEvaluation(context.prevPosition, context.prevEvaluation, options);
11
18
  return {
12
19
  evaluation: evaluation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chess-tactics",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/antonryoung02/chess-tactics.git"