diff --git a/mastermind/.classpath b/mastermind/.classpath
new file mode 100644
index 0000000..e834eb8
--- /dev/null
+++ b/mastermind/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mastermind/.project b/mastermind/.project
new file mode 100644
index 0000000..7ba2a68
--- /dev/null
+++ b/mastermind/.project
@@ -0,0 +1,17 @@
+
+
+ mastermind
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/mastermind/.settings/org.eclipse.core.resources.prefs b/mastermind/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/mastermind/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/mastermind/.settings/org.eclipse.jdt.core.prefs b/mastermind/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..9a7984b
--- /dev/null
+++ b/mastermind/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/mastermind/src/mastermind/One.java b/mastermind/src/mastermind/One.java
new file mode 100644
index 0000000..ba9011c
--- /dev/null
+++ b/mastermind/src/mastermind/One.java
@@ -0,0 +1,348 @@
+package mastermind;
+
+import tester.Tester;
+import java.awt.Color;
+import java.awt.Image;
+import java.util.Random;
+import javalib.worldimages.*;
+import javalib.funworld.*;
+import javalib.worldcanvas.*;
+
+class Examples {
+ ILoInt noInt = new MtInt(),
+ intsOne = new ConsInt(1, new ConsInt(2, new ConsInt(3, noInt)));
+
+ Dot redDot = new Dot(Color.red),
+ greenDot = new Dot(Color.green),
+ blueDot = new Dot(Color.blue),
+ reenDot = new Dot(new Color(255, 255, 0));
+
+ ILoDot noDot = new MtDot(),
+ dotsOne = new ConsDot(redDot, new ConsDot(greenDot, new ConsDot(blueDot, noDot)), new Random(0)),
+ dotsTwo = new ConsDot(redDot, new ConsDot(blueDot, new ConsDot(blueDot, noDot))),
+ dotsThree = new ConsDot(reenDot, new ConsDot(reenDot, new ConsDot(reenDot, noDot))),
+ 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))))));
+
+ 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 true; }
+
+ /*
+ boolean testILoDotCompare(Tester t) {
+ return t.checkExpect(exampleDotsOne.compare(exampleDotsTwo), new Feedback(2, 2));
+ }*/
+
+ boolean testDrawMethods(Tester t) {
+ WorldCanvas c = new WorldCanvas(1000, 1000);
+ WorldScene s = new WorldScene(1000, 1000);
+ return
+ // c.drawScene(s.placeImageXY(exampleGame.draw(), 0, 0))
+ //c.drawScene(s.placeImageXY(redDot.draw(), 100, 100))
+ //c.drawScene(s.placeImageXY(dotsOne.draw(), 250, 250))
+ //&& c.show();
+ true;
+ }
+}
+
+// A game state.
+class Game {
+ 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);
+
+ GameConf conf;
+ int guessesLeft;
+ ILoGuess guesses;
+
+ Game(GameConf conf, int guessesLeft, ILoGuess guesses) {
+ this.conf = conf;
+ this.guessesLeft = guessesLeft;
+ this.guesses = guesses;
+ }
+
+ // Convenience constructor using default config.
+ Game() { this(DEFAULTCONF, DEFAULTCONF.nguesses, new MtGuess()); }
+
+ WorldImage draw() {
+ return new EmptyImage();
+ }
+}
+
+// A game configuration.
+class GameConf {
+ boolean dups; // Whether duplicates are allowed.
+ int len; // The length of the sequence to be guessed.
+ int nguesses; // Number of guesses the player is allowed.
+ ILoDot options; // The dots of which the solution is comprised.
+
+ GameConf(boolean dups, int len, int nguesses, ILoDot options) {
+ if (len <= 0)
+ throw new IllegalArgumentException("Length of the solution must be greater than 0.");
+ if (nguesses <= 0)
+ throw new IllegalArgumentException("Must provide the player some guesses.");
+ int oplen = options.len();
+ if (oplen <= 0)
+ throw new IllegalArgumentException("Must have dot options to guess with.");
+ if (!dups && len > oplen)
+ throw new IllegalArgumentException("Cant create solution of that length without duplicates.");
+
+ this.dups = dups;
+ this.len = len;
+ this.nguesses = nguesses;
+ this.options = options;
+ }
+}
+
+// A list of guesses;
+interface ILoGuess {}
+
+class ConsGuess implements ILoGuess {
+ Guess guess;
+ ILoGuess nxt;
+
+ ConsGuess(Guess guess, ILoGuess nxt) {
+ this.guess = guess;
+ this.nxt = nxt;
+ }
+}
+
+class MtGuess implements ILoGuess {}
+
+class Guess {
+ ILoDot guess;
+ Feedback feedback;
+
+ Guess(ILoDot guess, Feedback feedback) {
+ this.guess = guess;
+ this.feedback = feedback;
+ }
+}
+
+class Feedback {
+ int exact,
+ inexact;
+
+ Feedback(int exact, int inexact) {
+ this.exact = exact;
+ this.inexact = inexact;
+ }
+
+ Feedback add(Feedback other) {
+ int otherExact = other.exact,
+ otherInexact = other.inexact;
+
+ return new Feedback(this.exact + otherExact, this.inexact + otherInexact);
+ }
+}
+
+interface ILoDot {
+ int len(); // Get length.
+ Dot get(int n); // Get nth element.
+ ILoDot remove(int n); // Remove nth element.
+ ILoDot removeAll(ILoInt indices); // Remove element at each index.
+ ILoDot gen(int n); // Generate randomized list.
+
+ boolean match(Color col); // Do the colors match?
+ boolean in(Dot dot); // Is the dot in here?
+
+ Feedback compare(ILoDot other); // Compare two lists & give feedback.
+ ILoInt exactIndices(ILoDot other); // Get indices of exact matches.
+ 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.
+
+ WorldImage draw(); // Draw the dots.
+}
+
+class ConsDot implements ILoDot {
+ Random rand;
+ Dot dot;
+ ILoDot nxt;
+
+ ConsDot(Dot dot, ILoDot nxt, Random rand) {
+ this.rand = rand;
+ this.dot = dot;
+ this.nxt = nxt;
+ }
+ ConsDot(Dot dot, ILoDot nxt) { this(dot, nxt, new Random()); }
+
+ public ILoDot gen(int n) {
+ return n <= 0 ? new MtDot() : new ConsDot(this.get(this.rand.nextInt(this.len())), this.gen(n - 1));
+ }
+ public Dot get(int n) {
+ if (n == 0) return this.dot;
+ 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(), this.nxt.draw()); }
+
+ public Feedback compare(ILoDot other) {
+ if (this.len() != other.len()) throw new IllegalArgumentException("Cannot compare different lengthed lists.");
+
+ ILoInt exactIndices = this.exactIndices(other);
+
+ ILoDot thisWithoutExact = this.removeAll(exactIndices);
+ ILoDot otherWithoutExact = other.removeAll(exactIndices);
+
+ int exact = exactIndices.len();
+ int inexact = thisWithoutExact.countInexact(otherWithoutExact);
+
+ return new Feedback(exact, inexact);
+ }
+
+ public ILoInt exactIndices(ILoDot other) { return this.exactIndicesHelper(other, 0); }
+
+ public ILoInt exactIndicesHelper(ILoDot other, int i) {
+ // Stop after reaching the end of the list.
+ if (i == this.len()) return new MtInt();
+
+ return this.get(i).equals(other.get(i)) ? new ConsInt(i, this.exactIndicesHelper(other, i + 1))
+ : this.exactIndicesHelper(other, i + 1);
+ }
+
+ public int countInexact(ILoDot other) {
+ return 0;
+ }
+
+ public ILoDot remove(int n) {
+ if (n < 0) throw new IllegalArgumentException("Indices must be positive.");
+
+ if (n == 0) return this.nxt;
+ else return new ConsDot(this.dot, this.nxt.remove(n - 1));
+ }
+
+ public ILoDot removeAll(ILoInt indices) {
+ if (indices.isEmpty()) return this;
+ return this.remove(indices.first()).removeAll(indices.rest().subOne());
+ }
+}
+
+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 int len() { return 0; }
+ public WorldImage draw() { return new EmptyImage(); }
+ 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 ILoDot remove(int n) { throw new IllegalArgumentException("Index out of bounds."); }
+ public ILoDot removeAll(ILoInt indices) { return this; }
+}
+
+class Dot {
+ static int r = 32;
+ static OutlineMode outlineMode = OutlineMode.SOLID;
+
+ Color c;
+
+ Dot(Color c) { this.c = c; }
+
+ // Draw the dot.
+ WorldImage draw() { return new CircleImage(r, outlineMode, this.c); }
+}
+
+// A list of integers.
+interface ILoInt {
+ int len(); // Get the length of the list.
+ ILoInt remove(int n); // Remove the nth element of the list.
+ boolean isEmpty(); // Is it empty?
+ int first(); // Get the first value.
+ ILoInt rest(); // Get the rest value.
+ ILoInt subOne(); // Subtract 1 from every int.
+}
+
+class ConsInt implements ILoInt {
+ int val;
+ ILoInt nxt;
+
+ ConsInt(int val, ILoInt nxt) {
+ this.val = val;
+ this.nxt = nxt;
+ }
+
+ public int len() { return 1 + this.nxt.len(); }
+ 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()); }
+}
+
+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 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; }
+}