diff --git a/build.sh b/build.sh index 95996d8..52377e9 100755 --- a/build.sh +++ b/build.sh @@ -2,10 +2,7 @@ set -e cd "$(dirname "$(realpath "$0")")" - mkdir -p bin - deno compile -o bin/manual_proxy src/manual_proxy.ts deno compile -o bin/simulation src/simulation.ts -deno compile -o bin/game src/game.ts diff --git a/deno.lock b/deno.lock index e5c2464..832355f 100644 --- a/deno.lock +++ b/deno.lock @@ -1,7 +1,6 @@ { "version": "3", "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" }, "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_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74", "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/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", "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/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", "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/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", "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/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf", "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/_errors.ts": "d78e1b4d69d84b8b476b5f3c0b028e3906d48f21b8f1ca1d36d5abe9ccfe48bc", "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/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/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" + "https://deno.land/x/cliffy@v1.0.0-rc.4/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684" } } diff --git a/profile/aies.sh b/profile/aies.sh deleted file mode 100755 index a353f66..0000000 --- a/profile/aies.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -e -cd "$(dirname "$(realpath "$0")")" - - -PROFILE=true ../src/simulation.ts --target=aies diff --git a/src/game.ts b/src/game.ts deleted file mode 100644 index 324e64a..0000000 --- a/src/game.ts +++ /dev/null @@ -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 ", - "Sets dictionnary to use words from (defaults to internal french dict).", - ).option( - "-l, --length ", - "Length of the word to use from the dictionnary.", - ).option( - "-n, --iterations ", - "Number of iterations.", - ).option( - "-t, --target ", - "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(); diff --git a/src/lib/guesser/explorer.ts b/src/lib/guesser/explorer.ts index 1be4322..73dd703 100644 --- a/src/lib/guesser/explorer.ts +++ b/src/lib/guesser/explorer.ts @@ -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 { Dict } from "../dict.ts"; import { GuessResult } from "../game/game.ts"; -import { Guessing, pick_random_common_word } from "./guesser.ts"; +import { Guessing } from "./guesser.ts"; type Knowledge = { letter: string; diff --git a/src/lib/guesser/input.ts b/src/lib/guesser/input.ts deleted file mode 100644 index 2a1570a..0000000 --- a/src/lib/guesser/input.ts +++ /dev/null @@ -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) { - 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; -} diff --git a/src/lib/guesser/reducing.ts b/src/lib/guesser/reducing.ts index aa7f090..2f34558 100644 --- a/src/lib/guesser/reducing.ts +++ b/src/lib/guesser/reducing.ts @@ -6,7 +6,6 @@ import { GuessResult, Info } from "../game/game.ts"; import { info_of_guess } from "../game/simulator.ts"; import { Awaitable, dbg, enumerate, first, range, zip } from "../utils.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 { length; @@ -23,7 +22,7 @@ export class ReducingGuesser implements Guessing { return ["candidates", "best score"]; } - public async guess_impl(try_: (guess: string, candidates: number, score: number) => Awaitable) { + public async guess(try_: (guess: string, candidates: number, score: number) => Awaitable) { 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); if (score >= this.candidates.size) { @@ -39,13 +38,6 @@ export class ReducingGuesser implements Guessing { return null; } - public async guess(try_: (guess: string, candidates: number, score: number) => Awaitable) { - tip("guess"); - const res = await this.guess_impl(try_); - top("guess"); - return res; - } - learn(word: string, infos: Info[]) { let next_cnd = new Map([...this.candidates.values()].map((value) => [value, value])); // 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) { - tip("word_cuts"); const results = [...range(0, word.length)] .map(() => [new Set(), new Set(), new Set()] as const); for (const option of dict) { @@ -111,12 +102,10 @@ function word_cuts(word: string, dict: Set) { if (info.kind === "abscent") results[index][2].add(option); } } - top("word_cuts"); return results; } function get_word_with_smallest_cuts(candidates: Set, dict: Set) { - tip("get_word_with_smallest_cuts"); let best = null as null | [string, number]; for (const candidate of dict.values()) { const cuts = word_cuts(candidate, candidates); @@ -126,7 +115,6 @@ function get_word_with_smallest_cuts(candidates: Set, dict: Set) else if (max_part_size < best[1]) best = [candidate, max_part_size]; } assertExists(best); - top("get_word_with_smallest_cuts"); return best; } diff --git a/src/lib/lib.ts b/src/lib/lib.ts index 9a6affb..4dfe6c4 100644 --- a/src/lib/lib.ts +++ b/src/lib/lib.ts @@ -4,7 +4,6 @@ export type { LoggingStrategy } from "./runner.ts"; export { Dict } from "./dict.ts"; export { ExplorerGuesser } from "./guesser/explorer.ts"; export { ReducingGuesser } from "./guesser/reducing.ts"; -export { InputGuesser } from "./guesser/input.ts"; export { Simulator } from "./game/simulator.ts"; export { ManualProxy } from "./game/proxy.ts"; -export { GameLogging, Runner, TableLogging, VerboseLogging } from "./runner.ts"; +export { Runner, TableLogging, VerboseLogging } from "./runner.ts"; diff --git a/src/lib/prompt.ts b/src/lib/prompt.ts index 80f866f..01f42a8 100644 --- a/src/lib/prompt.ts +++ b/src/lib/prompt.ts @@ -1,16 +1,14 @@ import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts"; -import { enumerate, LineReader } 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"; +import { enumerate } from "./utils.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(" letter [a-z] known letter"); console.log(" dot . unknown letter"); console.log("example : .rb.."); console.log(""); - const inputted = await parse_initialization_until_correct(lines); + const inputted = parse_initialization_until_correct(); console.log(""); console.log("From now on, please try the following guesses and report results. Format is :"); console.log(" plus + correct"); @@ -21,14 +19,13 @@ export async function initialize_prompt(lines: LineReader) { return inputted; } -async function parse_initialization_until_correct(lines: LineReader) { - print(Deno.stdout, "initial : "); +function parse_initialization_until_correct() { + let input = prompt("initial :"); while (true) { - const input = await lines.read(); assertExists(input); const parsed = parse_initialization(input); - if (parsed !== null) return parsed; - print(Deno.stdout, "Invalid, please try again : "); + if (parsed === null) input = prompt("Invalid, please try again :"); + else return parsed; } } @@ -47,8 +44,3 @@ function parse_initialization(input: string) { } return { length, constraints }; } - -async function print(writer: Writer, ...rest: unknown[]) { - const text = rest.map((o) => `${o}`).join(" "); - await writeAll(writer, new TextEncoder().encode(text)); -} diff --git a/src/lib/runner.ts b/src/lib/runner.ts index 5fa9229..a9edf50 100644 --- a/src/lib/runner.ts +++ b/src/lib/runner.ts @@ -3,7 +3,6 @@ import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists import { Guessing } from "./guesser/guesser.ts"; import { Gaming, GuessResult } from "./game/game.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 { game; @@ -22,22 +21,15 @@ export class Runner { this.max = max; } - async play_once() { - tip("play_once"); - const res = await this.guesser.guess(async (guess, ...properties) => { - const result = await this.game.guess(guess); - this.turns.push({ guess, result }); - this.logging.on_guess(guess, result, ...properties); - 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(); + const result = await this.guesser.guess(async (guess, ...properties) => { + const result = await this.game.guess(guess); + this.turns.push({ guess, result }); + this.logging.on_guess(guess, result, ...properties); + return result; + }); if (result !== null) break; if (this.max !== undefined) if (this.turns.length >= this.max) return this.turns; await wait(this.delay_ms); @@ -130,31 +122,3 @@ export class TableLogging implements LoggingStrategy { 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; - } -} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e3d79fe..4903927 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -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(iterator: Iterable) { let index = 0; for (const item of iterator) yield [index++, item] as const; @@ -45,93 +41,3 @@ export function dbg(value: T, ...rest: unknown[]) { } export type Value = { value: T }; - -export function next(iterator: Iterator) { - const result = iterator.next().value; - if (result === undefined) return null; - else return result as T; -} - -export async function async_next(iterator: AsyncIterator) { - 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) { - 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) { - 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) { - const queue = new AsyncQueue(); - ReadableStream.from(queue.iter()).pipeThrough(new TextEncoderStream()).pipeTo(writable); - return { queue, write: (line: string) => queue.push(line) }; -} - -export type Consumer = (value: T) => void; - -export function split_promise() { - let resolver = null as null | Consumer; - const promise = new Promise((res) => resolver = res); - assertExists(resolver); - return [promise, resolver] as const; -} - -class AsyncQueue { - items; - item_resolver; - - constructor() { - this.items = [] as T[]; - this.item_resolver = null as null | Consumer; - } - - 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(); - 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))); -} diff --git a/src/manual_proxy.ts b/src/manual_proxy.ts index 6dce195..1b7d935 100755 --- a/src/manual_proxy.ts +++ b/src/manual_proxy.ts @@ -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 { Dict, ExplorerGuesser, Guessing, ManualProxy, ReducingGuesser, Runner } from "./lib/lib.ts"; import { initialize_prompt } from "./lib/prompt.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() { const args = await new Command().name("manual_proxy") @@ -23,8 +22,7 @@ async function main() { { default: "reducing" }, ).parse(Deno.args); - const lines_ = new LineReader(Deno.stdin.readable); - const init = await initialize_prompt(lines_); + const init = initialize_prompt(); let dict = Dict.from_lines(gutenberg, init.length); if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, init.length); diff --git a/src/simulation.ts b/src/simulation.ts index 0b965ee..4b4ed65 100755 --- a/src/simulation.ts +++ b/src/simulation.ts @@ -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 { report, tip, top } from "https://git.barnulf.net/mb/profiterole/raw/branch/master/mod.ts"; import { Dict, @@ -15,7 +14,7 @@ import { VerboseLogging, } from "./lib/lib.ts"; -import { gutenberg } from "../data/data.ts"; +import { francais } from "../data/data.ts"; import { last } from "./lib/utils.ts"; async function main() { @@ -52,10 +51,8 @@ async function main() { .parse(Deno.args); const length = args.options.length ?? args.options.target?.length ?? 6; - tip("dict"); - let dict = Dict.from_lines(gutenberg, length); + let dict = Dict.from_lines(francais, 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); let game = Simulator.from_dict_rand(dict); @@ -67,8 +64,6 @@ async function main() { const result = last(await runner.play_all()); if (result === undefined) Deno.exit(1); if (result.result.kind === "failure") Deno.exit(1); - - report(); } function validate_target(target: string, length: number) {