fixes and cleanup
This commit is contained in:
parent
374c42802e
commit
bc211621e5
6 changed files with 199 additions and 83 deletions
|
@ -1,6 +1,10 @@
|
||||||
|
import { assertNotEquals } from "https://deno.land/std@0.224.0/assert/assert_not_equals.ts";
|
||||||
|
|
||||||
import { Dict } from "../dict.ts";
|
import { Dict } from "../dict.ts";
|
||||||
import { enumerate, range, zip } from "../utils.ts";
|
import { enumerate } from "../utils.ts";
|
||||||
import { Gaming, GuessResult, Info } from "./game.ts";
|
import { Gaming, GuessResult, Info } from "./game.ts";
|
||||||
|
import { assertEquals } from "https://deno.land/std@0.224.0/assert/assert_equals.ts";
|
||||||
|
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
|
||||||
|
|
||||||
export class Simulator implements Gaming {
|
export class Simulator implements Gaming {
|
||||||
word;
|
word;
|
||||||
|
@ -27,25 +31,86 @@ export class Simulator implements Gaming {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function info_of_guess(guess: string, actual: string) {
|
export function info_of_guess(guess: string, actual: string) {
|
||||||
const rest_actual = [...actual].map((letter) => letter as (string | null));
|
const actual_letters = [...actual];
|
||||||
const rest_guess = [...guess].map((letter) => letter as (string | null));
|
const infos = [...guess].map(() => null) as (Info | null)[];
|
||||||
const info = [...range(0, actual.length)].map(() => null) as (Info | null)[];
|
|
||||||
|
|
||||||
for (const [index, [guessed, actual]] of enumerate(zip(rest_guess, rest_actual))) {
|
const used_letter_indices = new Set<number>();
|
||||||
if (guessed !== actual) continue;
|
for (const [index, letter] of enumerate(guess)) {
|
||||||
rest_actual[index] = null;
|
if (actual_letters[index] !== letter) continue;
|
||||||
rest_guess[index] = null;
|
infos[index] = { kind: "there" };
|
||||||
info[index] = { kind: "there" };
|
actual_letters[index] = ".";
|
||||||
|
used_letter_indices.add(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [index, guessed] of enumerate(rest_guess)) {
|
for (const [index, letter] of enumerate(guess)) {
|
||||||
if (guessed === null) continue;
|
assertNotEquals(letter, ".");
|
||||||
if (!rest_actual.includes(guessed)) continue;
|
if (used_letter_indices.has(index)) continue;
|
||||||
info[index] = { kind: "somewhere" };
|
if (!actual_letters.includes(letter)) {
|
||||||
rest_guess[index] = null;
|
infos[index] = { kind: "abscent" };
|
||||||
// note : removes only one.
|
continue;
|
||||||
rest_actual[rest_actual.indexOf(guessed)] = null;
|
}
|
||||||
|
const actual_index = actual_letters.findIndex((i) => i === letter);
|
||||||
|
assertNotEquals(actual_index, -1);
|
||||||
|
infos[index] = { kind: "somewhere" };
|
||||||
|
actual_letters[actual_index] = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.map((i) => i != undefined ? i : ({ kind: "abscent" }) as Info);
|
const infos_ = infos.map((i) => i === null ? ({ kind: "abscent" }) : i);
|
||||||
|
for (const info of infos_) assertExists(info);
|
||||||
|
return infos_ as Info[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Deno.test("test_info_of_guess_peigne", () => {
|
||||||
|
const guess_ = "soiree";
|
||||||
|
const actual = "peigne";
|
||||||
|
const constraints = [
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "there" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "there" },
|
||||||
|
] as Info[];
|
||||||
|
assertEquals(info_of_guess(guess_, actual), constraints);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("test_info_of_guess_genant", () => {
|
||||||
|
const guess_ = "genant";
|
||||||
|
const actual = "peigne";
|
||||||
|
const constraints = [
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "there" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "there" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
] as Info[];
|
||||||
|
assertEquals(info_of_guess(guess_, actual), constraints);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("test_info_of_guess_arbre", () => {
|
||||||
|
const guess_ = "resta";
|
||||||
|
const actual = "arbre";
|
||||||
|
const constraints = [
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "somewhere" }, // <- "abscent" ; ptn ... gerté la lettre dans la mauvaise liste
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
] as Info[];
|
||||||
|
assertEquals(info_of_guess(guess_, actual), constraints);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("test_info_of_guess_poncif", () => {
|
||||||
|
const guess_ = "pacino";
|
||||||
|
const actual = "poncif";
|
||||||
|
const constraints = [
|
||||||
|
{ kind: "there" },
|
||||||
|
{ kind: "abscent" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
{ kind: "somewhere" },
|
||||||
|
] as Info[];
|
||||||
|
assertEquals(info_of_guess(guess_, actual), constraints);
|
||||||
|
});
|
||||||
|
|
|
@ -129,8 +129,3 @@ export class ExplorerGuesser implements Guessing {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pick_random_common_word(bests: string[]) {
|
|
||||||
const index = Math.floor(Math.random() * bests.length);
|
|
||||||
return bests[index];
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { assertNotEquals } from "https://deno.land/std@0.224.0/assert/assert_not_equals.ts";
|
||||||
|
|
||||||
import { GuessResult } from "../game/game.ts";
|
import { GuessResult } from "../game/game.ts";
|
||||||
import { Awaitable } from "../utils.ts";
|
import { Awaitable } from "../utils.ts";
|
||||||
|
|
||||||
|
@ -5,3 +7,9 @@ export interface Guessing {
|
||||||
declare_properties(): string[];
|
declare_properties(): string[];
|
||||||
guess(try_: (guess: string, ...properties: unknown[]) => Awaitable<GuessResult>): Promise<GuessResult | null>;
|
guess(try_: (guess: string, ...properties: unknown[]) => Awaitable<GuessResult>): Promise<GuessResult | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function pick_random_common_word(bests: string[]) {
|
||||||
|
assertNotEquals(bests.length, 0);
|
||||||
|
const index = Math.floor(Math.random() * bests.length);
|
||||||
|
return bests[index];
|
||||||
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { assertEquals } from "https://deno.land/std@0.224.0/assert/assert_equals
|
||||||
import { Dict } from "../dict.ts";
|
import { Dict } from "../dict.ts";
|
||||||
import { GuessResult, Info } from "../game/game.ts";
|
import { GuessResult, Info } from "../game/game.ts";
|
||||||
import { info_of_guess } from "../game/simulator.ts";
|
import { info_of_guess } from "../game/simulator.ts";
|
||||||
import { Awaitable, enumerate, first, range, zip } from "../utils.ts";
|
import { Awaitable, dbg, enumerate, first, range, zip } from "../utils.ts";
|
||||||
import { Guessing } from "./guesser.ts";
|
import { Guessing, pick_random_common_word } from "./guesser.ts";
|
||||||
|
|
||||||
export class ReducingGuesser implements Guessing {
|
export class ReducingGuesser implements Guessing {
|
||||||
length;
|
length;
|
||||||
|
@ -25,6 +25,13 @@ export class ReducingGuesser implements Guessing {
|
||||||
public async guess(try_: (guess: string, candidates: number, score: number) => Awaitable<GuessResult>) {
|
public async guess(try_: (guess: string, candidates: number, score: number) => Awaitable<GuessResult>) {
|
||||||
if (this.candidates.size === 1) return await try_(first(this.candidates)!, this.candidates.size, 1);
|
if (this.candidates.size === 1) return await try_(first(this.candidates)!, this.candidates.size, 1);
|
||||||
const [guess, score] = get_word_with_smallest_cuts(this.candidates, this.words);
|
const [guess, score] = get_word_with_smallest_cuts(this.candidates, this.words);
|
||||||
|
if (score >= this.candidates.size) {
|
||||||
|
const pick = pick_random_common_word([...this.candidates.values()]);
|
||||||
|
assertExists(pick);
|
||||||
|
const result = await try_(pick, this.candidates.size, score);
|
||||||
|
if (result.kind === "success") return result;
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
const result = await try_(guess, this.candidates.size, score);
|
const result = await try_(guess, this.candidates.size, score);
|
||||||
if (result.kind === "success") return result;
|
if (result.kind === "success") return result;
|
||||||
this.learn(guess, result.informations);
|
this.learn(guess, result.informations);
|
||||||
|
@ -39,7 +46,9 @@ export class ReducingGuesser implements Guessing {
|
||||||
if (info.kind === "somewhere") next_cnd = filter_map(next_cnd, (_, r) => r.includes(c) ? consume(r, c) : null);
|
if (info.kind === "somewhere") next_cnd = filter_map(next_cnd, (_, r) => r.includes(c) ? consume(r, c) : null);
|
||||||
if (info.kind === "there") next_cnd = filter_map(next_cnd, (_, r) => r[i] === c ? consume(r, c) : null);
|
if (info.kind === "there") next_cnd = filter_map(next_cnd, (_, r) => r[i] === c ? consume(r, c) : null);
|
||||||
}
|
}
|
||||||
this.candidates = new Set(next_cnd.keys());
|
const new_candidates = new Set(next_cnd.keys());
|
||||||
|
if (new_candidates.size === this.candidates.size) console.log({ new_candidates });
|
||||||
|
this.candidates = new_candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
restraint_candidates(constraints: [string, Info][]) {
|
restraint_candidates(constraints: [string, Info][]) {
|
||||||
|
@ -83,32 +92,6 @@ note : The algorithm must proceed as follow :
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function word_cuts(word: string, dict: Set<string>) {
|
function word_cuts(word: string, dict: Set<string>) {
|
||||||
const result = [] as [Set<string>, Set<string>, Set<string>][];
|
|
||||||
const valued = [...dict.values()].map((value) => ({ value, rest: value }));
|
|
||||||
// note : first pass to detect corrects.
|
|
||||||
for (const [index, letter] of enumerate(word)) {
|
|
||||||
const [theres, somewheres, abscents] = [new Set<string>(), new Set<string>(), new Set<string>()];
|
|
||||||
for (const option of valued) {
|
|
||||||
if (option.rest[index] === letter) {
|
|
||||||
theres.add(option.value);
|
|
||||||
option.rest = consume(option.value, letter, index);
|
|
||||||
}
|
|
||||||
result.push([theres, somewheres, abscents]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// note : second pass to detect rest.
|
|
||||||
for (const letter of word) {
|
|
||||||
for (const [option, [theres, somewheres, abscents]] of zip(valued, result)) {
|
|
||||||
if (option.rest.includes(letter)) {
|
|
||||||
somewheres.add(option.value);
|
|
||||||
option.rest = consume(option.rest, letter);
|
|
||||||
} else if (!theres.has(option.value)) abscents.add(option.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function word_cuts_alt(word: string, dict: Set<string>) {
|
|
||||||
const results = [...range(0, word.length)]
|
const results = [...range(0, word.length)]
|
||||||
.map(() => [new Set<string>(), new Set<string>(), new Set<string>()] as const);
|
.map(() => [new Set<string>(), new Set<string>(), new Set<string>()] as const);
|
||||||
for (const option of dict) {
|
for (const option of dict) {
|
||||||
|
@ -125,7 +108,7 @@ function word_cuts_alt(word: string, dict: Set<string>) {
|
||||||
function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>) {
|
function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>) {
|
||||||
let best = null as null | [string, number];
|
let best = null as null | [string, number];
|
||||||
for (const candidate of dict.values()) {
|
for (const candidate of dict.values()) {
|
||||||
const cuts = word_cuts_alt(candidate, candidates);
|
const cuts = word_cuts(candidate, candidates);
|
||||||
let max_part_size = 0;
|
let max_part_size = 0;
|
||||||
for (const cut of cuts) for (const part of cut) if (part.size > max_part_size) max_part_size = part.size;
|
for (const cut of cuts) for (const part of cut) if (part.size > max_part_size) max_part_size = part.size;
|
||||||
if (best === null) best = [candidate, max_part_size];
|
if (best === null) best = [candidate, max_part_size];
|
||||||
|
@ -135,46 +118,101 @@ function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>)
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
Deno.test("test_word_cuts", () => {
|
|
||||||
{
|
|
||||||
const cuts = word_cuts("a", new Set(["a", "b"]));
|
|
||||||
assertEquals(cuts, [[new Set(["a"]), new Set([]), new Set(["b"])]]);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const cuts = word_cuts("aa", new Set(["aa", "ab", "ba", "bb"]));
|
|
||||||
assertEquals(cuts, [
|
|
||||||
[new Set(["aa", "ab"]), new Set(["ba"]), new Set(["bb"])],
|
|
||||||
[new Set(["aa", "ba"]), new Set(["ab"]), new Set(["bb"])],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Deno.test("test_smallest_cuts", () => {
|
|
||||||
const [best] = get_word_with_smallest_cuts(
|
|
||||||
new Set(["aa", "ab", "ac", "ba", "bc"]),
|
|
||||||
new Set(["ab", "ba"]),
|
|
||||||
);
|
|
||||||
assertEquals(best, "ba");
|
|
||||||
});
|
|
||||||
|
|
||||||
function matches_constraints(candidate: string, constraints: [string, Info][]) {
|
function matches_constraints(candidate: string, constraints: [string, Info][]) {
|
||||||
const letters = [...candidate];
|
const letters = [...candidate];
|
||||||
|
|
||||||
for (const [index, [letter, info]] of enumerate(constraints)) {
|
for (const [index, [letter, info]] of enumerate(constraints)) {
|
||||||
if (info.kind !== "there") continue;
|
if (info.kind !== "there") continue;
|
||||||
if (letters[index] !== letter) return false;
|
if (letters[index] !== letter) return dbg(false, "a", index);
|
||||||
letters[index] = ".";
|
letters[index] = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [index, [letter, info]] of enumerate(constraints)) {
|
for (const [index, [letter, info]] of enumerate(constraints)) {
|
||||||
if (info.kind === "there") continue;
|
if (info.kind === "there") continue;
|
||||||
if (info.kind === "abscent") if (letters.includes(letter)) return false;
|
if (info.kind === "abscent") {
|
||||||
|
if (letters.includes(letter)) return dbg(false, "b", index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// is somewhere
|
// is somewhere
|
||||||
if (letters[index] === letter) return false;
|
if (letters[index] === letter) return dbg(false, "c", index);
|
||||||
if (!letters.includes(letter)) return false;
|
if (!letters.includes(letter)) return dbg(false, "d", index);
|
||||||
const index_ = letters.findIndex((i) => i === letter);
|
const index_ = letters.findIndex((i) => i === letter);
|
||||||
letters[index_] = ".";
|
letters[index_] = ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Deno.test("test_matches", () => {
|
||||||
|
{
|
||||||
|
const candidate = "peigne";
|
||||||
|
const constraints = [
|
||||||
|
["s", { kind: "abscent" }],
|
||||||
|
["o", { kind: "abscent" }],
|
||||||
|
["i", { kind: "there" }],
|
||||||
|
["r", { kind: "abscent" }],
|
||||||
|
["e", { kind: "somewhere" }],
|
||||||
|
["e", { kind: "there" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const candidate = "peigne";
|
||||||
|
const constraints = [
|
||||||
|
["g", { kind: "somewhere" }],
|
||||||
|
["e", { kind: "there" }],
|
||||||
|
["n", { kind: "abscent" }],
|
||||||
|
["a", { kind: "abscent" }],
|
||||||
|
["n", { kind: "there" }],
|
||||||
|
["t", { kind: "abscent" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const candidate = "arbre";
|
||||||
|
const constraints = [
|
||||||
|
["r", { kind: "somewhere" }],
|
||||||
|
["e", { kind: "somewhere" }],
|
||||||
|
["s", { kind: "abscent" }],
|
||||||
|
["t", { kind: "abscent" }],
|
||||||
|
["a", { kind: "somewhere" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const candidate = "poncif";
|
||||||
|
const constraints = [
|
||||||
|
["p", { kind: "there" }],
|
||||||
|
["a", { kind: "abscent" }],
|
||||||
|
["c", { kind: "somewhere" }],
|
||||||
|
["i", { kind: "somewhere" }],
|
||||||
|
["n", { kind: "somewhere" }],
|
||||||
|
["o", { kind: "somewhere" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const candidate = "piteux";
|
||||||
|
const constraints = [
|
||||||
|
["s", { kind: "abscent" }],
|
||||||
|
["o", { kind: "abscent" }],
|
||||||
|
["i", { kind: "somewhere" }],
|
||||||
|
["r", { kind: "abscent" }],
|
||||||
|
["e", { kind: "somewhere" }],
|
||||||
|
["e", { kind: "abscent" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const candidate = "piteux";
|
||||||
|
const constraints = [
|
||||||
|
["l", { kind: "abscent" }],
|
||||||
|
["a", { kind: "abscent" }],
|
||||||
|
["t", { kind: "there" }],
|
||||||
|
["i", { kind: "somewhere" }],
|
||||||
|
["n", { kind: "abscent" }],
|
||||||
|
["e", { kind: "somewhere" }],
|
||||||
|
] as [string, Info][];
|
||||||
|
assertEquals(matches_constraints(candidate, constraints), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -10,13 +10,15 @@ export class Runner<Ga extends Gaming, Gu extends Guessing> {
|
||||||
delay_ms;
|
delay_ms;
|
||||||
turns;
|
turns;
|
||||||
logging;
|
logging;
|
||||||
|
max;
|
||||||
|
|
||||||
constructor(game: Ga, guesser: Gu, logging: LoggingStrategy, delay_ms = 0) {
|
constructor(game: Ga, guesser: Gu, logging: LoggingStrategy, delay_ms = 0, max: number | undefined = undefined) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.guesser = guesser;
|
this.guesser = guesser;
|
||||||
this.delay_ms = delay_ms;
|
this.delay_ms = delay_ms;
|
||||||
this.turns = [] as Turn[];
|
this.turns = [] as Turn[];
|
||||||
this.logging = logging;
|
this.logging = logging;
|
||||||
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
async play_all() {
|
async play_all() {
|
||||||
|
@ -29,9 +31,11 @@ export class Runner<Ga extends Gaming, Gu extends Guessing> {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
if (result !== null) break;
|
if (result !== null) break;
|
||||||
|
if (this.max !== undefined) if (this.turns.length >= this.max) return this.turns;
|
||||||
await wait(this.delay_ms);
|
await wait(this.delay_ms);
|
||||||
}
|
}
|
||||||
this.logging.on_finish(this.turns);
|
this.logging.on_finish(this.turns);
|
||||||
|
return this.turns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +103,7 @@ export class TableLogging implements LoggingStrategy {
|
||||||
this.columns = properties.map((p) => [p, p.length] as const);
|
this.columns = properties.map((p) => [p, p.length] as const);
|
||||||
this.columns.splice(0, 0, ["guess", length], ["result", Math.max(7, length)]);
|
this.columns.splice(0, 0, ["guess", length], ["result", Math.max(7, length)]);
|
||||||
let line = "";
|
let line = "";
|
||||||
for (const [name, width] of this.columns) line += name.padStart(width) + " ";
|
for (const [name, width] of this.columns) line += name.padStart(width) + " ";
|
||||||
console.log(line);
|
console.log(line);
|
||||||
console.log();
|
console.log();
|
||||||
}
|
}
|
||||||
|
@ -107,7 +111,7 @@ export class TableLogging implements LoggingStrategy {
|
||||||
on_guess(guess: string, result: GuessResult, ...properties: unknown[]): void {
|
on_guess(guess: string, result: GuessResult, ...properties: unknown[]): void {
|
||||||
const properties_ = [guess, format_result(result), ...properties];
|
const properties_ = [guess, format_result(result), ...properties];
|
||||||
let line = "";
|
let line = "";
|
||||||
for (const [[_, width], value] of zip(this.columns, properties_)) line += `${value}`.padStart(width) + " ";
|
for (const [[_, width], value] of zip(this.columns, properties_)) line += `${value}`.padStart(width) + " ";
|
||||||
console.log(line);
|
console.log(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from "./lib/lib.ts";
|
} from "./lib/lib.ts";
|
||||||
|
|
||||||
import { francais } from "../data/data.ts";
|
import { francais } from "../data/data.ts";
|
||||||
|
import { last } from "./lib/utils.ts";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const args = await new Command().name("simulation")
|
const args = await new Command().name("simulation")
|
||||||
|
@ -27,6 +28,9 @@ async function main() {
|
||||||
).option(
|
).option(
|
||||||
"-n, --length <length:number>",
|
"-n, --length <length:number>",
|
||||||
"Length of the word to use from the dictionnary.",
|
"Length of the word to use from the dictionnary.",
|
||||||
|
).option(
|
||||||
|
"-m, --max <max:number>",
|
||||||
|
"Maximum number of iterations.",
|
||||||
).option(
|
).option(
|
||||||
"-w, --wait <wait:number>",
|
"-w, --wait <wait:number>",
|
||||||
"Time to wait between guesses, in ms.",
|
"Time to wait between guesses, in ms.",
|
||||||
|
@ -56,8 +60,10 @@ async function main() {
|
||||||
console.log("Target is", game.word);
|
console.log("Target is", game.word);
|
||||||
console.log();
|
console.log();
|
||||||
|
|
||||||
const runner = new Runner(game, guesser, new TableLogging(), args.options.wait);
|
const runner = new Runner(game, guesser, new TableLogging(), args.options.wait, args.options.max);
|
||||||
await runner.play_all();
|
const result = last(await runner.play_all());
|
||||||
|
if (result === undefined) Deno.exit(1);
|
||||||
|
if (result.result.kind === "failure") Deno.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate_target(target: string, length: number) {
|
function validate_target(target: string, length: number) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue