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 19981 days, 11 hours, 40 minutes ago.