chore: added slightly smart cpu

This commit is contained in:
Andre Henriques 2025-04-03 11:23:46 +01:00
parent 67a4096442
commit 7a8b5e198d
2 changed files with 87 additions and 3 deletions

View File

@ -1,13 +1,96 @@
import { Play, PLAYER_OPTIONS, PlayerAction } from "../game";
export type CPUNAME = "CPU Random" | "CPU Always Rock";
export const CPUS_NAMES: CPUNAME[] = ["CPU Random", "CPU Always Rock"];
export type CPUNAME = "CPU Random" | "CPU Always Rock" | "Slightly Smart";
export const CPUS_NAMES: CPUNAME[] = ["CPU Random", "CPU Always Rock", "Slightly Smart"];
export const CPU_FUNCTION_MAPING: Record<CPUNAME, (plays: Play[]) => PlayerAction> = {
"CPU Random": CpuRandom,
"CPU Always Rock": () => 'Rock',
"Slightly Smart": CpuSlightlySmart,
}
export const CPU_FUNCTION_MAPING_END: ((plays: Play[], user: string) => void)[] = [
CpuSlightlySmartEnd
]
function CpuRandom(): PlayerAction {
return PLAYER_OPTIONS[Math.floor(Math.random() * PLAYER_OPTIONS.length)];
}
//
// CPU slightly Smart
//
function CpuSlightlySmart(plays: Play[]): PlayerAction {
const turn = plays.length;
function runTurn(extractFromStorage: 'st' | 'nd' | 'rd') {
let base = PLAYER_OPTIONS.reduce((acc, a) => {
acc[a] = 1;
return acc;
}, {} as Record<PlayerAction, number>);
try {
const newBase = JSON.parse(localStorage.getItem('slightly-smart-cpu-data') ?? '');
base = { ...base, ...newBase[extractFromStorage] };
} catch {
// Do nothing use the default
}
let sum = PLAYER_OPTIONS.reduce((acc, a) => acc + base[a], 0);
const choise = Math.floor(Math.random() * sum);
let runningCount = 0;
for (const a of PLAYER_OPTIONS) {
let newSum = runningCount + base[a];
if (choise > runningCount && choise < newSum) {
return a;
}
runningCount = newSum;
}
// it shouldn't reach here but if it does just return something random
return undefined;
}
if (turn === 0) {
const res = runTurn('st')
if (res !== undefined) return res;
} else if (turn === 1) {
const res = runTurn('nd')
if (res !== undefined) return res;
}
else if (turn === 2) {
const res = runTurn('rd')
if (res !== undefined) return res;
}
else throw 'unrechable';
return PLAYER_OPTIONS[Math.floor(Math.random() * PLAYER_OPTIONS.length)];
}
function CpuSlightlySmartEnd(plays: Play[]) {
let storageData: {
st: Partial<Record<PlayerAction, number>>
nd: Partial<Record<PlayerAction, number>>
rd: Partial<Record<PlayerAction, number>>
} = { st: {}, nd: {}, rd: {} };
try {
// It's ok for this to error
storageData = JSON.parse(localStorage.getItem('slightly-smart-cpu-data') ?? '');
} catch {
// do nothing just goto the default value
}
const ResultReverseMappings: Record<PlayerAction, PlayerAction[]> = {
"Scissors": ["Rock", "Spock"],
"Paper": ["Scissors", "Lizard"],
"Rock": ["Paper", "Spock"],
"Lizard": ["Scissors", "Rock"],
"Spock": ["Paper", "Lizard"],
};
ResultReverseMappings[plays[0].user].forEach((a: PlayerAction) => { storageData.st[a] = (storageData.st[a] ?? 0) + 1; })
ResultReverseMappings[plays[1].user].forEach((a: PlayerAction) => { storageData.nd[a] = (storageData.nd[a] ?? 0) + 1; })
ResultReverseMappings[plays[2].user].forEach((a: PlayerAction) => { storageData.rd[a] = (storageData.rd[a] ?? 0) + 1; })
localStorage.setItem('slightly-smart-cpu-data', JSON.stringify(storageData));
}

View File

@ -1,6 +1,6 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { CPU_FUNCTION_MAPING, CPUNAME } from './CPUS';
import { CPU_FUNCTION_MAPING, CPU_FUNCTION_MAPING_END, CPUNAME } from './CPUS';
import { GetResult, Play, PlayerAction, PlayResult } from './game';
export interface SessionInfoPlayResultOver {
@ -70,6 +70,7 @@ export const useSession = create<SessionInfo>()(persist<SessionInfo>((set) => ({
// TODO: maybe make the best of out a configurable
if (plays.length === 3) {
CPU_FUNCTION_MAPING_END.forEach((fn) => fn(plays, state.currentUser ?? ''));
let winner: 'tie' | 'user' | 'cpu' = 'tie';
let cpu = 0;
let user = 0;