Skip to content

Commit

Permalink
add test for promotions
Browse files Browse the repository at this point in the history
  • Loading branch information
EllAchE committed Nov 5, 2023
1 parent 02b9810 commit eabd027
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 46 deletions.
20 changes: 20 additions & 0 deletions cjsmin/src/chess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,26 @@ export type PrettyMove = {
uas: UASymbol;
};

export type PromotablePiece = 'q' | 'r' | 'b' | 'n';

export type Pawns =
| 'pa'
| 'pb'
| 'pc'
| 'pd'
| 'pe'
| 'pf'
| 'pg'
| 'ph'
| 'PA'
| 'PB'
| 'PC'
| 'PD'
| 'PE'
| 'PF'
| 'PG'
| 'PH';

export type UASymbol =
| 'RA'
| 'NB'
Expand Down
1 change: 1 addition & 0 deletions src/metrics/moves.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Chess } from '../../cjsmin/src/chess';
import { FileReaderGame } from '../types';

export async function getGameWithMostMoves(games: FileReaderGame[]) {
console.time('Task 5: getGameWithMostMoves');
let maxNumMoves = 0;
Expand Down
93 changes: 48 additions & 45 deletions src/metrics/promotions.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,57 @@
import { Chess } from '../../cjsmin/src/chess';
import { FileReaderGame } from '../types';

export async function getPiecePromotionInfo(games: FileReaderGame[]) {
console.time('Task 7: getPiecePromotionInfo');
let ambigPiecePromotedToMap = {};
let promotingPieceMap = {};

for (const game of games) {
const chess = new Chess();
chess.loadPgn(game.moves);
const chessHistory = chess.history();
import {
Pawns,
Piece,
PrettyMove,
PromotablePiece,
} from '../../cjsmin/src/chess';
import { Metric } from './metric';

export class PromotionMetric implements Metric {
//uas pawns mapped to count of promotions to each piece type
//prettier-ignore
promotionMap: {
[key in Pawns]: {
[key in PromotablePiece]: number;
}
};

for (const moveInfo of chessHistory) {
if (moveInfo.originalString.includes('=')) {
// REGEX to only capture the piece type
const piecePromotedTo = moveInfo.originalString
.split('=')[1]
.match(/[a-zA-Z]/)[0];
constructor() {
this.clear();
}

const promotingPiece = moveInfo.uas;
clear(): void {
let promotionMap = {};
//prettier-ignore
for (const pawn of ["pa", "pb", "pc", "pd", "pe", "pf", "pg", "ph", 'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH']) {
promotionMap[pawn] = { q: 0, r: 0, b: 0, n: 0 };
}
this.promotionMap = promotionMap as any;
}

processGame(game: { move: PrettyMove; board: Piece[] }[], gameLink?: string) {
for (const { move } of game) {
// TODO: we can use flags instead of includes('=)
if (move.originalString.includes('=')) {
// update ambigPiecePromotedToMap
if (!ambigPiecePromotedToMap[piecePromotedTo]) {
ambigPiecePromotedToMap[piecePromotedTo] = 0;
}
ambigPiecePromotedToMap[piecePromotedTo]++;

// update promotingPieceMap
if (!promotingPieceMap[promotingPiece]) {
promotingPieceMap[promotingPiece] = 0;
}
promotingPieceMap[promotingPiece]++;
this.promotionMap[move.uas][move.promotion]++;
}
}
}

// promotions facts
console.log('PROMOTIONS FACTS:');
console.log(
'How often a piece is promoted to different ambiguous piece types:'
),
console.table(ambigPiecePromotedToMap);
console.log('How often unambiguous piece is promoted:'),
console.table(promotingPieceMap);
console.log('==============================================================');
console.log('\n');

console.timeEnd('Task 7: getPiecePromotionInfo');
return {
ambigPiecePromotedToMap,
promotingPieceMap,
};
aggregate() {}

logResults(): void {
// promotions facts
console.log('PROMOTIONS FACTS:');
console.log(
'How often a piece is promoted to different ambiguous piece types:'
),
console.table(this.promotionMap);
console.log('How often unambiguous piece is promoted:'),
console.table(this.promotionMap);
console.log(
'=============================================================='
);
console.log('\n');
}
}
108 changes: 107 additions & 1 deletion tests/metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '../src/metrics/captures';
import { MoveDistanceMetric } from '../src/metrics/distances';
import { getGameWithMostMoves } from '../src/metrics/moves';
import { PromotionMetric } from '../src/metrics/promotions';

// convert PGN string to GameHistoryObject
export function pgnToGameHistory(pgn: string) {
Expand Down Expand Up @@ -331,7 +332,6 @@ describe('All Tests', () => {

kdrMetric.processGame(Array.from(cjsmin.historyGenerator(game[0].moves)));

console.log(kdrMetric.KDAssistsMap['ng'].kills);
expect(kdrMetric.KDAssistsMap['ng'].kills).toEqual(3);
});
});
Expand All @@ -351,4 +351,110 @@ describe('All Tests', () => {
expect(result.maxNumMoves).toEqual(24);
});
});

describe('PromotionMetric', () => {
const promotionMetric = new PromotionMetric();

afterEach(() => {
promotionMetric.clear();
});

it('should update the promotion map when a promotion occurs', () => {
const moves = [
{
move: {
originalString: 'e8=Q',
color: 'b',
from: 'e7',
to: 'e8',
piece: 'p',
flags: 'p',
promotion: 'q',
uas: 'pe',
},
board: [],
},
{
move: {
originalString: 'a2=a1',
color: 'w',
from: 'a2',
to: 'a1',
piece: 'p',
flags: 'p',
promotion: 'q',
uas: 'PA',
},
},
{
move: {
originalString: 'b7=b8',
color: 'b',
from: 'b7',
to: 'b8',
piece: 'p',
flags: 'p',
promotion: 'r',
uas: 'pb',
},
},
].map((entry) => {
return {
move: entry.move as any, // cast to match type checks in the processGame handler
board: [],
};
});

promotionMetric.processGame(moves);

expect(promotionMetric.promotionMap.pe.q).toEqual(1);
expect(promotionMetric.promotionMap.PA.q).toEqual(1);
expect(promotionMetric.promotionMap.pb.r).toEqual(1);
});

it('should not update the promotion map when a promotion does not occur', () => {
const moves = [
{
move: {
originalString: 'e4',
color: 'w',
from: 'e2',
to: 'e4',
piece: 'p',
flags: 'b',
uas: 'PE',
},
},
{
move: {
originalString: 'e5',
color: 'b',
from: 'e7',
to: 'e5',
piece: 'p',
flags: 'n',
uas: 'pe',
},
},
].map((entry) => {
return {
move: entry.move as any, // cast to match type checks in the processGame handler
board: [],
};
});

promotionMetric.processGame(moves);
let promoTotal = 0;

for (const k of Object.keys(promotionMetric.promotionMap)) {
for (const promoCount of Object.values(
promotionMetric.promotionMap[k]
)) {
promoTotal += promoCount as number;
}
}

expect(promoTotal).toEqual(0);
});
});
});

0 comments on commit eabd027

Please sign in to comment.