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]
}
/** 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.movesRemaining[].removeRandom[] // Choose a move at random
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 20152 days, 19 hours, 29 minutes ago.