add manual proxy program

This commit is contained in:
JOLIMAITRE Matthieu 2024-04-30 18:17:23 +02:00
parent e058363a52
commit 626e639f59
5 changed files with 76 additions and 21 deletions

View file

@ -25,6 +25,13 @@ export class Dict {
return Dict.from_lines(content.split("\n"), length);
}
constraint(at: number, letter: string) {
const to_delete = new Set<string>();
for (const word of this.words.values()) if (word[at] !== letter) to_delete.add(word);
for (const item of to_delete) this.words.delete(item);
return to_delete.size;
}
[Symbol.for("Deno.customInspect")]() {
return `Dict { ${this.words.size} words, ${this.letters.size} letters }`;
}

View file

@ -12,7 +12,9 @@ export class ManualProxy implements Gaming {
guess(guess: string, _known: string): Awaitable<GuessResult> {
console.log("<proxy> Guessing:", guess);
return read_until_correct(this.word_length);
const result = read_until_correct(this.word_length);
console.log();
return result;
}
length(): number {
@ -25,7 +27,10 @@ function read_until_correct(length: number): GuessResult {
const input = prompt("<proxy> Result:");
assertExists(input);
const informations = parse_input(input, length);
if (informations === null) continue;
if (informations === null) {
console.log("<proxy> incorrect input, try again");
continue;
}
if (informations.every((i) => i.kind === "there")) return { kind: "success" };
return { kind: "failure", informations };
}
@ -34,9 +39,9 @@ function read_until_correct(length: number): GuessResult {
function parse_input(input: string, length: number) {
const parsed = [] as Info[];
for (const character of input.trim()) {
if (character === "n") parsed.push({ kind: "abscent" });
if (character === "i") parsed.push({ kind: "somewhere" });
if (character === "y") parsed.push({ kind: "there" });
if (character === ".") parsed.push({ kind: "abscent" });
if (character === "-") parsed.push({ kind: "somewhere" });
if (character === "+") parsed.push({ kind: "there" });
}
if (parsed.length !== length) return null;
else return parsed;

View file

@ -53,13 +53,13 @@ export class Guesser implements Guessing {
return null;
}
learn_does_not_exist(letter: string) {
public learn_does_not_exist(letter: string) {
const letter_info = this.informations.get(letter);
assertExists(letter_info);
letter_info.exists = false;
}
learn_does_exist(letter: string) {
public learn_does_exist(letter: string) {
const letter_info = this.informations.get(letter);
assertExists(letter_info);
letter_info.exists = true;
@ -68,7 +68,8 @@ export class Guesser implements Guessing {
for (const info of this.informations.values()) if (info.exists === "unknown") info.exists = false;
}
learn_letter_at(letter: string, at: number) {
public learn_letter_at(letter: string, at: number) {
this.learn_does_exist(letter);
const letter_info = this.informations.get(letter);
assertExists(letter_info);
letter_info.at.add(at);
@ -78,7 +79,7 @@ export class Guesser implements Guessing {
}
}
learn_letter_not_at(letter: string, at: number) {
public learn_letter_not_at(letter: string, at: number) {
const letter_info = this.informations.get(letter);
assertExists(letter_info);
letter_info.not_at.add(at);

46
src/lib/prompt.ts Normal file
View file

@ -0,0 +1,46 @@
import { assertExists } from "https://deno.land/std@0.224.0/assert/assert_exists.ts";
import { enumerate } from "./utils.ts";
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 = 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");
console.log(" minus - wrong placement");
console.log(" dot . incorrect");
console.log("example : -++..");
console.log();
return inputted;
}
function parse_initialization_until_correct() {
let input = prompt("initial :");
while (true) {
assertExists(input);
const parsed = parse_initialization(input);
if (parsed === null) input = prompt("Invalid, please try again :");
else return parsed;
}
}
function parse_initialization(input: string) {
const code_a = "a".charCodeAt(0);
const code_z = "z".charCodeAt(0);
let length = 0;
const constraints = [] as [number, string][];
for (const [index, char] of enumerate(input.trim().toLowerCase())) {
length += 1;
if (char === ".") continue;
const code = char.charCodeAt(0);
if (code < code_a) return null;
if (code > code_z) return null;
constraints.push([index, char]);
}
return { length, constraints };
}

20
src/manual_proxy.ts Normal file → Executable file
View file

@ -3,6 +3,7 @@
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts";
import { Dict, Guesser, ManualProxy, Runner } from "./lib/lib.ts";
import { initialize_prompt } from "./lib/prompt.ts";
import { VerboseLogging } from "./lib/runner.ts";
import { francais } from "../data/data.ts";
@ -15,23 +16,18 @@ async function main() {
.option(
"-f, --file <path:string>",
"Sets dictionnary to use words from (defaults to internal french dict).",
).option(
"-n, --length <length:number>",
"Length of the word to use from the dictionnary.",
{ default: 6 },
).option(
"-w, --wait <wait:number>",
"Time to wait between guesses, in ms.",
{ default: 0 },
).parse(Deno.args);
let dict = Dict.from_lines(francais, args.options.length);
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, args.options.length);
const init = initialize_prompt();
let dict = Dict.from_lines(francais, init.length);
if (args.options.file !== undefined) dict = await Dict.from_text_file(args.options.file, init.length);
for (const [index, letter] of init.constraints) dict.constraint(index, letter);
const guesser = new Guesser(dict);
const game = new ManualProxy(args.options.length);
const game = new ManualProxy(init.length);
const runner = new Runner(game, guesser, new VerboseLogging(), args.options.wait);
const runner = new Runner(game, guesser, new VerboseLogging());
await runner.play_all();
}