diff --git a/examples/wordle/Makefile b/examples/wordle/Makefile new file mode 100644 index 0000000..2ad4a02 --- /dev/null +++ b/examples/wordle/Makefile @@ -0,0 +1,21 @@ +BASE := today + +TEST = 1 + +words.ptable.tsv: word-probs.csv + perl make-ptable-from-words.pl $< > $@ +letters.ptable.tsv: letter-freqs.csv + perl make-ptable-from-letter-freqs.pl $< > $@ +today.ptable.tsv: words.ptable.tsv letters.ptable.tsv + cat $^ > $@ + +ont-%.pre: my-guesses-%.csv + perl guesses2owl.pl $< > $@ + +ont-%.omn: ont-%.pre + cat wordle.omn $< > $@ + +today.owl: ont-$(TEST).omn + cp $< $@ + +include ../Makefile diff --git a/examples/wordle/README.md b/examples/wordle/README.md new file mode 100644 index 0000000..e8a1b1c --- /dev/null +++ b/examples/wordle/README.md @@ -0,0 +1,80 @@ +# Boomerdle + +NOT WORKING + +aims to show how boomer can be used to find most likely Wordle answers. + +## Background knowledge + +[letter-freqs.csv](letter-freqs.csv): + +``` +A, 0.05, 0.05, 0.05, 0.05, 0.05 +B, 0.05, 0.05, 0.05, 0.05, 0.05 +C, 0.05, 0.05, 0.05, 0.05, 0.05 +``` + +this is the prior chance of a letter being present at positions 1-5. Currently seeded at equal probs but this could be changed, e.g. Q lower. + +probabilities of pairwise, e.g Q-followed-by-not-U is not supported + +This is compiled to a ptable [letters.ptable.tsv](letters.ptable.tsv) by [make-ptable-from-words.pl](make-ptable-from-words.pl) + +``` +✗ less word-probs.csv +bunch, 0.001 +canoe, 0.001 +stair, 0.001 +stare, 0.001 +dance, 0.001 +zebra, 0.0005 +``` + +this is just a demo set. Could be expanded using any dictionary plus info on frequencies + +This is converted to words.ptable.tsv + +## Logical Axioms + +### Background Knowledge + +[wordle.omn](wordle.omn) + +### Guesses so far + +These go in: + +my-guesses-N.csv + +the 2nd colum is the wordle feedback (G=green, O=organe) + +These are translated into logical axioms (combined with the list of all words) + +canoe, OxGxx + +=> + +```owl +Class: soln:canoe DisjointWith: :TodaysWord +Class: :TodaysWord SubClassOf: :hasLetter some :C +Class: :TodaysWord DisjointWith: :hasLetter1 some :C +Class: :TodaysWord DisjointWith: :hasLetter some :A +Class: :TodaysWord SubClassOf: :hasLetter3 some :N +Class: :TodaysWord DisjointWith: :hasLetter some :O +Class: :TodaysWord DisjointWith: :hasLetter some :E +Class: soln:bunch +Class: soln:canoe +Class: soln:stair +Class: soln:stare +Class: soln:dance +Class: soln:zebra +Class: :TodaysWord DisjointUnionOf: soln:bunch, soln:canoe, soln:stair, soln:stare, soln:dance, soln:zebra +Class: :TodaysWord SubClassOf: soln:bunch OR soln:canoe OR soln:stair OR soln:stare OR soln:dance OR soln:zebra +``` + +## Boomer + +all ptables and owl is combined and boomer is run + +currently Whelk doesn't support DisjointUnionOf so we can't 'close the world', and boomer gives the most likely answer +as being *none* of the candidate words, so it refuses to play and pick one (not unlike the computer in wargames). diff --git a/examples/wordle/guesses2owl.pl b/examples/wordle/guesses2owl.pl new file mode 100755 index 0000000..621f711 --- /dev/null +++ b/examples/wordle/guesses2owl.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl +use strict; + +#print "Prefix: : \n"; +#print "Prefix: soln: \n"; + +#print "## Constraints from guesses\n"; +#print "Ontology: \n\n"; + + +while (<>) { + chomp; + my ($w, $result) = split(/,\s+/, $_); + $w = lc($w); + # we rule out the word in its entirety + print "Class: soln:$w DisjointWith: :TodaysWord\n"; + for my $i (0..4) { + my $n = $i+1; + my $letter = uc(substr($w,$i,1)); + my $letter_result = substr($result,$i,1); + if ($letter_result eq 'x') { + print "Class: :TodaysWord DisjointWith: :hasLetter some :$letter\n"; + } + elsif ($letter_result eq 'G') { + print "Class: :TodaysWord SubClassOf: :hasLetter$n some :$letter\n"; + } + elsif ($letter_result eq 'O') { + print "Class: :TodaysWord SubClassOf: :hasLetter some :$letter\n"; + print "Class: :TodaysWord DisjointWith: :hasLetter$n some :$letter\n"; + } + else { + die "Word: $w results: $result index: $i == $letter_result"; + } + } +} +open(F, 'word-probs.csv'); +my @words = (); +while () { + chomp; + s@,.*@@; + my $c = "soln:$_"; + push(@words, $c); + print "Class: $c\n"; +} +close(F); +my $wstr = join(', ', @words); +my $union = join(' OR ', @words); +# whelk doesn't support: +print "Class: :TodaysWord DisjointUnionOf: $wstr\n"; +print "Class: :TodaysWord SubClassOf: $union\n"; diff --git a/examples/wordle/letter-freqs.csv b/examples/wordle/letter-freqs.csv new file mode 100644 index 0000000..5bbdb1f --- /dev/null +++ b/examples/wordle/letter-freqs.csv @@ -0,0 +1,26 @@ +A, 0.05, 0.05, 0.05, 0.05, 0.05 +B, 0.05, 0.05, 0.05, 0.05, 0.05 +C, 0.05, 0.05, 0.05, 0.05, 0.05 +D, 0.05, 0.05, 0.05, 0.05, 0.05 +E, 0.05, 0.05, 0.05, 0.05, 0.05 +F, 0.05, 0.05, 0.05, 0.05, 0.05 +G, 0.05, 0.05, 0.05, 0.05, 0.05 +H, 0.05, 0.05, 0.05, 0.05, 0.05 +I, 0.05, 0.05, 0.05, 0.05, 0.05 +J, 0.05, 0.05, 0.05, 0.05, 0.05 +K, 0.05, 0.05, 0.05, 0.05, 0.05 +L, 0.05, 0.05, 0.05, 0.05, 0.05 +M, 0.05, 0.05, 0.05, 0.05, 0.05 +N, 0.05, 0.05, 0.05, 0.05, 0.05 +O, 0.05, 0.05, 0.05, 0.05, 0.05 +P, 0.05, 0.05, 0.05, 0.05, 0.05 +Q, 0.05, 0.05, 0.05, 0.05, 0.05 +R, 0.05, 0.05, 0.05, 0.05, 0.05 +S, 0.05, 0.05, 0.05, 0.05, 0.05 +T, 0.05, 0.05, 0.05, 0.05, 0.05 +U, 0.05, 0.05, 0.05, 0.05, 0.05 +V, 0.05, 0.05, 0.05, 0.05, 0.05 +W, 0.05, 0.05, 0.05, 0.05, 0.05 +X, 0.05, 0.05, 0.05, 0.05, 0.05 +Y, 0.05, 0.05, 0.05, 0.05, 0.05 +Z, 0.05, 0.05, 0.05, 0.05, 0.05 diff --git a/examples/wordle/make-ptable-from-letter-freqs.pl b/examples/wordle/make-ptable-from-letter-freqs.pl new file mode 100755 index 0000000..0c141b9 --- /dev/null +++ b/examples/wordle/make-ptable-from-letter-freqs.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +use strict; + +open(F,'letter-freqs.csv'); +while () { + chomp; + my ($letter,@rest) = split(/,\s*/, $_); + for my $i (0..4) { + my $n = $i+1; + my $p = $rest[$i]; + my $np = 1-$p; + print "wordle:$letter\twordle:Letter$n\t$p\t0\t0\t$np\n"; + } +} diff --git a/examples/wordle/make-ptable-from-words.pl b/examples/wordle/make-ptable-from-words.pl new file mode 100644 index 0000000..4446e52 --- /dev/null +++ b/examples/wordle/make-ptable-from-words.pl @@ -0,0 +1,13 @@ +#!/usr/bin/perl +use strict; + +open(F,'word-probs.csv'); +while () { + chomp; + my ($w,$p) = split(/,\s*/, $_); + if (!$p) { + $p = '0.0001'; + } + my $np = 1-$p; + print "soln:$w\twordle:TodaysWord\t0\t0\t$p\t$np\n"; +} diff --git a/examples/wordle/my-guesses-1.csv b/examples/wordle/my-guesses-1.csv new file mode 100644 index 0000000..37e2790 --- /dev/null +++ b/examples/wordle/my-guesses-1.csv @@ -0,0 +1 @@ +canoe, OxGxx diff --git a/examples/wordle/prefixes.yaml b/examples/wordle/prefixes.yaml new file mode 100644 index 0000000..7521633 --- /dev/null +++ b/examples/wordle/prefixes.yaml @@ -0,0 +1,3 @@ +wordle: http://example.org/wordle/ +soln: http://example.org/soln/ + diff --git a/examples/wordle/true-answer-1.csv b/examples/wordle/true-answer-1.csv new file mode 100644 index 0000000..4f454c3 --- /dev/null +++ b/examples/wordle/true-answer-1.csv @@ -0,0 +1 @@ +bunch diff --git a/examples/wordle/word-probs.csv b/examples/wordle/word-probs.csv new file mode 100644 index 0000000..8e44665 --- /dev/null +++ b/examples/wordle/word-probs.csv @@ -0,0 +1,6 @@ +bunch, 0.001 +canoe, 0.001 +stair, 0.001 +stare, 0.001 +dance, 0.001 +zebra, 0.0005 diff --git a/examples/wordle/wordle.omn b/examples/wordle/wordle.omn new file mode 100644 index 0000000..2b0397b --- /dev/null +++ b/examples/wordle/wordle.omn @@ -0,0 +1,74 @@ +Prefix: : +Prefix: soln: + +## Wordle +Ontology: + + +ObjectProperty: :hasLetter +ObjectProperty: :hasLetter1 + Characteristics: Functional + SubPropertyOf: :hasLetter +ObjectProperty: :hasLetter2 + Characteristics: Functional + SubPropertyOf: :hasLetter +ObjectProperty: :hasLetter3 + Characteristics: Functional + SubPropertyOf: :hasLetter +ObjectProperty: :hasLetter4 + Characteristics: Functional + SubPropertyOf: :hasLetter +ObjectProperty: :hasLetter5 + Characteristics: Functional + SubPropertyOf: :hasLetter + +Class: :Letter + DisjointUnionOf: :A, :B, :C, :D, :E, :F, :G, :H, :I, :J, :K, :L, :M, :N, :O, :P, :Q, :R, :S, :T, :U, :V, :W, :X, :Y, :Z + SubClassOf: :A OR :B OR :C OR :D OR :E OR :F OR :G OR :H OR :I OR :J OR :K OR :L OR :M OR :N OR :O OR :P OR :Q OR :R OR :S OR :T OR :U OR :V OR :W OR :X OR :Y OR :Z +Class: :A SubClassOf: :Letter +Class: :B SubClassOf: :Letter +Class: :C SubClassOf: :Letter +Class: :D SubClassOf: :Letter +Class: :E SubClassOf: :Letter +Class: :F SubClassOf: :Letter +Class: :G SubClassOf: :Letter +Class: :H SubClassOf: :Letter +Class: :I SubClassOf: :Letter +Class: :J SubClassOf: :Letter +Class: :K SubClassOf: :Letter +Class: :L SubClassOf: :Letter +Class: :M SubClassOf: :Letter +Class: :N SubClassOf: :Letter +Class: :O SubClassOf: :Letter +Class: :P SubClassOf: :Letter +Class: :Q SubClassOf: :Letter +Class: :R SubClassOf: :Letter +Class: :S SubClassOf: :Letter +Class: :T SubClassOf: :Letter +Class: :U SubClassOf: :Letter +Class: :V SubClassOf: :Letter +Class: :W SubClassOf: :Letter +Class: :X SubClassOf: :Letter +Class: :Y SubClassOf: :Letter +Class: :Z SubClassOf: :Letter + +Class: :Letter1 + SubClassOf: :Letter +Class: :Letter2 + SubClassOf: :Letter +Class: :Letter3 + SubClassOf: :Letter +Class: :Letter4 + SubClassOf: :Letter +Class: :Letter5 + SubClassOf: :Letter + + +Class: :TodaysWord + SubClassOf: :hasLetter1 some :Letter1, :hasLetter1 only :Letter1 + SubClassOf: :hasLetter2 some :Letter2, :hasLetter2 only :Letter2 + SubClassOf: :hasLetter3 some :Letter3, :hasLetter3 only :Letter3 + SubClassOf: :hasLetter4 some :Letter4, :hasLetter4 only :Letter4 + SubClassOf: :hasLetter5 some :Letter5, :hasLetter5 only :Letter5 + +