import { Dict } from "../dict.ts";
import { enumerate, range, zip } from "../utils.ts";
import { Gaming, GuessResult, Info } from "./game.ts";

export class Simulator implements Gaming {
	word;

	constructor(word: string) {
		this.word = word;
	}

	static from_dict_rand(dict: Dict) {
		const index = Math.floor(Math.random() * dict.words.size);
		const word = [...dict.words.values()][index];
		return new Simulator(word);
	}

	guess(guess_: string, _known: string): GuessResult {
		if (guess_ === this.word) return { kind: "success" };
		const rest_actual = [...this.word].map((letter) => letter as (string | null));
		const rest_guess = [...guess_].map((letter) => letter as (string | null));
		const info = [...range(0, this.word.length)].map(() => null) as (Info | null)[];

		for (const [index, [guessed, actual]] of enumerate(zip(rest_guess, rest_actual))) {
			if (guessed !== actual) continue;
			rest_actual[index] = null;
			rest_guess[index] = null;
			info[index] = { kind: "there" };
		}

		for (const [index, guessed] of enumerate(rest_guess)) {
			if (guessed === null) continue;
			if (!rest_actual.includes(guessed)) continue;
			info[index] = { kind: "somewhere" };
			rest_guess[index] = null;
			// note : removes only one.
			rest_actual[rest_actual.indexOf(guessed)] = null;
		}

		const informations = info.map((i) => i != undefined ? i : ({ kind: "abscent" }) as Info);
		return { kind: "failure", informations };
	}

	length(): number {
		return this.word.length;
	}
}
