Compare commits
No commits in common. "optimize" and "master" have entirely different histories.
13 changed files with 23 additions and 290 deletions
3
build.sh
3
build.sh
|
@ -2,10 +2,7 @@
|
||||||
set -e
|
set -e
|
||||||
cd "$(dirname "$(realpath "$0")")"
|
cd "$(dirname "$(realpath "$0")")"
|
||||||
|
|
||||||
|
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
|
|
||||||
|
|
||||||
deno compile -o bin/manual_proxy src/manual_proxy.ts
|
deno compile -o bin/manual_proxy src/manual_proxy.ts
|
||||||
deno compile -o bin/simulation src/simulation.ts
|
deno compile -o bin/simulation src/simulation.ts
|
||||||
deno compile -o bin/game src/game.ts
|
|
||||||
|
|
13
deno.lock
generated
13
deno.lock
generated
|
@ -1,7 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": "3",
|
"version": "3",
|
||||||
"redirects": {
|
"redirects": {
|
||||||
"https://deno.land/std@0.224.0/streams/": "https://deno.land/std@0.224.0/streams",
|
|
||||||
"https://deno.land/x/cliffy/command/mod.ts": "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"
|
"https://deno.land/x/cliffy/command/mod.ts": "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"
|
||||||
},
|
},
|
||||||
"remote": {
|
"remote": {
|
||||||
|
@ -17,15 +16,12 @@
|
||||||
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
|
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
|
||||||
"https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74",
|
"https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74",
|
||||||
"https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
|
"https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
|
||||||
"https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29",
|
|
||||||
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
|
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
|
||||||
"https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47",
|
"https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47",
|
||||||
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
|
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
|
||||||
"https://deno.land/std@0.224.0/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f",
|
|
||||||
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
|
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
|
||||||
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
|
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
|
||||||
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
|
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
|
||||||
"https://deno.land/std@0.224.0/io/write_all.ts": "24aac2312bb21096ae3ae0b102b22c26164d3249dff96dbac130958aa736f038",
|
|
||||||
"https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
|
"https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
|
||||||
"https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
|
"https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
|
||||||
"https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
|
"https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
|
||||||
|
@ -43,7 +39,6 @@
|
||||||
"https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
|
"https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
|
||||||
"https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
|
"https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
|
||||||
"https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
|
"https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
|
||||||
"https://deno.land/std@0.224.0/streams/text_line_stream.ts": "21f33d3922e019ec1a1676474beb543929cb564ec99b69cd2654e029e0f45bd5",
|
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead",
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_errors.ts": "d78e1b4d69d84b8b476b5f3c0b028e3906d48f21b8f1ca1d36d5abe9ccfe48bc",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_errors.ts": "d78e1b4d69d84b8b476b5f3c0b028e3906d48f21b8f1ca1d36d5abe9ccfe48bc",
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245",
|
||||||
|
@ -102,12 +97,6 @@
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/consume_words.ts": "369d065dbf7f15c664ea8523e0ef750fb952aea6d88e146c375e64aec9503052",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/consume_words.ts": "369d065dbf7f15c664ea8523e0ef750fb952aea6d88e146c375e64aec9503052",
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/deps.ts": "cbb896e8d7a6b5e3c2b9dda7d16638c202d9b46eb738c2dae1fa9480d8091486",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/deps.ts": "cbb896e8d7a6b5e3c2b9dda7d16638c202d9b46eb738c2dae1fa9480d8091486",
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f",
|
||||||
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684",
|
"https://deno.land/x/cliffy@v1.0.0-rc.4/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684"
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/data/generated.ts": "3af769f4f14914c8fca84054f580754b797fd5c0fef9ef59e9f47bfed7ba6f7c",
|
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/mod.ts": "bc9436bcf45f3204ebcd0b2559f53e5d38162195fc48ac6d435cf8ca38c77ae3",
|
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/src/lib.ts": "d0d9af31237f93f6b6c2b695ac2fdcc7e761ca3904382e140f4676fc109d8453",
|
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/src/lib/observer.ts": "58beebe5f1854b16470df7a715f9cb60dc7db4d4f8648a71eee58a3d1cb7bb53",
|
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/src/lib/types.ts": "ecd5f1260a839576787e22ff205fee0399837c66f037f31f0322df723f1490c2",
|
|
||||||
"https://git.barnulf.net/mb/profiterole/raw/commit/02d19fce2a0878abd176801cf8f2a663f6db6c16/src/lib/utils.ts": "e79ae3583e148fd8ccf5d53f9d7d316ee658b6a62c3a0f66517c630c1586e0a8"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
cd "$(dirname "$(realpath "$0")")"
|
|
||||||
|
|
||||||
|
|
||||||
PROFILE=true ../src/simulation.ts --target=aies
|
|
47
src/game.ts
47
src/game.ts
|
@ -1,47 +0,0 @@
|
||||||
#!/usr/bin/env -S deno run --allow-read
|
|
||||||
|
|
||||||
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
|
|
||||||
import { Dict, GameLogging, InputGuesser, Runner, Simulator } from "./lib/lib.ts";
|
|
||||||
import { gutenberg } from "../data/data.ts";
|
|
||||||
import { range } from "./lib/utils.ts";
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const args = await new Command().name("simulation")
|
|
||||||
.description(
|
|
||||||
"Program to simulate TUSMO game with guesser controller.",
|
|
||||||
)
|
|
||||||
.option(
|
|
||||||
"-f, --file <path:string>",
|
|
||||||
"Sets dictionnary to use words from (defaults to internal french dict).",
|
|
||||||
).option(
|
|
||||||
"-l, --length <length:number>",
|
|
||||||
"Length of the word to use from the dictionnary.",
|
|
||||||
).option(
|
|
||||||
"-n, --iterations <iterations:number>",
|
|
||||||
"Number of iterations.",
|
|
||||||
).option(
|
|
||||||
"-t, --target <target:string>",
|
|
||||||
"Target word to search for.",
|
|
||||||
).parse(Deno.args);
|
|
||||||
|
|
||||||
const length = args.options.length ?? args.options.target?.length ?? 6;
|
|
||||||
|
|
||||||
let dict = Dict.from_lines(gutenberg, length);
|
|
||||||
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, length);
|
|
||||||
|
|
||||||
let game = Simulator.from_dict_rand(dict);
|
|
||||||
if (args.options.target !== undefined) game = new Simulator(validate_target(args.options.target, length));
|
|
||||||
|
|
||||||
const guesser = new InputGuesser(length);
|
|
||||||
const runner = new Runner(game, guesser, new GameLogging());
|
|
||||||
|
|
||||||
const iterations = args.options.iterations ?? 100_000;
|
|
||||||
for (const _ of range(0, iterations)) await runner.play_once();
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate_target(target: string, length: number) {
|
|
||||||
if (target.length !== length) throw new Error("Invalid target length");
|
|
||||||
return target.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (import.meta.main) await main();
|
|
|
@ -3,7 +3,7 @@ import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists
|
||||||
import { Awaitable, enumerate, range, zip } from "../utils.ts";
|
import { Awaitable, enumerate, range, zip } from "../utils.ts";
|
||||||
import { Dict } from "../dict.ts";
|
import { Dict } from "../dict.ts";
|
||||||
import { GuessResult } from "../game/game.ts";
|
import { GuessResult } from "../game/game.ts";
|
||||||
import { Guessing, pick_random_common_word } from "./guesser.ts";
|
import { Guessing } from "./guesser.ts";
|
||||||
|
|
||||||
type Knowledge = {
|
type Knowledge = {
|
||||||
letter: string;
|
letter: string;
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
|
|
||||||
import { GuessResult } from "../game/game.ts";
|
|
||||||
import { async_next, Awaitable, LineReader } from "../utils.ts";
|
|
||||||
import { Guessing } from "./guesser.ts";
|
|
||||||
|
|
||||||
export class InputGuesser implements Guessing {
|
|
||||||
length;
|
|
||||||
lines;
|
|
||||||
|
|
||||||
constructor(length: number) {
|
|
||||||
this.length = length;
|
|
||||||
this.lines = new LineReader(Deno.stdin.readable);
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_properties(): string[] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
async next_line() {
|
|
||||||
const value = await this.lines.read();
|
|
||||||
assertExists(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
async guess(try_: (guess: string, ...properties: unknown[]) => Awaitable<GuessResult>) {
|
|
||||||
let input = "";
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
input = await this.next_line();
|
|
||||||
if (input.length === this.length && are_letters(input)) break;
|
|
||||||
console.log("Word is length", this.length, "and composed of letters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return await try_(input.slice(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function are_letters(text: string) {
|
|
||||||
const letters = "azertyuiopqsdfghjklmwxcvbn";
|
|
||||||
for (const char of text) if (!letters.includes(char)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ 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, dbg, enumerate, first, range, zip } from "../utils.ts";
|
import { Awaitable, dbg, enumerate, first, range, zip } from "../utils.ts";
|
||||||
import { Guessing, pick_random_common_word } from "./guesser.ts";
|
import { Guessing, pick_random_common_word } from "./guesser.ts";
|
||||||
import { tip, top } from "https://git.barnulf.net/mb/profiterole/raw/branch/master/mod.ts";
|
|
||||||
|
|
||||||
export class ReducingGuesser implements Guessing {
|
export class ReducingGuesser implements Guessing {
|
||||||
length;
|
length;
|
||||||
|
@ -23,7 +22,7 @@ export class ReducingGuesser implements Guessing {
|
||||||
return ["candidates", "best score"];
|
return ["candidates", "best score"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async guess_impl(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) {
|
if (score >= this.candidates.size) {
|
||||||
|
@ -39,13 +38,6 @@ export class ReducingGuesser implements Guessing {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async guess(try_: (guess: string, candidates: number, score: number) => Awaitable<GuessResult>) {
|
|
||||||
tip("guess");
|
|
||||||
const res = await this.guess_impl(try_);
|
|
||||||
top("guess");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
learn(word: string, infos: Info[]) {
|
learn(word: string, infos: Info[]) {
|
||||||
let next_cnd = new Map([...this.candidates.values()].map((value) => [value, value]));
|
let next_cnd = new Map([...this.candidates.values()].map((value) => [value, value]));
|
||||||
// TODO : should treat all there before somewheres
|
// TODO : should treat all there before somewheres
|
||||||
|
@ -100,7 +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>) {
|
||||||
tip("word_cuts");
|
|
||||||
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) {
|
||||||
|
@ -111,12 +102,10 @@ function word_cuts(word: string, dict: Set<string>) {
|
||||||
if (info.kind === "abscent") results[index][2].add(option);
|
if (info.kind === "abscent") results[index][2].add(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
top("word_cuts");
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>) {
|
function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>) {
|
||||||
tip("get_word_with_smallest_cuts");
|
|
||||||
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(candidate, candidates);
|
const cuts = word_cuts(candidate, candidates);
|
||||||
|
@ -126,7 +115,6 @@ function get_word_with_smallest_cuts(candidates: Set<string>, dict: Set<string>)
|
||||||
else if (max_part_size < best[1]) best = [candidate, max_part_size];
|
else if (max_part_size < best[1]) best = [candidate, max_part_size];
|
||||||
}
|
}
|
||||||
assertExists(best);
|
assertExists(best);
|
||||||
top("get_word_with_smallest_cuts");
|
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ export type { LoggingStrategy } from "./runner.ts";
|
||||||
export { Dict } from "./dict.ts";
|
export { Dict } from "./dict.ts";
|
||||||
export { ExplorerGuesser } from "./guesser/explorer.ts";
|
export { ExplorerGuesser } from "./guesser/explorer.ts";
|
||||||
export { ReducingGuesser } from "./guesser/reducing.ts";
|
export { ReducingGuesser } from "./guesser/reducing.ts";
|
||||||
export { InputGuesser } from "./guesser/input.ts";
|
|
||||||
export { Simulator } from "./game/simulator.ts";
|
export { Simulator } from "./game/simulator.ts";
|
||||||
export { ManualProxy } from "./game/proxy.ts";
|
export { ManualProxy } from "./game/proxy.ts";
|
||||||
export { GameLogging, Runner, TableLogging, VerboseLogging } from "./runner.ts";
|
export { Runner, TableLogging, VerboseLogging } from "./runner.ts";
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
|
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
|
||||||
|
|
||||||
import { enumerate, LineReader } from "./utils.ts";
|
import { enumerate } from "./utils.ts";
|
||||||
import { writeAll } from "https://deno.land/std@0.224.0/io/write_all.ts";
|
|
||||||
import { Writer } from "https://deno.land/std@0.224.0/io/types.ts";
|
|
||||||
|
|
||||||
export async function initialize_prompt(lines: LineReader) {
|
export function initialize_prompt() {
|
||||||
console.log("Please input initial state of the game. Format is :");
|
console.log("Please input initial state of the game. Format is :");
|
||||||
console.log(" letter [a-z] known letter");
|
console.log(" letter [a-z] known letter");
|
||||||
console.log(" dot . unknown letter");
|
console.log(" dot . unknown letter");
|
||||||
console.log("example : .rb..");
|
console.log("example : .rb..");
|
||||||
console.log("");
|
console.log("");
|
||||||
const inputted = await parse_initialization_until_correct(lines);
|
const inputted = parse_initialization_until_correct();
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log("From now on, please try the following guesses and report results. Format is :");
|
console.log("From now on, please try the following guesses and report results. Format is :");
|
||||||
console.log(" plus + correct");
|
console.log(" plus + correct");
|
||||||
|
@ -21,14 +19,13 @@ export async function initialize_prompt(lines: LineReader) {
|
||||||
return inputted;
|
return inputted;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parse_initialization_until_correct(lines: LineReader) {
|
function parse_initialization_until_correct() {
|
||||||
print(Deno.stdout, "initial : ");
|
let input = prompt("initial :");
|
||||||
while (true) {
|
while (true) {
|
||||||
const input = await lines.read();
|
|
||||||
assertExists(input);
|
assertExists(input);
|
||||||
const parsed = parse_initialization(input);
|
const parsed = parse_initialization(input);
|
||||||
if (parsed !== null) return parsed;
|
if (parsed === null) input = prompt("Invalid, please try again :");
|
||||||
print(Deno.stdout, "Invalid, please try again : ");
|
else return parsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +44,3 @@ function parse_initialization(input: string) {
|
||||||
}
|
}
|
||||||
return { length, constraints };
|
return { length, constraints };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function print(writer: Writer, ...rest: unknown[]) {
|
|
||||||
const text = rest.map((o) => `${o}`).join(" ");
|
|
||||||
await writeAll(writer, new TextEncoder().encode(text));
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists
|
||||||
import { Guessing } from "./guesser/guesser.ts";
|
import { Guessing } from "./guesser/guesser.ts";
|
||||||
import { Gaming, GuessResult } from "./game/game.ts";
|
import { Gaming, GuessResult } from "./game/game.ts";
|
||||||
import { last, wait, zip } from "./utils.ts";
|
import { last, wait, zip } from "./utils.ts";
|
||||||
import { tip, top } from "https://git.barnulf.net/mb/profiterole/raw/branch/master/mod.ts";
|
|
||||||
|
|
||||||
export class Runner<Ga extends Gaming, Gu extends Guessing> {
|
export class Runner<Ga extends Gaming, Gu extends Guessing> {
|
||||||
game;
|
game;
|
||||||
|
@ -22,22 +21,15 @@ export class Runner<Ga extends Gaming, Gu extends Guessing> {
|
||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
async play_once() {
|
async play_all() {
|
||||||
tip("play_once");
|
this.logging.on_start(this.game.length(), ...this.guesser.declare_properties());
|
||||||
const res = await this.guesser.guess(async (guess, ...properties) => {
|
while (true) {
|
||||||
|
const result = await this.guesser.guess(async (guess, ...properties) => {
|
||||||
const result = await this.game.guess(guess);
|
const result = await this.game.guess(guess);
|
||||||
this.turns.push({ guess, result });
|
this.turns.push({ guess, result });
|
||||||
this.logging.on_guess(guess, result, ...properties);
|
this.logging.on_guess(guess, result, ...properties);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
top("play_once");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
async play_all() {
|
|
||||||
this.logging.on_start(this.game.length(), ...this.guesser.declare_properties());
|
|
||||||
while (true) {
|
|
||||||
const result = await this.play_once();
|
|
||||||
if (result !== null) break;
|
if (result !== null) break;
|
||||||
if (this.max !== undefined) if (this.turns.length >= this.max) return this.turns;
|
if (this.max !== undefined) if (this.turns.length >= this.max) return this.turns;
|
||||||
await wait(this.delay_ms);
|
await wait(this.delay_ms);
|
||||||
|
@ -130,31 +122,3 @@ export class TableLogging implements LoggingStrategy {
|
||||||
console.log(last_.result.kind, "in", turns.length, "steps");
|
console.log(last_.result.kind, "in", turns.length, "steps");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GameLogging implements LoggingStrategy {
|
|
||||||
on_finish(turns: Turn[]): void {
|
|
||||||
const last_ = last(turns);
|
|
||||||
assertExists(last_);
|
|
||||||
console.log();
|
|
||||||
console.log(last_.result.kind, "in", turns.length, "steps");
|
|
||||||
}
|
|
||||||
|
|
||||||
on_guess(_guess: string, result: GuessResult, ..._properties: unknown[]): void {
|
|
||||||
console.log(this.result_to_display(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
on_start(_length: number, ..._properties: string[]): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
result_to_display(result: GuessResult) {
|
|
||||||
if (result.kind === "success") return " success";
|
|
||||||
|
|
||||||
let line = " ";
|
|
||||||
for (const info of result.informations) {
|
|
||||||
if (info.kind === "abscent") line += ".";
|
|
||||||
if (info.kind === "somewhere") line += "-";
|
|
||||||
if (info.kind === "there") line += "+";
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
|
|
||||||
import { dirname } from "https://deno.land/std@0.224.0/path/dirname.ts";
|
|
||||||
import { TextLineStream } from "https://deno.land/std@0.224.0/streams/text_line_stream.ts";
|
|
||||||
|
|
||||||
export function* enumerate<T>(iterator: Iterable<T>) {
|
export function* enumerate<T>(iterator: Iterable<T>) {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (const item of iterator) yield [index++, item] as const;
|
for (const item of iterator) yield [index++, item] as const;
|
||||||
|
@ -45,93 +41,3 @@ export function dbg<T>(value: T, ...rest: unknown[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Value<T> = { value: T };
|
export type Value<T> = { value: T };
|
||||||
|
|
||||||
export function next<T>(iterator: Iterator<T>) {
|
|
||||||
const result = iterator.next().value;
|
|
||||||
if (result === undefined) return null;
|
|
||||||
else return result as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function async_next<T>(iterator: AsyncIterator<T>) {
|
|
||||||
const result = await iterator.next();
|
|
||||||
const value = result.value;
|
|
||||||
if (value === undefined) return null;
|
|
||||||
else return value as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LineReader {
|
|
||||||
iterator;
|
|
||||||
|
|
||||||
constructor(readable: ReadableStream<Uint8Array>) {
|
|
||||||
this.iterator = readable
|
|
||||||
.pipeThrough(new TextDecoderStream())
|
|
||||||
.pipeThrough(new TextLineStream())
|
|
||||||
[Symbol.asyncIterator]();
|
|
||||||
}
|
|
||||||
|
|
||||||
async read() {
|
|
||||||
return await async_next(this.iterator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class LineWriter {
|
|
||||||
writable;
|
|
||||||
|
|
||||||
constructor(writable: WritableStream<Uint8Array>) {
|
|
||||||
const encoder = new TextEncoderStream();
|
|
||||||
encoder.readable.pipeTo(writable);
|
|
||||||
this.writable = encoder.writable.getWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
async write(line: string) {
|
|
||||||
await this.writable.write(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function write_lines(writable: WritableStream<Uint8Array>) {
|
|
||||||
const queue = new AsyncQueue<string>();
|
|
||||||
ReadableStream.from(queue.iter()).pipeThrough(new TextEncoderStream()).pipeTo(writable);
|
|
||||||
return { queue, write: (line: string) => queue.push(line) };
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Consumer<T> = (value: T) => void;
|
|
||||||
|
|
||||||
export function split_promise<T = void>() {
|
|
||||||
let resolver = null as null | Consumer<T>;
|
|
||||||
const promise = new Promise<T>((res) => resolver = res);
|
|
||||||
assertExists(resolver);
|
|
||||||
return [promise, resolver] as const;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AsyncQueue<T> {
|
|
||||||
items;
|
|
||||||
item_resolver;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.items = [] as T[];
|
|
||||||
this.item_resolver = null as null | Consumer<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
push(item: T) {
|
|
||||||
if (this.item_resolver !== null) this.item_resolver(item);
|
|
||||||
else this.items.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
async pull() {
|
|
||||||
const [first] = this.items.splice(0, 1);
|
|
||||||
if (first !== undefined) return first;
|
|
||||||
const [promise, resolver] = split_promise<T>();
|
|
||||||
this.item_resolver = resolver;
|
|
||||||
return await promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
async *iter() {
|
|
||||||
while (true) yield await this.pull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function project_root() {
|
|
||||||
const this_url = new URL(import.meta.url);
|
|
||||||
const this_path = await Deno.realPath(this_url.pathname);
|
|
||||||
return dirname(dirname(dirname(this_path)));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#!/usr/bin/env -S deno run --allow-read --allow-env
|
#!/usr/bin/env -S deno run --allow-read
|
||||||
|
|
||||||
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
|
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
|
||||||
|
|
||||||
import { Dict, ExplorerGuesser, Guessing, ManualProxy, ReducingGuesser, Runner } from "./lib/lib.ts";
|
import { Dict, ExplorerGuesser, Guessing, ManualProxy, ReducingGuesser, Runner } from "./lib/lib.ts";
|
||||||
import { initialize_prompt } from "./lib/prompt.ts";
|
import { initialize_prompt } from "./lib/prompt.ts";
|
||||||
import { VerboseLogging } from "./lib/runner.ts";
|
import { VerboseLogging } from "./lib/runner.ts";
|
||||||
import { LineReader } from "./lib/utils.ts";
|
|
||||||
|
|
||||||
import { gutenberg } from "../data/data.ts";
|
import { francais, gutenberg } from "../data/data.ts";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const args = await new Command().name("manual_proxy")
|
const args = await new Command().name("manual_proxy")
|
||||||
|
@ -23,8 +22,7 @@ async function main() {
|
||||||
{ default: "reducing" },
|
{ default: "reducing" },
|
||||||
).parse(Deno.args);
|
).parse(Deno.args);
|
||||||
|
|
||||||
const lines_ = new LineReader(Deno.stdin.readable);
|
const init = initialize_prompt();
|
||||||
const init = await initialize_prompt(lines_);
|
|
||||||
|
|
||||||
let dict = Dict.from_lines(gutenberg, init.length);
|
let dict = Dict.from_lines(gutenberg, init.length);
|
||||||
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, init.length);
|
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, init.length);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/env -S deno run -A --unstable-temporal
|
#!/usr/bin/env -S deno run --allow-read
|
||||||
|
|
||||||
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
|
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
|
||||||
import { report, tip, top } from "https://git.barnulf.net/mb/profiterole/raw/branch/master/mod.ts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Dict,
|
Dict,
|
||||||
|
@ -15,7 +14,7 @@ import {
|
||||||
VerboseLogging,
|
VerboseLogging,
|
||||||
} from "./lib/lib.ts";
|
} from "./lib/lib.ts";
|
||||||
|
|
||||||
import { gutenberg } from "../data/data.ts";
|
import { francais } from "../data/data.ts";
|
||||||
import { last } from "./lib/utils.ts";
|
import { last } from "./lib/utils.ts";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
@ -52,10 +51,8 @@ async function main() {
|
||||||
.parse(Deno.args);
|
.parse(Deno.args);
|
||||||
const length = args.options.length ?? args.options.target?.length ?? 6;
|
const length = args.options.length ?? args.options.target?.length ?? 6;
|
||||||
|
|
||||||
tip("dict");
|
let dict = Dict.from_lines(francais, length);
|
||||||
let dict = Dict.from_lines(gutenberg, length);
|
|
||||||
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, length);
|
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, length);
|
||||||
top("dict");
|
|
||||||
|
|
||||||
const guesser = guessers.get(args.options.guesser)!(dict);
|
const guesser = guessers.get(args.options.guesser)!(dict);
|
||||||
let game = Simulator.from_dict_rand(dict);
|
let game = Simulator.from_dict_rand(dict);
|
||||||
|
@ -67,8 +64,6 @@ async function main() {
|
||||||
const result = last(await runner.play_all());
|
const result = last(await runner.play_all());
|
||||||
if (result === undefined) Deno.exit(1);
|
if (result === undefined) Deno.exit(1);
|
||||||
if (result.result.kind === "failure") Deno.exit(1);
|
if (result.result.kind === "failure") Deno.exit(1);
|
||||||
|
|
||||||
report();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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