Skip to content

Commit

Permalink
Create capture function for evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
jsveron23 committed Jun 19, 2022
1 parent 1abcd7c commit b8512fe
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 51 deletions.
92 changes: 50 additions & 42 deletions packages/chess/src/ai/AI.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import {
startsWith,
reverse,
isEmpty,
flip,
} from 'ramda';
import StateBuilder from './StateBuilder';
import { parseCode } from '../utils';
import { PST, Side, File, Rank } from '../presets';

// TODO
// bestway for boosting performance
// best way for boosting performance
// 1. go rust
// 2. implement core functions to another ways

const _indexOfRank = flip(indexOf)(reverse(Rank));
const _indexOfFile = flip(indexOf)(File);

class AI {
static #PST = {
wP: PST.P,
Expand All @@ -39,33 +43,44 @@ class AI {
K: 20000,
};

static #evalCaptureScore(state) {
const { side, pretendCode } = state;
const piece = parseCode.prop('piece', pretendCode);
const cScore = this.#Scores[piece];

if (side === Side.w) {
return cScore;
} else {
return -cScore;
}
}

/**
* Evaluate state
* @param {Object} state
* @return {Number}
*/
static #evaluate(state) {
const { timeline } = state;
const { timeline, isCaptured } = state;
const snapshot = head(timeline);
let totalEvalW = 0;
let totalEvalB = 0;
let totalEvaluation = 0;

if (isCaptured) {
totalEvaluation += this.#evalCaptureScore(state);
}

forEach((code) => {
const { side, piece, pKey, fileName, rankName } = parseCode(code);
const rIdx = indexOf(Number(rankName), reverse(Rank));
const fIdx = indexOf(fileName, File);
const rIdx = _indexOfRank(Number(rankName));
const fIdx = _indexOfFile(fileName);
const pstProp = this.#PST[pKey] || this.#PST[piece];
const pstScore = pstProp[rIdx][fIdx];
const score = this.#Scores[piece] + pstScore;

if (side === Side.w) {
totalEvalW += score;
} else {
totalEvalB -= score;
}
totalEvaluation += side === Side.w ? score : -score;
}, snapshot);

return totalEvalW + totalEvalB;
return totalEvaluation;
}

/**
Expand All @@ -79,54 +94,47 @@ class AI {
* @return {Number}
*/
static minimax(currState, depth, alpha, beta, isMaximisingPlayer) {
if (depth === 0) {
if (depth === 0 || currState.isCaptured) {
return -this.#evaluate(currState);
}

const iV = StateBuilder.createInitialV(currState);
const codeList = this.createList(iV.side, iV.snapshot);
const stateList = [];
let bestMove = isMaximisingPlayer ? -9999 : 9999;

for (let i = 0, len = codeList.length; i < len; i++) {
// TODO StateBuilder spent time that calculating movable tiles
const generatedStates = StateBuilder.of(iV).build(codeList[i]);
const state = StateBuilder.of(iV).build(codeList[i]);

if (!isEmpty(generatedStates)) {
stateList.push(...generatedStates);
if (!isEmpty(state)) {
stateList.push(...state);
}
}

const _minimax = (state) => {
return this.minimax(state, depth - 1, alpha, beta, !isMaximisingPlayer);
};

if (isMaximisingPlayer) {
let bestMove = -9999;

for (let i = 0, len = stateList.length; i < len; i++) {
bestMove = Math.max(bestMove, _minimax(stateList[i]));
for (let i = 0, len = stateList.length; i < len; i++) {
const score = this.minimax(
stateList[i],
depth - 1,
alpha,
beta,
!isMaximisingPlayer
);

if (isMaximisingPlayer) {
bestMove = Math.max(bestMove, score);
alpha = Math.max(alpha, bestMove);

if (alpha >= beta) {
return bestMove;
}
}

return bestMove;
} else {
let bestMove = 9999;

for (let i = 0, len = stateList.length; i < len; i++) {
bestMove = Math.min(bestMove, _minimax(stateList[i]));
} else {
bestMove = Math.min(bestMove, score);
beta = Math.min(beta, bestMove);

if (alpha >= beta) {
return bestMove;
}
}

return bestMove;
if (alpha >= beta) {
break;
}
}

return bestMove;
}

static createList(side, snapshot) {
Expand Down
15 changes: 7 additions & 8 deletions src/services/worker/ai.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,26 @@ self.onmessage = ({ data }) => {
...checkData,
});
const codeList = AI.createList(iV.side, iV.snapshot);
const stateList = [];
let bestMove = -9999;
let bestState = null;

console.time('worker');
const stateList = [];

for (let i = 0, len = codeList.length; i < len; i++) {
const generatedStates = StateBuilder.of(iV).build(codeList[i]);
const state = StateBuilder.of(iV).build(codeList[i]);

if (!isEmpty(generatedStates)) {
stateList.push(...generatedStates);
if (!isEmpty(state)) {
stateList.push(...state);
}
}

for (let i = 0, len = stateList.length; i < len; i++) {
const generatedState = stateList[i];
const score = AI.minimax(generatedState, depth - 1, -10000, 10000, false);
const state = stateList[i];
const score = AI.minimax(state, depth - 1, -10000, 10000, false);

if (score >= bestMove) {
bestMove = score;
bestState = generatedState;
bestState = state;
}
}
console.timeEnd('worker');
Expand Down
2 changes: 1 addition & 1 deletion src/store/reducers/ai.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UPDATE_MATCH_TYPE, TOGGLE_THINKING } from '../actionTypes';
const initialState = {
cpuTurn: Turn.b,
thinking: false,
depth: 2,
depth: 3,
};

function reducer(state = initialState, action) {
Expand Down

0 comments on commit b8512fe

Please sign in to comment.