Download or view wordleDeducer.frink in plain text format
use Deducer.frink
/** This plays Wordle using the Deducer framework.
If you want to let it guess a target for you, you can just hit the "enter"
key and watch it play.
See Deducer.frink for the deducer framework. To implement this game, we
have to implement 3 interfaces from the Deducer framework:
* DeducerProblem
* DeducerRank
* DeducerMove
*/
class WordleProblem implements DeducerProblem
{
// Number of letters in the game
var numChars
// Create a new game with the specified number of letters.
new[numChars=5] :=
{
this.numChars = numChars
}
/** Rank/score a particular move with respect to target and return an object
of type WordleRank */
rank[move is WordleMove, target is WordleMove] :=
{
return new WordleRank[move, target]
}
/** Return all possible moves as an array or enumerating expression of
WordleMove appropriate for this problem. */
allPossibleMoves[] :=
{
opts = new array
for opt = select[lines["file:/home/eliasen/prog/mobydict/scrabble/sowpods.txt"], {|x, data| length[x] == data}, numChars]
opts.push[new WordleMove[opt]]
return opts
}
}
/** This represents a move for a Wordle game. */
class WordleMove implements DeducerMove
{
var word // The word as a string
var chars // The word as an array of chars
/** Construct a WordleMove for the specified word. */
new[word] :=
{
this.word = word
chars = charList[word]
}
/** Compares the goodness of this move to another move. A move is considered
"better" if it has more different letters. */
compareTo[other is WordleMove] :=
{
return length[toSet[this.chars]] <=> length[toSet[other.chars]]
}
/** Returns a string representation of the move suitable for presenting to a
human. */
toString[] := word
}
/** This implements DeducerRank to represent a rank for a Wordle move. Its
data is an array of chars like ["B", "B", "Y", "G", "G"]
*/
class WordleRank implements DeducerRank
{
var result // An array of chars like ["B", "B", "Y", "G", "G"]
/** Create a new WordleRank by determining how good a move was at matching
the specified target. */
new[move is WordleMove, target is WordleMove] :=
{
targetCopy = target.chars.shallowCopy[]
result = new array[[length[target.chars]], undef]
for i = rangeOf[move.chars]
if (move.chars)@i == (target.chars)@i
{
result@i = "G"
targetCopy.removeValue[(move.chars)@i]
}
for i = rangeOf[move.chars]
if result@i == undef
{
if targetCopy.removeValue[(move.chars)@i]
result@i = "Y"
else
result@i = "B"
}
}
/** Construct a WordleRank from a string like "BBYGG" */
new[str] :=
{
result = charList[str]
}
/** Compares this rank with another rank and returns true if they are equal.
*/
equals[other is DeducerRank] :=
{
return result == other.result
}
/** Returns a string representation of the rank for display to a human. */
toString[] :=
{
return join["", result]
}
}
/** Main play loop. */
chars = eval[input["Number of letters: ", 5]]
println["0.) Computer plays itself"]
println["1.) Human guesses computer word"]
println["2.) Computer plays outside puzzle"]
println["3.) Assistant mode"]
mode = eval[input["Mode: ", "0"]]
computerPicksWord = bitAnd[mode, 2] == 0
humanGuesses = bitAnd[mode, 1] != 0
// Play the game.
d = new Deducer[new WordleProblem[chars]]
// Pick a target play at random.
if computerPicksWord
target = random[d.movesRemaining[]]
if mode == 0
println["Computer picks: " + target.toString[]]
winCondition = repeat["G", chars]
guesses = 0
// The main loop.
do
{
if humanGuesses
move = new WordleMove[uc[trim[input["Enter guess: "]]]]
else
move = d.pickSmartMove[] // Pick a smart move.
if computerPicksWord
{
r1 = new WordleRank[move, target] // Tentative rank against target
if ! humanGuesses
result = uc[input["Rank of " + move.toString[], r1.toString[]]]
else
{
println["Rank is " + r1.toString[]]
result = r1.toString[]
}
} else
result = uc[input["Rank of " + move.toString[] + ": "]]
guesses = guesses + 1
rank = new WordleRank[result]
d.doMove[move,rank] // Eliminate options that can't match.
println["\nPossible solutions remaining: " + d.numMovesRemaining[]]
if mode == 3
{
for m1 = d.movesRemaining[]
print[m1.toString[] + " "]
println[]
}
} while rank.toString[] != winCondition and d.numMovesRemaining[] > 1
// All green? We guessed right last time!
if rank.toString[] == winCondition
println["Guessed the solution correctly in $guesses guesses!"]
else // Otherwise, we know what the solution will be.
{
if length[d.movesRemaining[]] == 0
println["No words remaining. Either the word is not in my list or I got bad feedback."]
else
println["Remaining solution is " + first[d.movesRemaining[]].toString[] + " after " + (guesses+1) + " guesses"]
}
Download or view wordleDeducer.frink in plain text format
This is a program written in the programming language Frink.
For more information, view the Frink
Documentation or see More Sample Frink Programs.
Alan Eliasen was born 20217 days, 15 hours, 7 minutes ago.