Source

core/src/Envs/BlackJackEnv.ts

import { EnvOptions } from '../RLInterface/Environment';
import {
    BlackJackGame,
    BlackJackGameState,
} from '../Games/BlackJack/index';
import { SingleAgentEnvironment } from '../RLInterface/SingleAgentEnvironment';
import StepResult from '../RLInterface/StepResult';
import { BlackJackActionKey } from '@root/Games/BlackJack/Action';

/**
 * The BlackJack stats
 * @category Environments
 * @property {number} averageReturn - the average return
 * @property {number} averageDealerScore The average dealers score
 * @property {number} averagePlayerScore The average players score
 */
export interface BlackJackStats {
    averageReturn: number;
    averageDealerScore: number;
    averagePlayerScore: number;
}

/**
 * The BlackJack Environment
 * @category Environments
 * @extends SingleAgentEnvironment
 */
class BlackJackEnv extends SingleAgentEnvironment {
    private _game: BlackJackGame;
    private intervalCount: number = 0;
    private averagePlayerScore: number = 0;
    private averageReturn: number = 0;
    private averageDealerScore: number = 0;
    private static _name: string = 'BlackJack';

    /**
     * Get the games stats
     * @type {BlackJackStats}
     */
    public get stats(): BlackJackStats {
        return {
            averageReturn: this.intervalCount
                ? this.averageReturn / this.intervalCount
                : 0,
            averageDealerScore: this.intervalCount
                ? this.averageDealerScore / this.intervalCount
                : 0,
            averagePlayerScore: this.intervalCount
                ? this.averagePlayerScore / this.intervalCount
                : 0,
        };
    }

    public get name(): string {
        return BlackJackEnv._name;
    }

    /**
     * Get the game object
     * @returns {BlackJackGame} The game object
     */
    public get game(): BlackJackGame {
        return this._game;
    }

    public get stateDim(): number[] {
        return BlackJackGame.gameStateDim;
    }

    public get actionSpace(): string[] {
        return BlackJackGame.actionSpace;
    }

    public setOptions(options: EnvOptions): void {
        super.setOptions(options);
        if (this.randomSeed) {
            this.game.randomSeed = this.randomSeed;
        }
    }

    /**
     * Initialize the environment
     * @param {?EnvOptions} options The environment options
     * @param {?BlackJackGameState} initialGameState The initial game state
     * @returns {void}
     */
    public init(
        options?: EnvOptions,
        initialGameState?: BlackJackGameState
    ): void {
        super.init(options, initialGameState);
        if (options) {
            this._game = new BlackJackGame(options.randomSeed);
        } else {
            this._game = new BlackJackGame();
        }
        this._game.initGame();
    }
    public step(
        action: BlackJackActionKey
    ): StepResult<BlackJackGameState> {
        this._lastAction = action;
        return this._game.step(action);
    }
    public get getReturn(): number {
        return this._game.return;
    }
    public get state(): object {
        return this._game.gameState;
    }
    public reset(): boolean {
        return this._game.reset();
    }
    public get isTerminal(): boolean {
        return this._game.isTerminal;
    }
    public get iteration(): number {
        return this._game.iteration;
    }
    public encodeStateToIndices(state: object): number[] {
        return BlackJackGame.encodeStateToIndices(state as BlackJackGameState);
    }

    public override onIterationEnd(): void {
        this.intervalCount++;
        const currentStats = this.state as BlackJackGameState;
        this.averagePlayerScore += currentStats.playerScore;
        this.averageReturn += this.getReturn;
        this.averageDealerScore += this._game.dealer.score;
    }

    public override log(trainIteration: number): void {
        console.log('Iteration:', trainIteration);
        console.log(
            'Average Player Score:',
            this.averagePlayerScore / this.intervalCount
        );
        console.log('Average Return:', this.averageReturn / this.intervalCount);
        console.log(
            'Average Dealer Score:',
            this.averageDealerScore / this.intervalCount
        );
        this.resetStats();
    }

    public resetStats(): boolean {
        this.averagePlayerScore = 0;
        this.intervalCount = 0;
        this.averageReturn = 0;
        this.averageDealerScore = 0;
        return true;
    }
}

export default BlackJackEnv;