Updated Mastermind, Fibonacci.

This commit is contained in:
Jacob Signorovitch
2024-11-19 19:05:35 -05:00
parent 3b66749f41
commit 0f8c20aa73
2 changed files with 643 additions and 255 deletions

View File

@@ -36,7 +36,8 @@ class Examples {
} }
// A generic list. // A generic list.
interface ILo<A> {} interface ILo<A> {
}
class Cons<A> implements ILo<A> { class Cons<A> implements ILo<A> {
@@ -49,7 +50,8 @@ class Cons<A> implements ILo<A> {
} }
} }
class Mt<A> implements ILo<A> {} class Mt<A> implements ILo<A> {
}
interface ISequence<X> { interface ISequence<X> {
// Returns the current element in the sequence. // Returns the current element in the sequence.
@@ -78,19 +80,14 @@ class Fibonacci implements ISequence<Integer> {
public Integer get() { public Integer get() {
int ret; // What to return. int ret; // What to return.
/* /*
*
idx pen pre ret * idx pen pre ret 0 0 1 0 1 0 1 1 2 1 1 2 3 1 2 3 4 2 3 5 5 3 5 8
0 0 1 0 *
1 0 1 1
2 1 1 2
3 1 2 3
4 2 3 5
5 3 5 8
*/ */
// F(0) = 0; F(1) = 1 // F(0) = 0; F(1) = 1
if (this.idx <= 1) ret = this.idx; if (this.idx <= 1)
ret = this.idx;
else { // F(n) = F(n-1) + F(n-2) else { // F(n) = F(n-1) + F(n-2)
ret = this.pre + this.pen; ret = this.pre + this.pen;

View File

@@ -1,109 +1,83 @@
package mastermind; package mastermind;
import tester.Tester;
import java.awt.Color; import java.awt.Color;
import java.awt.Image; import java.awt.Image;
import java.util.Random; import java.util.Random;
import javalib.worldimages.*;
import javalib.funworld.*; import javalib.funworld.*;
import javalib.worldcanvas.*; import javalib.worldcanvas.*;
import javalib.worldimages.*;
import tester.Tester;
class Examples { class Examples {
ILoInt noInt = new MtInt(),
intsOne = new ConsInt(1, new ConsInt(2, new ConsInt(3, noInt)));
Dot redDot = new Dot(Color.red), ILoInt noInt = new MtInt();
greenDot = new Dot(Color.green), ILoInt intsOne = new ConsInt(1, new ConsInt(2, new ConsInt(3, noInt)));
blueDot = new Dot(Color.blue),
reenDot = new Dot(new Color(255, 255, 0));
ILoDot noDot = new MtDot(), Dot redDot = new Dot(Color.red);
dotsOne = new ConsDot(redDot, new ConsDot(greenDot, new ConsDot(blueDot, noDot)), new Random(0)), Dot greenDot = new Dot(Color.green);
dotsTwo = new ConsDot(redDot, new ConsDot(blueDot, new ConsDot(blueDot, noDot))), Dot blueDot = new Dot(Color.blue);
dotsThree = new ConsDot(reenDot, new ConsDot(reenDot, new ConsDot(reenDot, noDot))), Dot reenDot = new Dot(new Color(255, 255, 0));
exampleDotsOne = new ConsDot(redDot, new ConsDot(greenDot, new ConsDot(blueDot, new ConsDot(greenDot, new ConsDot(redDot, new ConsDot(greenDot, noDot)))))),
exampleDotsTwo = new ConsDot(redDot, new ConsDot(blueDot, new ConsDot(greenDot, new ConsDot(greenDot, new ConsDot(blueDot, new ConsDot(blueDot, noDot)))))), ILoDot noDot = new MtDot();
exampleDotsOneNoExact = new ConsDot(greenDot, new ConsDot(blueDot, new ConsDot(redDot, new ConsDot(greenDot, noDot)))), ILoDot dotsOne = new ConsDot(
exampleDotsTwoNoExact = new ConsDot(blueDot, new ConsDot(greenDot, new ConsDot(blueDot, new ConsDot(blueDot, noDot)))); redDot,
new ConsDot(greenDot, new ConsDot(blueDot, noDot)),
new Random(0)
);
ILoDot dotsTwo = new ConsDot(
redDot,
new ConsDot(blueDot, new ConsDot(blueDot, noDot))
);
ILoDot dotsThree = new ConsDot(
reenDot,
new ConsDot(reenDot, new ConsDot(reenDot, noDot))
);
ILoDot exampleDotsOne = new ConsDot(
redDot,
new ConsDot(
greenDot,
new ConsDot(
blueDot,
new ConsDot(
greenDot,
new ConsDot(redDot, new ConsDot(greenDot, noDot))
)
)
)
);
ILoDot exampleDotsTwo = new ConsDot(
redDot,
new ConsDot(
blueDot,
new ConsDot(
greenDot,
new ConsDot(
greenDot,
new ConsDot(blueDot, new ConsDot(blueDot, noDot))
)
)
)
);
ILoDot exampleDotsOneNoExact = new ConsDot(
greenDot,
new ConsDot(blueDot, new ConsDot(redDot, new ConsDot(greenDot, noDot)))
);
ILoDot exampleDotsTwoNoExact = new ConsDot(
blueDot,
new ConsDot(greenDot, new ConsDot(blueDot, new ConsDot(blueDot, noDot)))
);
Feedback exampleFeedback = new Feedback(2, 2); Feedback exampleFeedback = new Feedback(2, 2);
Game exampleGame = new Game(); Game exampleGame = new Game();
boolean testILoDotLen(Tester t) {
return t.checkExpect(noDot.len(), 0) && t.checkExpect(dotsOne.len(), 3);
}
boolean testILoDotGetnth(Tester t) {
return t.checkException(new IllegalArgumentException("Index out of bounds."), noDot, "get", 1)
&& t.checkException(new IllegalArgumentException("Index out of bounds."), dotsOne, "get", 3)
&& t.checkExpect(dotsOne.get(0), redDot)
&& t.checkExpect(dotsOne.get(2), blueDot);
}
boolean testILoDotGen(Tester t) {
return t.checkExpect(noDot.gen(219), noDot)
&& t.checkExpect(dotsOne.gen(1), new ConsDot(redDot, noDot))
&& t.checkExpect(dotsOne.gen(3), new ConsDot(greenDot, new ConsDot(greenDot, new ConsDot(blueDot, noDot))));
}
boolean testILoDotIn(Tester t) {
return t.checkExpect(dotsOne.in(blueDot), true)
&& t.checkExpect(noDot.in(redDot), false)
&& t.checkExpect(dotsThree.in(blueDot), false);
}
boolean testILoIntRemove(Tester t) {
return t.checkExpect(intsOne.remove(0), new ConsInt(2, new ConsInt(3, noInt)))
&& t.checkExpect(intsOne.remove(2), new ConsInt(1, new ConsInt(2, noInt)))
&& t.checkException(new IllegalArgumentException("Index out of bounds: cannot remove something from nothing."), intsOne, "remove", 3)
&& t.checkException(new IllegalArgumentException("Index out of bounds: cannot remove something from nothing."), noInt, "remove", 0)
&& t.checkException(new IllegalArgumentException("Indices must be positive."), intsOne, "remove", -2);
}
boolean testILoIntLen(Tester t) {
return t.checkExpect(intsOne.len(), 3) && t.checkExpect(noInt.len(), 0);
}
boolean testILoIntSubOne(Tester t) {
return t.checkExpect(intsOne.subOne(), new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt))));
}
boolean testILoDotExactIndices(Tester t) {
return t.checkException(new IllegalArgumentException("Empty list doesn't exactly match anything."), noDot, "exactIndices", noDot)
&& t.checkExpect(dotsOne.exactIndices(dotsOne), new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt))))
&& t.checkExpect(dotsOne.exactIndices(dotsTwo), new ConsInt(0, new ConsInt(2, new MtInt())));
}
boolean testILoDotRemove(Tester t) {
return t.checkException(new IllegalArgumentException("Index out of bounds."), noDot, "remove", 0)
&& t.checkExpect(dotsOne.remove(0), new ConsDot(greenDot, new ConsDot(blueDot, noDot)))
&& t.checkExpect(dotsTwo.remove(1), new ConsDot(redDot, new ConsDot(blueDot, noDot)));
}
boolean testILoDotRemoveAll(Tester t) {
return t.checkExpect(dotsOne.removeAll(noInt), dotsOne)
&& t.checkExpect(dotsOne.removeAll(new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt)))), noDot)
&& t.checkExpect(noDot.removeAll(intsOne), noDot)
&& t.checkExpect(dotsTwo.removeAll(new ConsInt(1, new ConsInt(2, noInt))), new ConsDot(redDot, noDot));
}
boolean testILoDotCountInexact(Tester t) {
return t.checkExpect(noDot.countInexact(noDot), 0)
&& t.checkExpect(dotsOne.countInexact(dotsOne), 3)
&& t.checkExpect(exampleDotsOneNoExact.countInexact(exampleDotsTwoNoExact), 2);
}
boolean testILoDotCompare(Tester t) {
return t.checkExpect(exampleDotsOne.compare(exampleDotsTwo), exampleFeedback)
&& t.checkExpect(dotsOne.compare(dotsOne), new Feedback(3, 0));
}
boolean testDrawMethods(Tester t) { boolean testDrawMethods(Tester t) {
// WorldImage incomplete = new IncompleteGuess(exampleDotsOne).draw(); // WorldImage incomplete = new IncompleteGuess(exampleDotsOne).draw();
//WorldImage guesses = new ConsGuess(new Guess(dotsOne, new Feedback(1, 2)), new ConsGuess(new Guess(dotsTwo, new Feedback(2, 5)), new MtGuess())).draw(); // WorldImage guesses = new ConsGuess(new Guess(dotsOne, new Feedback(1, 2)),
Game game = new Game().addGuess(new Guess(dotsOne, exampleFeedback)); // new ConsGuess(new Guess(dotsTwo, new Feedback(2, 5)), new MtGuess())).draw();
//Game game = new Game().addGuess(new Guess(dotsOne, exampleFeedback));
/*
WorldImage gameImg = game.draw(); WorldImage gameImg = game.draw();
int w = (int) gameImg.getWidth(); int w = (int) gameImg.getWidth();
@@ -111,25 +85,202 @@ class Examples {
WorldCanvas c = new WorldCanvas(w, h); WorldCanvas c = new WorldCanvas(w, h);
WorldScene s = new WorldScene(w, h); WorldScene s = new WorldScene(w, h);
*/
return game.launch(); return exampleGame.launch();
//c.drawScene(s.placeImageXY(gameImg, w/2, h/2)) // c.drawScene(s.placeImageXY(gameImg, w/2, h/2))
//c.drawScene(s.placeImageXY(incomplete, (int) (incomplete.getWidth()/2), 100)) // c.drawScene(s.placeImageXY(incomplete, (int) (incomplete.getWidth()/2), 100))
//c.drawScene(s.placeImageXY(exampleFeedback.draw(), 100, 100)) // c.drawScene(s.placeImageXY(exampleFeedback.draw(), 100, 100))
//c.drawScene(s.placeImageXY(redDot.draw(), 100, 100)) // c.drawScene(s.placeImageXY(redDot.draw(), 100, 100))
//c.drawScene(s.placeImageXY(dotsOne.draw(), 250, 250)) // c.drawScene(s.placeImageXY(dotsOne.draw(), 250, 250))
//&& c.show(); // && c.show();
//true; // true;
}
boolean testILoDotLen(Tester t) {
return t.checkExpect(noDot.len(), 0) && t.checkExpect(dotsOne.len(), 3);
}
boolean testILoDotGetnth(Tester t) {
return (
t.checkException(
new IllegalArgumentException("Index out of bounds."),
noDot,
"get",
1
) &&
t.checkException(
new IllegalArgumentException("Index out of bounds."),
dotsOne,
"get",
3
) &&
t.checkExpect(dotsOne.get(0), redDot) &&
t.checkExpect(dotsOne.get(2), blueDot)
);
}
boolean testILoDotGen(Tester t) {
return (
t.checkExpect(noDot.gen(219), noDot) &&
t.checkExpect(dotsOne.gen(1), new ConsDot(redDot, noDot)) &&
t.checkExpect(
dotsOne.gen(3),
new ConsDot(
greenDot,
new ConsDot(greenDot, new ConsDot(blueDot, noDot))
)
)
);
}
boolean testILoDotIn(Tester t) {
return (
t.checkExpect(dotsOne.in(blueDot), true) &&
t.checkExpect(noDot.in(redDot), false) &&
t.checkExpect(dotsThree.in(blueDot), false)
);
}
boolean testILoIntRemove(Tester t) {
return (
t.checkExpect(
intsOne.remove(0),
new ConsInt(2, new ConsInt(3, noInt))
) &&
t.checkExpect(
intsOne.remove(2),
new ConsInt(1, new ConsInt(2, noInt))
) &&
t.checkException(
new IllegalArgumentException(
"Index out of bounds: cannot remove something from nothing."
),
intsOne,
"remove",
3
) &&
t.checkException(
new IllegalArgumentException(
"Index out of bounds: cannot remove something from nothing."
),
noInt,
"remove",
0
) &&
t.checkException(
new IllegalArgumentException("Indices must be positive."),
intsOne,
"remove",
-2
)
);
}
boolean testILoIntLen(Tester t) {
return t.checkExpect(intsOne.len(), 3) && t.checkExpect(noInt.len(), 0);
}
boolean testILoIntSubOne(Tester t) {
return t.checkExpect(
intsOne.subOne(),
new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt)))
);
}
boolean testILoDotExactIndices(Tester t) {
return (
t.checkException(
new IllegalArgumentException(
"Empty list doesn't exactly match anything."
),
noDot,
"exactIndices",
noDot
) &&
t.checkExpect(
dotsOne.exactIndices(dotsOne),
new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt)))
) &&
t.checkExpect(
dotsOne.exactIndices(dotsTwo),
new ConsInt(0, new ConsInt(2, new MtInt()))
)
);
}
boolean testILoDotRemove(Tester t) {
return (
t.checkException(
new IllegalArgumentException("Index out of bounds."),
noDot,
"remove",
0
) &&
t.checkExpect(
dotsOne.remove(0),
new ConsDot(greenDot, new ConsDot(blueDot, noDot))
) &&
t.checkExpect(
dotsTwo.remove(1),
new ConsDot(redDot, new ConsDot(blueDot, noDot))
)
);
}
boolean testILoDotRemoveAll(Tester t) {
return (
t.checkExpect(dotsOne.removeAll(noInt), dotsOne) &&
t.checkExpect(
dotsOne.removeAll(
new ConsInt(0, new ConsInt(1, new ConsInt(2, noInt)))
),
noDot
) &&
t.checkExpect(noDot.removeAll(intsOne), noDot) &&
t.checkExpect(
dotsTwo.removeAll(new ConsInt(1, new ConsInt(2, noInt))),
new ConsDot(redDot, noDot)
)
);
}
boolean testILoDotCountInexact(Tester t) {
return (
t.checkExpect(noDot.countInexact(noDot), 0) &&
t.checkExpect(dotsOne.countInexact(dotsOne), 3) &&
t.checkExpect(
exampleDotsOneNoExact.countInexact(exampleDotsTwoNoExact),
2
)
);
}
boolean testILoDotCompare(Tester t) {
return (
t.checkExpect(
exampleDotsOne.compare(exampleDotsTwo),
exampleFeedback
) &&
t.checkExpect(dotsOne.compare(dotsOne), new Feedback(3, 0))
);
} }
} }
class Util { class Util {
static int scale = 2; static int scale = 2;
static int fontSz = 24 * scale; static int fontSz = 24 * scale;
static int gapW = 4 * scale; // The gap between objects. static int gapW = 4 * scale; // The gap between objects.
// Drawing methods. // Drawing methods.
static WorldImage gap = new RectangleImage(gapW, gapW, "outline", new Color(0, 0, 0, 0)); static WorldImage gap = new RectangleImage(
gapW,
gapW,
"outline",
new Color(0, 0, 0, 0)
);
static WorldImage pairGap(WorldImage img1, WorldImage img2) { static WorldImage pairGap(WorldImage img1, WorldImage img2) {
return new BesideAlignImage(AlignModeY.MIDDLE, img1, gap, img2); return new BesideAlignImage(AlignModeY.MIDDLE, img1, gap, img2);
} }
@@ -139,7 +290,10 @@ class Util {
} }
static WorldImage strPair(String str1, String str2) { static WorldImage strPair(String str1, String str2) {
return pairGap(new TextImage(str1, fontSz, Color.black), new TextImage(str2, fontSz, Color.black)); return pairGap(
new TextImage(str1, fontSz, Color.black),
new TextImage(str2, fontSz, Color.black)
);
} }
static int pairgapW = 2 * 16 * scale + gapW; static int pairgapW = 2 * 16 * scale + gapW;
@@ -147,7 +301,14 @@ class Util {
// A game state. // A game state.
class Game extends World { class Game extends World {
static ILoDot DEFAULTDOTS = new ConsDot(new Dot(Color.RED), new ConsDot(new Dot(Color.GREEN), new ConsDot(new Dot(Color.BLUE), new MtDot())));
static ILoDot DEFAULTDOTS = new ConsDot(
new Dot(Color.RED),
new ConsDot(
new Dot(Color.GREEN),
new ConsDot(new Dot(Color.BLUE), new MtDot())
)
);
static GameConf DEFAULTCONF = new GameConf(true, 5, 5, DEFAULTDOTS); static GameConf DEFAULTCONF = new GameConf(true, 5, 5, DEFAULTDOTS);
GameConf conf; // The game's configuration. GameConf conf; // The game's configuration.
@@ -157,8 +318,17 @@ class Game extends World {
boolean done; // Is the game over? boolean done; // Is the game over?
boolean won; // Did they player win? boolean won; // Did they player win?
Game(GameConf conf, ILoDot solution, int guessesLeft, ILoGuess guesses, boolean won, boolean done) { Game(
if (this.won && !this.done) throw new IllegalArgumentException("Can't win before you've finished playing."); GameConf conf,
ILoDot solution,
int guessesLeft,
ILoGuess guesses,
boolean won,
boolean done
) {
if (this.won && !this.done) throw new IllegalArgumentException(
"Can't win before you've finished playing."
);
this.conf = conf; this.conf = conf;
this.solution = solution; this.solution = solution;
this.won = won; this.won = won;
@@ -168,21 +338,51 @@ class Game extends World {
} }
// Convenience constructor using default config and starting values. // Convenience constructor using default config and starting values.
Game() { this(DEFAULTCONF, DEFAULTCONF.options.gen(DEFAULTCONF.len), DEFAULTCONF.nguesses, new MtGuess(), false, false); } Game() {
this(
DEFAULTCONF,
DEFAULTCONF.options.gen(DEFAULTCONF.len),
DEFAULTCONF.nguesses,
new MtGuess(),
false,
false
);
}
public WorldScene makeScene() { public WorldScene makeScene() {
WorldScene bg = this.getEmptyScene(); WorldImage img = this.draw();
WorldImage dot = new Dot(Color.RED).draw(); int w = (int) img.getWidth(), h = (int) img.getHeight();
return bg.placeImageXY(dot , (int)dot.getWidth(), (int)dot.getHeight()); WorldScene bg = new WorldScene(w, h);
return bg.placeImageXY(img, (int) w / 2, (int) h / 2);
} }
boolean launch() { boolean launch() {
return this.bigBang(100, 100); return this.bigBang(this.calcW(), this.calcH());
}
// Calculate the width of the window without drawing anything.
int calcW() {
return (
(this.conf.len * Dot.r * 2) + // The width of all the dots.
((this.conf.len + 1) * Util.gapW) + // The width of all the spaces between the dots.
Util.fontSz * 2 + // The width of the feedback numbers.
Util.gapW // The width of the gap between the feedback numbers.
);
}
// Calculate the height of the window without drawing anything.
int calcH() {
return ((this.conf.nguesses + 2) * Dot.r * 2); // Width of all the guess rows, plus the two rows above and below (for solution and options respectively.)
} }
// Draw the current game state. // Draw the current game state.
WorldImage draw() { WorldImage draw() {
return new AboveAlignImage(AlignModeX.LEFT, this.draw_sol(), this.draw_guesses(), this.draw_options()); return new AboveAlignImage(
AlignModeX.LEFT,
this.draw_sol(),
this.draw_guesses(),
this.draw_options()
);
} }
// Draw the solution. // Draw the solution.
@@ -198,7 +398,12 @@ class Game extends World {
// Draw the hidden answer. // Draw the hidden answer.
WorldImage draw_sol_hid() { WorldImage draw_sol_hid() {
return new RectangleImage(this.solution.getW(), 2*Dot.r, OutlineMode.SOLID, Color.BLACK); return new RectangleImage(
this.solution.getW(),
2 * Dot.r,
OutlineMode.SOLID,
Color.BLACK
);
} }
WorldImage draw_guesses() { WorldImage draw_guesses() {
@@ -210,27 +415,51 @@ class Game extends World {
} }
// Convenience methods for testing -- not part of program. // Convenience methods for testing -- not part of program.
Game win() { return new Game(this.conf, this.solution, this.guessesLeft, this.guesses, true, true); } Game win() {
Game addGuess(Guess guess) { return new Game(this.conf, this.solution, this.guessesLeft, new ConsGuess(guess, this.guesses), this.won, this.done); } return new Game(
this.conf,
this.solution,
this.guessesLeft,
this.guesses,
true,
true
);
}
Game addGuess(Guess guess) {
return new Game(
this.conf,
this.solution,
this.guessesLeft,
new ConsGuess(guess, this.guesses),
this.won,
this.done
);
}
} }
// A game configuration. // A game configuration.
class GameConf { class GameConf {
boolean dups; // Whether duplicates are allowed. boolean dups; // Whether duplicates are allowed.
int len; // The length of the sequence to be guessed. int len; // The length of the sequence to be guessed.
int nguesses; // Number of guesses the player is allowed. int nguesses; // Number of guesses the player is allowed.
ILoDot options; // The dots of which the solution is comprised. ILoDot options; // The dots of which the solution is comprised.
GameConf(boolean dups, int len, int nguesses, ILoDot options) { GameConf(boolean dups, int len, int nguesses, ILoDot options) {
if (len <= 0) if (len <= 0) throw new IllegalArgumentException(
throw new IllegalArgumentException("Length of the solution must be greater than 0."); "Length of the solution must be greater than 0."
if (nguesses <= 0) );
throw new IllegalArgumentException("Must provide the player some guesses."); if (nguesses <= 0) throw new IllegalArgumentException(
"Must provide the player some guesses."
);
int oplen = options.len(); int oplen = options.len();
if (oplen <= 0) if (oplen <= 0) throw new IllegalArgumentException(
throw new IllegalArgumentException("Must have dot options to guess with."); "Must have dot options to guess with."
if (!dups && len > oplen) );
throw new IllegalArgumentException("Cant create solution of that length without duplicates."); if (!dups && len > oplen) throw new IllegalArgumentException(
"Cant create solution of that length without duplicates."
);
this.dups = dups; this.dups = dups;
this.len = len; this.len = len;
@@ -245,6 +474,7 @@ interface ILoGuess {
} }
class ConsGuess implements ILoGuess { class ConsGuess implements ILoGuess {
Guess guess; Guess guess;
ILoGuess nxt; ILoGuess nxt;
@@ -259,12 +489,15 @@ class ConsGuess implements ILoGuess {
} }
class MtGuess implements ILoGuess { class MtGuess implements ILoGuess {
public WorldImage draw() { public WorldImage draw() {
return new EmptyImage(); return new EmptyImage();
} }
} }
// A guess.
class Guess { class Guess {
ILoDot guess; // The dots the user entered. ILoDot guess; // The dots the user entered.
Feedback feedback; // The feedback returned. Feedback feedback; // The feedback returned.
@@ -278,7 +511,9 @@ class Guess {
} }
} }
// A guess in the midst of being entered.
class IncompleteGuess { class IncompleteGuess {
ILoDot guessSoFar; ILoDot guessSoFar;
IncompleteGuess(ILoDot guessSoFar) { IncompleteGuess(ILoDot guessSoFar) {
@@ -290,9 +525,10 @@ class IncompleteGuess {
} }
} }
// Feedback for a guess.
class Feedback { class Feedback {
int exact,
inexact; int exact, inexact;
Feedback(int exact, int inexact) { Feedback(int exact, int inexact) {
this.exact = exact; this.exact = exact;
@@ -300,38 +536,56 @@ class Feedback {
} }
Feedback add(Feedback other) { Feedback add(Feedback other) {
int otherExact = other.exact, int otherExact = other.exact, otherInexact = other.inexact;
otherInexact = other.inexact;
return new Feedback(this.exact + otherExact, this.inexact + otherInexact); return new Feedback(
this.exact + otherExact,
this.inexact + otherInexact
);
} }
WorldImage draw() { WorldImage draw() {
return Util.strPair(String.valueOf(this.exact), String.valueOf(this.exact)); return Util.strPair(
String.valueOf(this.exact),
String.valueOf(this.exact)
);
} }
} }
// A list of dots.
interface ILoDot { interface ILoDot {
int len(); // Get length. int len(); // Get length.
Dot get(int n); // Get nth element. Dot get(int n); // Get nth element.
ILoDot remove(int n); // Remove nth element. ILoDot remove(int n); // Remove nth element.
ILoDot removeAll(ILoInt indices); // Remove element at each index. ILoDot removeAll(ILoInt indices); // Remove element at each index.
ILoDot gen(int n); // Generate randomized list. ILoDot gen(int n); // Generate randomized list.
boolean match(Color col); // Do the colors match? boolean match(Color col); // Do the colors match?
boolean in(Dot dot); // Is the dot in here? boolean in(Dot dot); // Is the dot in here?
Feedback compare(ILoDot other); // Compare two lists & give feedback. Feedback compare(ILoDot other); // Compare two lists & give feedback.
ILoInt exactIndices(ILoDot other); // Get indices of exact matches. ILoInt exactIndices(ILoDot other); // Get indices of exact matches.
ILoInt exactIndicesHelper(ILoDot other, int i); ILoInt exactIndicesHelper(ILoDot other, int i);
int countInexact(ILoDot other); // Get the number of inexact matches. Must be fed exact match-free lists to be accurate.
int countInexact(ILoDot other); // Get the number of inexact matches. Must be fed exact match-free lists to be
// accurate.
int countInexactHelper(ILoDot other, ILoDot seen); int countInexactHelper(ILoDot other, ILoDot seen);
WorldImage draw(); // Draw the dots. WorldImage draw(); // Draw the dots.
int getW(); // Get the total width, in pixels, of the list. int getW(); // Get the total width, in pixels, of the list.
} }
class ConsDot implements ILoDot { class ConsDot implements ILoDot {
Random rand; Random rand;
Dot dot; Dot dot;
ILoDot nxt; ILoDot nxt;
@@ -341,24 +595,54 @@ class ConsDot implements ILoDot {
this.dot = dot; this.dot = dot;
this.nxt = nxt; this.nxt = nxt;
} }
ConsDot(Dot dot, ILoDot nxt) { this(dot, nxt, new Random()); }
ConsDot(Dot dot, ILoDot nxt) {
this(dot, nxt, new Random());
}
public ILoDot gen(int n) { public ILoDot gen(int n) {
return n <= 0 ? new MtDot() : new ConsDot(this.get(this.rand.nextInt(this.len())), this.gen(n - 1)); return n <= 0
? new MtDot()
: new ConsDot(
this.get(this.rand.nextInt(this.len())),
this.gen(n - 1)
);
} }
public Dot get(int n) { public Dot get(int n) {
if (n == 0) return this.dot; if (n == 0) return this.dot;
else return this.nxt.get(n - 1); else return this.nxt.get(n - 1);
} }
public boolean in(Dot dot) { return dot.equals(this.dot) || this.nxt.in(dot); }
public int len() { return 1 + this.nxt.len(); }
public boolean match(Color col) { return col.equals(this.dot.c); }
public WorldImage draw() { return new BesideAlignImage(AlignModeY.PINHOLE, this.dot.draw(), Util.gap, this.nxt.draw()); } public boolean in(Dot dot) {
public int getW() { return this.len() * Dot.r * 2; } return dot.equals(this.dot) || this.nxt.in(dot);
}
public int len() {
return 1 + this.nxt.len();
}
public boolean match(Color col) {
return col.equals(this.dot.c);
}
public WorldImage draw() {
return new BesideAlignImage(
AlignModeY.PINHOLE,
this.dot.draw(),
Util.gap,
this.nxt.draw()
);
}
public int getW() {
return this.len() * Dot.r * 2;
}
public Feedback compare(ILoDot other) { public Feedback compare(ILoDot other) {
if (this.len() != other.len()) throw new IllegalArgumentException("Cannot compare different lengthed lists."); if (this.len() != other.len()) throw new IllegalArgumentException(
"Cannot compare different lengthed lists."
);
ILoInt exactIndices = this.exactIndices(other); ILoInt exactIndices = this.exactIndices(other);
@@ -371,14 +655,16 @@ class ConsDot implements ILoDot {
return new Feedback(exact, inexact); return new Feedback(exact, inexact);
} }
public ILoInt exactIndices(ILoDot other) { return this.exactIndicesHelper(other, 0); } public ILoInt exactIndices(ILoDot other) {
return this.exactIndicesHelper(other, 0);
}
public ILoInt exactIndicesHelper(ILoDot other, int i) { public ILoInt exactIndicesHelper(ILoDot other, int i) {
// Stop after reaching the end of the list. // Stop after reaching the end of the list.
if (i == this.len()) return new MtInt(); if (i == this.len()) return new MtInt();
return this.get(i).equals(other.get(i)) ? return this.get(i).equals(other.get(i))
new ConsInt(i, this.exactIndicesHelper(other, i + 1)) ? new ConsInt(i, this.exactIndicesHelper(other, i + 1))
: this.exactIndicesHelper(other, i + 1); : this.exactIndicesHelper(other, i + 1);
} }
@@ -388,14 +674,22 @@ class ConsDot implements ILoDot {
public int countInexactHelper(ILoDot other, ILoDot seen) { public int countInexactHelper(ILoDot other, ILoDot seen) {
if (seen.in(this.dot)) { if (seen.in(this.dot)) {
return this.nxt.countInexactHelper(other, new ConsDot(this.dot, seen)); return this.nxt.countInexactHelper(
other,
new ConsDot(this.dot, seen)
);
} }
return (other.in(this.dot) ? 1 : 0) + this.nxt.countInexactHelper(other, new ConsDot(this.dot, seen)); return (
(other.in(this.dot) ? 1 : 0) +
this.nxt.countInexactHelper(other, new ConsDot(this.dot, seen))
);
} }
public ILoDot remove(int n) { public ILoDot remove(int n) {
if (n < 0) throw new IllegalArgumentException("Indices must be positive."); if (n < 0) throw new IllegalArgumentException(
"Indices must be positive."
);
if (n == 0) return this.nxt; if (n == 0) return this.nxt;
else return new ConsDot(this.dot, this.nxt.remove(n - 1)); else return new ConsDot(this.dot, this.nxt.remove(n - 1));
@@ -408,50 +702,106 @@ class ConsDot implements ILoDot {
} }
class MtDot implements ILoDot { class MtDot implements ILoDot {
public ILoDot gen(int n) { return new MtDot(); }
public Dot get(int n) { throw new IllegalArgumentException("Index out of bounds."); } public ILoDot gen(int n) {
public int len() { return 0; } return new MtDot();
public WorldImage draw() { return new EmptyImage(); } }
public int getW() { return 0; }
public Feedback compare(ILoDot other) { return new Feedback(0, 0); } public Dot get(int n) {
public boolean match(Color col) { return false; } throw new IllegalArgumentException("Index out of bounds.");
public boolean in(Dot dot) { return false; } }
public ILoInt exactIndices(ILoDot other) {
throw new IllegalArgumentException("Empty list doesn't exactly match anything."); public int len() {
return 0;
}
public WorldImage draw() {
return new EmptyImage();
}
public int getW() {
return 0;
}
public Feedback compare(ILoDot other) {
return new Feedback(0, 0);
}
public boolean match(Color col) {
return false;
}
public boolean in(Dot dot) {
return false;
}
public ILoInt exactIndices(ILoDot other) {
throw new IllegalArgumentException(
"Empty list doesn't exactly match anything."
);
}
public ILoInt exactIndicesHelper(ILoDot other, int i) {
return new MtInt();
}
public int countInexact(ILoDot other) {
return 0;
}
public int countInexactHelper(ILoDot other, ILoDot seen) {
return 0;
}
public ILoDot remove(int n) {
throw new IllegalArgumentException("Index out of bounds.");
}
public ILoDot removeAll(ILoInt indices) {
return this;
} }
public ILoInt exactIndicesHelper(ILoDot other, int i) { return new MtInt(); }
public int countInexact(ILoDot other) { return 0; }
public int countInexactHelper(ILoDot other, ILoDot seen) { return 0; }
public ILoDot remove(int n) { throw new IllegalArgumentException("Index out of bounds."); }
public ILoDot removeAll(ILoInt indices) { return this; }
} }
// A dot.
class Dot { class Dot {
static int r = 16 * Util.scale; static int r = 16 * Util.scale;
static OutlineMode outlineMode = OutlineMode.SOLID; static OutlineMode outlineMode = OutlineMode.SOLID;
Color c; Color c;
Dot(Color c) { this.c = c; } Dot(Color c) {
this.c = c;
}
// Draw the dot. // Draw the dot.
WorldImage draw() { return new CircleImage(r, outlineMode, this.c); } WorldImage draw() {
return new CircleImage(r, outlineMode, this.c);
}
// Get the width of the dot. // Get the width of the dot.
int getW() { return 2 * r; } int getW() {
return 2 * r;
}
} }
// A list of integers. // A list of integers.
interface ILoInt { interface ILoInt {
int len(); // Get the length of the list. int len(); // Get the length of the list.
ILoInt remove(int n); // Remove the nth element of the list. ILoInt remove(int n); // Remove the nth element of the list.
boolean isEmpty(); // Is it empty? boolean isEmpty(); // Is it empty?
int first(); // Get the first value. int first(); // Get the first value.
ILoInt rest(); // Get the rest value. ILoInt rest(); // Get the rest value.
ILoInt subOne(); // Subtract 1 from every int. ILoInt subOne(); // Subtract 1 from every int.
} }
class ConsInt implements ILoInt { class ConsInt implements ILoInt {
int val; int val;
ILoInt nxt; ILoInt nxt;
@@ -460,22 +810,63 @@ class ConsInt implements ILoInt {
this.nxt = nxt; this.nxt = nxt;
} }
public int len() { return 1 + this.nxt.len(); } public int len() {
public ILoInt remove(int n) { return 1 + this.nxt.len();
if (n < 0) throw new IllegalArgumentException("Indices must be positive."); }
return n == 0 ? this.nxt : new ConsInt(this.val, this.nxt.remove(n - 1));
public ILoInt remove(int n) {
if (n < 0) throw new IllegalArgumentException(
"Indices must be positive."
);
return n == 0
? this.nxt
: new ConsInt(this.val, this.nxt.remove(n - 1));
}
public boolean isEmpty() {
return false;
}
public int first() {
return this.val;
}
public ILoInt rest() {
return this.nxt;
}
public ILoInt subOne() {
return new ConsInt(this.val - 1, this.nxt.subOne());
} }
public boolean isEmpty() { return false; }
public int first() { return this.val; }
public ILoInt rest() { return this.nxt; }
public ILoInt subOne() { return new ConsInt(this.val - 1, this.nxt.subOne()); }
} }
class MtInt implements ILoInt { class MtInt implements ILoInt {
public int len() { return 0; }
public ILoInt remove(int n) { throw new IllegalArgumentException("Index out of bounds: cannot remove something from nothing."); } public int len() {
public boolean isEmpty() { return true; } return 0;
public int first() { throw new IllegalArgumentException("Cannot get first element in a list without any."); } }
public ILoInt rest() { throw new IllegalArgumentException("Cannot get rest of empty list."); }
public ILoInt subOne() { return this; } public ILoInt remove(int n) {
throw new IllegalArgumentException(
"Index out of bounds: cannot remove something from nothing."
);
}
public boolean isEmpty() {
return true;
}
public int first() {
throw new IllegalArgumentException(
"Cannot get first element in a list without any."
);
}
public ILoInt rest() {
throw new IllegalArgumentException("Cannot get rest of empty list.");
}
public ILoInt subOne() {
return this;
}
} }