diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 7679cf52fab5030c48f7172ea8a82b57cf84b419..e2f56d778a657b089c5bc61a3b1b1ac50b18042c 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -10,20 +10,14 @@
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -73,6 +67,9 @@
+
+
+
@@ -97,7 +94,7 @@
-
+ 1580084914114
@@ -120,7 +117,23 @@
1580097683638
-
+
+
+ 1706048258917
+
+
+
+ 1706048258917
+
+
+
+ 1706048316975
+
+
+
+ 1706048316975
+
+
@@ -130,6 +143,23 @@
-
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/sge.java
+ 643
+
+
+
+ file://$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/sge.java
+ 167
+
+
+
+
\ No newline at end of file
diff --git a/src/edu/bu/ec504/spr24/Brain/Board.java b/src/edu/bu/ec504/spr24/Brain/Board.java
new file mode 100644
index 0000000000000000000000000000000000000000..d19b1b1e2717bed730eb11eece51a9a86b1e2796
--- /dev/null
+++ b/src/edu/bu/ec504/spr24/Brain/Board.java
@@ -0,0 +1,198 @@
+package edu.bu.ec504.spr24.Brain;
+
+import edu.bu.ec504.spr24.sameGameTris.CircleColor;
+import edu.bu.ec504.spr24.sameGameTris.sge;
+import java.util.LinkedList;
+import java.util.Objects;
+
+/**
+ * An internal recording of a board set up.
+ */
+class Board {
+
+ /**
+ * A 2-d Linked list of colors on the board.
+ */
+ final LinkedList> data;
+
+ /**
+ * The width and height of the board.
+ */
+ final private int width, height;
+
+ // constructs a board of specified width and height
+ Board(int width, int height) {
+ this.width = width;
+ this.height = height;
+
+ // allocate the data structure for storing board contents
+ data = new LinkedList<>();
+
+ // set up the data structure
+ for (int ii = 0; ii < width; ii++) {
+ LinkedList temp = new LinkedList<>();
+ for (int jj = 0; jj < height; jj++) {temp.add(CircleColor.NONE);}
+ data.add(temp);
+ }
+ }
+
+ /**
+ * default constructor
+ */
+ Board() {
+ this(sge.getInstance().boardWidth(), sge.getInstance().boardHeight());
+ }
+
+ /**
+ * copy constructor
+ *
+ * @param baseBoard the board to copy
+ */
+ Board(Board baseBoard) {
+ // allocate memory for the new board
+ this(baseBoard.width, baseBoard.height);
+
+ // copy over all the specific items
+ for (int xx = 0; xx < columns(); xx++) {
+ for (int yy = 0; yy < rows(xx); yy++) {modify(xx, yy, baseBoard.getAt(xx, yy));}
+ }
+ }
+
+ /**
+ * @return the color of the yy'th item in the xx'th column, or CircleColor.NONE
+ * if the cell is not in the data container
+ */
+ CircleColor getAt(int xx, int yy) {
+ try {
+ return data.get(xx).get(yy);
+ } catch (IndexOutOfBoundsException e) {
+ return CircleColor.NONE;
+ }
+ }
+
+ /**
+ * @return the xx'th column, or null if the xx'th column does not exist in the data container
+ */
+ private LinkedList getAt(int xx) {
+ try {
+ return data.get(xx);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Changes yy'th item in xx'th column
+ * %R: The circle at this location must still be in the data field
+ */
+ void modify(int xx, int yy, CircleColor col) {
+ data.get(xx).set(yy, col);
+ }
+
+ /**
+ * Deletes yy'th item in xx'th column
+ * %R: The circle at this location must still be in the data field
+ */
+ private void delete(int xx, int yy) {
+ data.get(xx).remove(yy);
+ }
+
+ /**
+ * Deletes the column at (horizontal) board location xx
+ * * %R: The column at this location must still be in the data field
+ */
+ private void delete(int xx) {
+ data.remove(xx);
+ }
+
+ // public accessors
+
+ /**
+ * Simulates a click on the yy'th cell of the xx'th column
+ *
+ * @return the number of cells deleted
+ * @modifies Deletes cells in the same region as cell (xx,yy)
+ * @expects The clicked cell is assumed not to be empty
+ */
+ int clickNode(int xx, int yy) {
+ CircleColor myColor = getAt(xx, yy); // the color to match
+
+ // mark the region
+ int count = clickNodeHelper(xx, yy, myColor);
+
+ // clean up
+ // ... delete all cells with no color
+ // ... delete from the end to the front so that there are no problems with re-indexing
+ for (int ii = data.size() - 1; ii >= 0; ii--) {
+ for (int jj = Objects.requireNonNull(getAt(ii)).size() - 1; jj >= 0; jj--) {
+ if (getAt(ii, jj) == CircleColor.NONE) {delete(ii, jj);}
+ }
+
+ // ... delete the column if it is empty
+ if (Objects.requireNonNull(getAt(ii)).size() == 0) {delete(ii);}
+ }
+
+ return count;
+ }
+
+ /**
+ * Recursive procedure for propagating a click at a location with color "col".
+ * All items in the same region as the clicked cell are made to have CircleColor.NONE
+ *
+ * @return the number of cells changed to CircleColor.NONE in this call (and its recursive subcalls)
+ * @modifies the color of some cells, but no cells are actually deleted
+ */
+ int clickNodeHelper(int xx, int yy, CircleColor col) {
+ if (getAt(xx, yy) == CircleColor.NONE ||
+ // we've either already seen this, or we've hit an empty space
+ getAt(xx, yy) != col) // this is not the color we want
+ {return 0;}
+
+ // modify the current cell
+ modify(xx, yy, CircleColor.NONE);
+
+ return 1 + // 1 is for the current cell
+ clickNodeHelper(xx - 1, yy, col) + // cell to the left
+ clickNodeHelper(xx + 1, yy, col) + // cell to the right
+ clickNodeHelper(xx, yy - 1, col) + // cell below
+ clickNodeHelper(xx, yy + 1, col) // cell above
+ ;
+ }
+
+ /**
+ * @return the number of columns in the current state
+ */
+ int columns() {
+ return data.size();
+ }
+
+ /**
+ * @param xx the column being considered (assumed to exist)
+ * @return the number of rows in column xx
+ */
+ int rows(int xx) {
+ return data.get(xx).size();
+ }
+
+ /**
+ * @return a "pretty-printed" version of the data structure
+ */
+ public String display() {
+ String temp = data.toString();
+ return temp.replace("], [", "]\n[");
+ }
+
+ /**
+ * Stores an (xx,yy) position on the board.
+ */
+ static class Pos {
+
+ final int xx;
+ final int yy;
+
+ Pos(int xx, int yy) {
+ this.xx = xx;
+ this.yy = yy;
+ }
+ }
+}
diff --git a/src/edu/bu/ec504/spr24/Brain/Brain.java b/src/edu/bu/ec504/spr24/Brain/Brain.java
index 63da5cfff3a9134f0e3d1e38385c0cd932ce26e7..11ae4f71fdcdda60db0621551aa6faf3310ccf9d 100644
--- a/src/edu/bu/ec504/spr24/Brain/Brain.java
+++ b/src/edu/bu/ec504/spr24/Brain/Brain.java
@@ -1,6 +1,7 @@
package edu.bu.ec504.spr24.Brain;
import edu.bu.ec504.spr24.sameGameTris.GUI;
+import edu.bu.ec504.spr24.sameGameTris.sge;
/**
* The Brain is the artificial intelligence that tries to come up with the
@@ -10,32 +11,47 @@ import edu.bu.ec504.spr24.sameGameTris.GUI;
*/
public abstract class Brain implements Runnable {
// FIELDS
- protected final GUI myGUI; // the GUI class attached to this Brain
-
- // METHODS
-
+ protected final GUI myGUI; // stores the GUI class attached to this Brain
/**
- * Constructs the brain
- * @param myGUI A reference to the Graphical User Interface on which the game is being played.
+ * When set to true, the Brain should stop what it's doing and exit as soon as is appropriate.
*/
- Brain(GUI myGUI) { this.myGUI = myGUI; }
+ private volatile boolean allDone = false;
+
+ // METHODS
/**
- * Each Brain should have a name, which is provided by this method.
- * @return the name of the brain
+ * Constructs the brain
*/
- public abstract String myName();
+ Brain() { this.myGUI = sge.getInstance(); }
/**
* This is called when the Brain is being asked to close down (i.e., the game is over).
* It should clean up any data structures and/or signal threads to close, etc.
*/
- public abstract void allDone();
-
+ final public void allDone() { allDone=true; };
+
/**
* Starts the Brain a'thinking.
- * This is the code for making decisions about which circles you Brain selects.
+ * This is the code for requests decisions about which circles you Brain selects.
* @see java.lang.Runnable#run()
*/
- public abstract void run();
+ final public void run() {
+ while (!allDone && !myGUI.gameOverQ()) {
+ Board.Pos theNextMove = nextMove();
+ myGUI.makeMove(theNextMove.xx, theNextMove.yy); // i.e. click on the lower left corner
+ }
+ }
+
+ // ... METHODS FOR SUBCLASSES TO DEFINE
+ /**
+ * Each Brain should have a name, which is provided by this method.
+ * @return the name of the brain
+ */
+ public abstract String myName();
+
+ /**
+ * Returns the next move of the Brain.
+ */
+ public abstract Board.Pos nextMove();
+
}
diff --git a/src/edu/bu/ec504/spr24/Brain/LazyBrain.java b/src/edu/bu/ec504/spr24/Brain/LazyBrain.java
index 7c429134ddeae73ef754834117d86f5ee7fb00c5..0620bc36047c5e7a48ff407c050ca04e53162c27 100644
--- a/src/edu/bu/ec504/spr24/Brain/LazyBrain.java
+++ b/src/edu/bu/ec504/spr24/Brain/LazyBrain.java
@@ -1,9 +1,6 @@
package edu.bu.ec504.spr24.Brain;
-import java.util.LinkedList;
-import java.util.Objects;
-
-import edu.bu.ec504.spr24.sameGameTris.GUI;
+import edu.bu.ec504.spr24.Brain.Board.Pos;
import edu.bu.ec504.spr24.sameGameTris.CircleColor;
/**
@@ -13,11 +10,6 @@ public class LazyBrain extends Brain {
// FIELDS
- /**
- * When set to true, the Brain should stop what it's doing and exit as soon as is appropriate.
- */
- private volatile boolean allDone = false;
-
/**
* The Brain's recording of the current state of the board.
*/
@@ -25,18 +17,11 @@ public class LazyBrain extends Brain {
// METHODS
- /** Constructs a Brain linked to a specified myGUI
- * @param myGUI The GUI that will be instantiating the Brain
- */
- public LazyBrain(GUI myGUI) {
- super(myGUI);
- }
-
/**
- * {@inheritDoc}
+ * Constructs a Brain linked to a specified myGUI
*/
- public void allDone() {
- allDone = true;
+ public LazyBrain() {
+ super();
}
/**
@@ -46,23 +31,18 @@ public class LazyBrain extends Brain {
return "Lazy Brain";
}
- /**
- * {@inheritDoc}
- */
- public void run() {
+ @Override
+ public Pos nextMove() {
// Initialize and set up the internal board state with the current position
currBoard = new Board();
for (int xx=0; xx max) {
// record a new best move
@@ -101,186 +81,5 @@ public class LazyBrain extends Brain {
// INTERNAL CLASSES
- /**
- * Stores a board set up
- */
- private class Board {
-
- /**
- * A 2-d Linked list of colors on the board.
- */
- final LinkedList< LinkedList > data;
-
- /**
- * The width and height of the board.
- */
- final private int width, height;
-
- // constructs a board of specified width and height
- Board(int width, int height) {
- this.width = width; this.height = height;
-
- // allocate the data structure for storing board contents
- data = new LinkedList<>();
-
- // set up the data structure
- for (int ii=0; ii temp = new LinkedList<>();
- for (int jj=0; jjdata container
- */
- private CircleColor get(int xx, int yy) {
- try {
- return data.get(xx).get(yy);
- } catch (IndexOutOfBoundsException e) {
- return CircleColor.NONE;
- }
- }
-
- /**
- * @return the xx'th column, or null if the xx'th column does not exist in the data container
- */
- private LinkedList get(int xx) {
- try {
- return data.get(xx);
- } catch (IndexOutOfBoundsException e) {
- return null;
- }
- }
- /**
- * Changes yy'th item in xx'th column
- * %R: The circle at this location must still be in the data field
- */
- private void modify(int xx, int yy, CircleColor col) {
- data.get(xx).set(yy, col);
- }
-
- /**
- * Deletes yy'th item in xx'th column
- * %R: The circle at this location must still be in the data field
- */
- private void delete(int xx, int yy) {
- data.get(xx).remove(yy);
- }
-
- /**
- * Deletes the column at (horizontal) board location xx
- * * %R: The column at this location must still be in the data field
- */
- private void delete(int xx) {
- data.remove(xx);
- }
-
- // public accessors
- /**
- * Simulates a click on the yy'th cell of the xx'th column
- * @return the number of cells deleted
- * @modifies Deletes cells in the same region as cell (xx,yy)
- * @expects The clicked cell is assumed not to be empty
- */
- int clickNode(int xx, int yy) {
- CircleColor myColor = get(xx,yy); // the color to match
-
- // mark the region
- int count = clickNodeHelper(xx, yy, myColor);
-
- // clean up
- // ... delete all cells with no color
- // ... delete from the end to the front so that there are no problems with re-indexing
- for (int ii=data.size()-1; ii>=0; ii--) {
- for (int jj = Objects.requireNonNull(get(ii)).size()-1; jj>=0; jj--)
- if (get(ii,jj)==CircleColor.NONE)
- delete(ii, jj);
-
- // ... delete the column if it is empty
- if (Objects.requireNonNull(get(ii)).size()==0)
- delete(ii);
- }
-
- return count;
- }
-
- /**
- * Recursive procedure for propagating a click at a location with color "col".
- * All items in the same region as the clicked cell are made to have CircleColor.NONE
- * @modifies the color of some cells, but no cells are actually deleted
- * @return the number of cells changed to CircleColor.NONE in this call (and its recursive subcalls)
- */
- private int clickNodeHelper(int xx, int yy, CircleColor col) {
- if (get(xx,yy) == CircleColor.NONE || // we've either already seen this, or we've hit an empty space
- get(xx,yy) != col) // this is not the color we want
- return 0;
-
- // modify the current cell
- modify(xx,yy,CircleColor.NONE);
-
- return 1 + // 1 is for the current cell
- clickNodeHelper(xx-1, yy, col) + // cell to the left
- clickNodeHelper(xx+1, yy, col) + // cell to the right
- clickNodeHelper(xx, yy-1, col) + // cell below
- clickNodeHelper(xx, yy+1, col) // cell above
- ;
- }
-
- /**
- * @return the number of columns in the current state
- */
- int columns() {
- return data.size();
- }
-
- /**
- *
- * @param xx the column being considered (assumed to exist)
- * @return the number of rows in column xx
- */
- int rows(int xx) {
- return data.get(xx).size();
- }
-
- /**
- * @return a "pretty-printed" version of the data structure
- */
- public String display() {
- String temp = data.toString();
- return temp.replace("], [", "]\n[");
- }
-
- /**
- * Stores an (xx,yy) position on the board.
- */
- static class Pos {
- final int xx;
- final int yy;
- Pos(int xx, int yy) {this.xx=xx; this.yy=yy;}
- }
- }
}
diff --git a/src/edu/bu/ec504/spr24/Brain/SimpleBrain.java b/src/edu/bu/ec504/spr24/Brain/SimpleBrain.java
index a20c245d2d3890993706e7642804e24c2a765694..d06b2de300eba6f16c893df780b8469778b3f30c 100644
--- a/src/edu/bu/ec504/spr24/Brain/SimpleBrain.java
+++ b/src/edu/bu/ec504/spr24/Brain/SimpleBrain.java
@@ -1,6 +1,6 @@
package edu.bu.ec504.spr24.Brain;
-import edu.bu.ec504.spr24.sameGameTris.GUI;
+import edu.bu.ec504.spr24.Brain.Board.Pos;
/**
* A very simple Brain for the game.
@@ -10,16 +10,10 @@ public class SimpleBrain extends Brain {
// fields
private volatile boolean allDone = false; // when set to true, the Brain should stop what it's doing and exit (at an appropriate time)
- public SimpleBrain(GUI myGUI) {
- super(myGUI);
+ public SimpleBrain() {
+ super();
}
- /**
- * {@inheritDoc}
- */
- public void allDone() {
- allDone = true;
- }
/**
* {@inheritDoc}
@@ -28,11 +22,8 @@ private volatile boolean allDone = false; // when set to true, the Brain should
return "Simple Brain";
}
- /**
- * {@inheritDoc}
- */
- public void run() {
- while (!allDone && !myGUI.gameOverQ())
- myGUI.makeMove(0, myGUI.boardHeight()-1); // i.e. click on the lower left corner
+ @Override
+ public Pos nextMove() {
+ return new Pos(0, myGUI.boardHeight()-1);
}
}
diff --git a/src/edu/bu/ec504/spr24/Brain/SmarterBrain.java b/src/edu/bu/ec504/spr24/Brain/SmarterBrain.java
index 0d72fd9ddee5bbe28e5b16fe9d8696f27013f984..d666a443c018df0de85a367e203bc128b50a7d57 100644
--- a/src/edu/bu/ec504/spr24/Brain/SmarterBrain.java
+++ b/src/edu/bu/ec504/spr24/Brain/SmarterBrain.java
@@ -1,19 +1,14 @@
package edu.bu.ec504.spr24.Brain;
-import edu.bu.ec504.spr24.sameGameTris.GUI;
-
+import edu.bu.ec504.spr24.Brain.Board.Pos;
import javax.swing.*;
/**
* A smarter brain, for you to produce.
*/
public class SmarterBrain extends Brain {
- public SmarterBrain(GUI myGUI) {
- super(myGUI);
- }
-
- @Override
- public void allDone() {
+ public SmarterBrain() {
+ super();
}
@Override
@@ -22,7 +17,9 @@ public class SmarterBrain extends Brain {
}
@Override
- public void run() {
+ public Pos nextMove() {
JOptionPane.showMessageDialog(null, "Please insert brain here!");
+ return null;
}
+
}
diff --git a/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java b/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java
index 58541a632f9b60cc39a5cbbb24f867cc8b5981f5..f9f4217177b864a469f80e5ca6c49c030be04e1c 100644
--- a/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java
+++ b/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java
@@ -55,28 +55,28 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
/**
* Creates a circle of the specified color at the specified location
+ *
* @param clr The color of the new circle.
* @param xx The xx location of the circle in the grid of circles.
* @param yy The yy location of the circle in the grid of circles.
- * @param sgeGui A reference to the game GUI in which the circle will lie.
*/
- SelfAwareCircle(CircleColor clr, int xx, int yy, sge sgeGui) {
+ SelfAwareCircle(CircleColor clr, int xx, int yy) {
// record field parameters
this.xx = xx;
this.yy = yy;
this.clr = clr; // record the color of the button
if (clr == CircleColor.NONE) // circles with no color should be cleared
setClear();
- this.sgeGUI = sgeGui; // record the GUI that created this button
+ this.sgeGUI = sge.getInstance(); // record the GUI that created this button
addMouseListener(this); // register for mouse events
_myID = _id++;
}
/**
- * Creates a circle of the specified color at the specified location, based on {@link #SelfAwareCircle(CircleColor, int, int, sge).}
+ * Creates a circle of the specified color at the specified location, based on {@link #SelfAwareCircle(CircleColor, int, int) .}
*/
- SelfAwareCircle(int xx, int yy, sge mySgeGui) {
- this(CircleColor.randColor(), xx, yy, mySgeGui);
+ SelfAwareCircle(int xx, int yy) {
+ this(CircleColor.randColor(), xx, yy);
}
// METHODS
diff --git a/src/edu/bu/ec504/spr24/sameGameTris/sge.java b/src/edu/bu/ec504/spr24/sameGameTris/sge.java
index 047f815e4b2329799436e0675862b59ddbfd899a..5ea62761387b70bc57269ac7f205f63a742db84e 100644
--- a/src/edu/bu/ec504/spr24/sameGameTris/sge.java
+++ b/src/edu/bu/ec504/spr24/sameGameTris/sge.java
@@ -36,7 +36,7 @@ import static java.util.concurrent.Executors.newScheduledThreadPool;
* A Singleton Graphical User Interface for the game.
* @author Ari Trachtenberg
*/
-class sge extends GUI implements ActionListener, ItemListener {
+public class sge extends GUI implements ActionListener, ItemListener {
// CONSTANTS
static public final int defaultWidth = 15, defaultHeight = 10; // sizes in terms of numbers of circles
@@ -147,18 +147,26 @@ class sge extends GUI implements ActionListener, ItemListener {
*/
private sge() {
super("Ari's samegame");
- try {
- SwingUtilities.invokeAndWait(
- this::setupGUI
- );
- } catch (Exception e) {
- System.out.println("Saw exception " + e);
- }
+ }
+
+ /**
+ * Fire up the GUI.
+ */
+ private void run() {
+ try {
+ SwingUtilities.invokeAndWait(
+ this::setupGUI
+ );
+ } catch (Exception e) {
+ System.out.println("Saw exception " + e);
+ }
}
public static sge getInstance() {
if (sge.Instance == null) {
+ // no Instance has been set up yet ... make it happen.
sge.Instance = new sge();
+ sge.Instance.run();
}
return Instance;
}
@@ -318,9 +326,9 @@ class sge extends GUI implements ActionListener, ItemListener {
for (int ii = 0; ii < width; ii++) {
// establish the button
if (jj<=emptyRows)
- circles[ii][jj] = new SelfAwareCircle(CircleColor.NONE, ii, jj, this); // the top emptyRows should have a circle with no color
+ circles[ii][jj] = new SelfAwareCircle(CircleColor.NONE, ii, jj); // the top emptyRows should have a circle with no color
else
- circles[ii][jj] = new SelfAwareCircle(ii, jj, this);
+ circles[ii][jj] = new SelfAwareCircle(ii, jj);
circlePanel.add(circles[ii][jj]);
}
// ... set up listeners in the area
@@ -614,11 +622,11 @@ class sge extends GUI implements ActionListener, ItemListener {
if (source == noPlayerMenuItem)
return; // i.e. no players
else if (source == simplePlayerMenuItem)
- startBrain(new SimpleBrain(this));
+ startBrain(new SimpleBrain());
else if (source == lazyPlayerMenuItem)
- startBrain(new LazyBrain(this));
+ startBrain(new LazyBrain());
else if (source == smarterPlayerMenuItem)
- startBrain(new SmarterBrain( this));
+ startBrain(new SmarterBrain());
} else {
// deselected
if (theBrain != null)