Download or view mastermindDeducer.frink in plain text format
use Deducer.frink
/** This is an implementation of the Mastermind game using the Deducer class.
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
For an example that doesn't use the Deducer framework, see mastermind.frink
*/
class MastermindProblem implements DeducerProblem
{
/* The possible colors. You can change these to whatever you want, including
full names. You can also use more or fewer colors and everything will
just work right. */
class var colors=["G","B","Y","P","O","R"]
// You can change from the normal 4-peg game to more or fewer pegs.
class var numPegs = 4
/** Rank/score a how a particular move would score against a target and
return an object of type DeducerRank */
rank[move is MastermindMove, target is MastermindMove] :=
{
return new MastermindRank[move, target]
}
/** Return all possible moves as an array or enumerating expression of
DeducerMove appropriate for this problem. In this case, returned values
are of type MastermindMove which implements DeducerMove.
*/
allPossibleMoves[] :=
{
// Create an array with all possible plays.
opts = new array
multifor x = makeArray[[numPegs], colors]
opts.push[new MastermindMove[x]]
return opts
}
}
/** The DeducerRank interface describes the methods for ranking a particular
move. For example, a Mastermind ranking would include the count of black
and white pegs. For Wordle, this would indicate which letters are green,
which are yellow, and which are black. */
class MastermindRank implements DeducerRank
{
var black
var white
/** Construct a rank from a [black, white] array. */
new[blackWhiteArray] :=
{
if isArray[blackWhiteArray] and length[blackWhiteArray] == 2
[black, white] = blackWhiteArray
else
println["MastermindRank.new: Invalid black-white array: $blackWhiteArray"]
}
/** Construct a rank by evaluating the move against the target. */
new[move is MastermindMove, target is MastermindMove] :=
{
black = 0
white = 0
targetCopy = target.vals.shallowCopy[]
// First, count total number of matches in any position. As a match is
// found in any position, remove it from the list so it's not counted
// twice.
for mpiece = move.vals
if targetCopy.removeValue[mpiece] // true if a piece was removed
white = white + 1
// Now count pieces in the correct positions. For each one found, remove
// one from the "white" count and add one to the "black" count.
for i = 0 to length[target.vals]-1
if move.vals@i == target.vals@i
{
white = white - 1
black = black + 1
}
}
/** Compares this rank with another rank and returns true if they are equal.
*/
equals[other is DeducerRank] :=
{
return this.black == other.black and this.white == other.white
}
/** Returns a string representation of the rank for display to a human. */
toString[] := "Black:$black White:$white"
}
/** This represents a move for Mastermind. The values are stored in the array
vals. These will have the same values as MastermindProblem.colors. */
class MastermindMove implements DeducerMove
{
/** The array of values */
var vals
new[vals] :=
{
if isString[vals] // Parse single-char names from a string badly
this.vals = charList[vals]
else
this.vals = vals
}
/** Returns a string representation of the move suitable for presenting to a
human. */
toString[] := toString[vals]
}
// Play the game.
d = new Deducer[new MastermindProblem]
// Pick a target play at random.
target = random[d.movesRemaining[]]
println["Suggest: " + target.toString[]]
// The main loop.
do
{
println["Possible solutions remaining: " + d.numMovesRemaining[]]
move = d.movesRemaining[].removeRandom[] // Choose a move at random
r1 = new MastermindRank[move, target] // Tentative rank against target
result = eval[input["Move is " + move.toString[],
[["Black: ", r1.black], ["White: ", r1.white]]]]
rank = new MastermindRank[result]
d.doMove[move,rank] // Eliminate options that can't match.
} while result@0 != MastermindProblem.numPegs and d.numMovesRemaining[] > 1
// All black? We guessed right last time!
if result@0 == MastermindProblem.numPegs
println["Guessed the solution correctly!"]
else // Otherwise, we know what the solution will be.
println["Solution is " + first[d.movesRemaining[]].toString[]]
Download or view mastermindDeducer.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 20139 days, 8 hours, 8 minutes ago.