From 2239bc6cf434879d95801220141c86cc229c2c76 Mon Sep 17 00:00:00 2001 From: Ari Trachtenberg Date: Thu, 24 Jan 2019 17:14:37 -0500 Subject: [PATCH] added IntelliJ project metadata --- .idea/encodings.xml | 4 + sg_dist.iml | 3 +- src/edu/bu/ec504/spr19/sameGame/sg.java | 951 ++++++++++++------------ 3 files changed, 485 insertions(+), 473 deletions(-) create mode 100644 .idea/encodings.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sg_dist.iml b/sg_dist.iml index 26db12c..bfc53fb 100644 --- a/sg_dist.iml +++ b/sg_dist.iml @@ -1,7 +1,6 @@ - - + diff --git a/src/edu/bu/ec504/spr19/sameGame/sg.java b/src/edu/bu/ec504/spr19/sameGame/sg.java index ee42b85..bb9ecfb 100644 --- a/src/edu/bu/ec504/spr19/sameGame/sg.java +++ b/src/edu/bu/ec504/spr19/sameGame/sg.java @@ -1,17 +1,16 @@ package edu.bu.ec504.spr19.sameGame; -/* - An implementation of the "samegnome" game, possibly with a computer-aided solver. - Written by Prof. Ari Trachtenberg, January 20, 2019. -*/ - - import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridLayout; -import java.awt.event.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; import javax.swing.ButtonGroup; +import javax.swing.JApplet; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; @@ -30,123 +29,126 @@ import edu.bu.ec504.spr19.Brain.Brain; import edu.bu.ec504.spr19.Brain.lazyBrain; import edu.bu.ec504.spr19.Brain.simpleBrain; +// Ari's implementation of the "samegnome" game, possibly with a computer-aided solver. + class sg extends GUI implements ActionListener,ItemListener { - // constants - private static final int DEFAULT_WIDTH =15; - private static final int DEFAULT_HEIGHT =10; // sizes in terms of numbers of circles - private static final int DEFAULT_WINDOW_WIDTH =500; - private static final int DEFAULT_WINDOW_HEIGHT =300; // default window size, if run as a standalone application - private static final int NUM_COLORS = 3; // the number of colors available for circles - private static final int DISPLAY_TIME = 1000; // number of milliseconds to display (highlight) a move before actually making it - static private final int SINGLE_CIRCLE_PENALTY = -10; // the penalty for clicking on a single circle - private static final String HIGH_SCORE_FILE =".highscores.db"; // where high scores are kept - private static final long serialVersionUID = 1L; // required for serializability - - // fields - final JLabel regionPoints = new JLabel("0"); // keeps track of the number of selected points - final JLabel totalPoints = new JLabel("0"); // keeps track of the total number of points so far - private int width = DEFAULT_WIDTH, height= DEFAULT_HEIGHT; // initial width and height of the array of circles - private SelfAwareCircle circles[][]; - private String highScoreName = null; // the name to use for the high score - - // ... GUI elements - private JPanel circlePanel; // the panel containing the circles - private JPanel textPanel; // the panel containing scoring information - // ... ... menu items - private JMenuItem changeBoard; - private JMenuItem quitGame; - private JRadioButtonMenuItem noPlayerMenuItem,simplePlayerMenuItem, lazyPlayerMenuItem, // various automatic player options - smarterPlayerMenuItem; - - // ... Brain elements - private Brain theBrain; // the Brain (automated player) for the game - private Thread brainThread; // the thread that will run the Brain - - // Public access methods - - /* - * Default no-args constructor - */ - private sg() { - super("Ari's sameGame"); - try { - SwingUtilities.invokeAndWait( - this::setupGUI - ); - } - catch (Exception e) { System.out.println("Saw exception "+e); } - } - - /* - * Returns the color of the circle at location [xx][yy], or NONE if the circle has been cleared - * @param xx must be between 0 and width - * @param yy must be between 0 and height - */ - public CircleColor colorAt(int xx, int yy) { - if (circles[xx][yy].isCleared()) - return CircleColor.NONE; - else - return circles[xx][yy].clr; - } - - /* - * Returns the width of the current board - */ - public int boardWidth() { - return width; - } - - /* - * Returns the height of the current board - */ - public int boardHeight() { - return height; - } - - /* - * Returns true iff the game is over - * (i.e. every circle is surrounded by cleared circles or circles of a different color) - */ - public boolean gameOverQ() { - for (int xx=0; xxlevel - */ - final public int score(int level, CircleColor theColor) { - int tmp; + // constants + static public final int defaultWidth=15, defaultHeight=10; // sizes in terms of numbers of circles + static public final int defaultWindowWidth=500, defaultWindowHeight=300; // default window size, if run as a standalone application + static public final int numColors = 3; // the number of colors available for circles + static public final int displayTime = 1000; // number of milliseconds to display (highlight) a move before actually making it + static public final String highScoreFile=".highscores.db"; // where high scores are kept + private static final long serialVersionUID = 1L; // required for serializability + + // fields (all static - only one instance of the game should be running at a time) + final JLabel regionPoints = new JLabel("0"); // keeps track of the number of selected points + final JLabel totalPoints = new JLabel("0"); // keeps track of the total number of points so far + private int width = defaultWidth, height=defaultHeight; // initial width and height of the array of circles + private SelfAwareCircle circles[][]; + private String highScoreName = null; // the name to use for the high score + + // ... GUI elements + private JPanel circlePanel; // the panel containing the circles + private JPanel textPanel; // the panel containing scoring information + // ... ... menu items + private JMenuItem changeBoard; + private JMenuItem quitGame; + private JRadioButtonMenuItem noPlayerMenuItem,simplePlayerMenuItem, lazyPlayerMenuItem, // various automatic player options + smarterPlayerMenuItem; + + // ... Brain elements + Brain theBrain; // the Brain (automated player) for the game + Thread brainThread; // the thread that will run the Brain + + // Public access methods + + /* + * Default no-args constructor + */ + public sg() { + super("Ari's samegame"); + try { + SwingUtilities.invokeAndWait( + new Runnable() { + public void run() { + setupGUI(); + } + } + ); + } + catch (Exception e) { System.out.println("Saw exception "+e); } + } + + /* + * Returns the color of the circle at location [xx][yy], or NONE if the circle has been cleared + * @param xx must be between 0 and width + * @param yy must be between 0 and height + */ + public CircleColor colorAt(int xx, int yy) { + if (circles[xx][yy].isCleared()) + return CircleColor.NONE; + else + return circles[xx][yy].clr; + } + + /* + * Returns the width of the current board + */ + public int boardWidth() { + return width; + } + + /* + * Returns the height of the current board + */ + public int boardHeight() { + return height; + } + + /* + * Returns true iff the game is over + * (i.e. every circle is surrounded by cleared circles or circles of a different color) + */ + public boolean gameOverQ() { + for (int xx=0; xxlevel + */ + final public int score(int level, CircleColor theColor) { + int tmp; if (level==1) - return -SINGLE_CIRCLE_PENALTY; + return -10; else tmp = (int) (level * Math.log(level)); switch (theColor) { @@ -157,355 +159,362 @@ class sg extends GUI implements ActionListener,ItemListener { default: return 0; } - } - - - /* - * setupGUI helper - * - adds to circle[ii][jj] a SelfAwareListener of circle[xx][yy] as 0<=xx=width || yy>=height || circles[xx][yy].isCleared()) - return false; - else - return circles[xx][yy].getColor().equals(theColor); - } - - /* - * Moves circle c1 into location c2, leaving c1 as a clear circle that - * does not receive mouse events - */ - private void moveCircle(SelfAwareCircle orig, SelfAwareCircle dest) { - // copy the immutable, position independent values - orig.copy(dest); - - // clear the top item - orig.setClear(); - } - - /* - * Called to request a reshifting of the board (as necessary). - * This should happen if some circles are rendered "clear"ed - * @return true if game continues; false otherwise - */ - - final boolean shiftCircles() { - /* start at the bottom and move up ... all cleared circles are - * removed, with upper circles falling into their positions; - * if a column is totally empty, then its rightmost columns - * shift into it - */ - - // 1. SHIFT VERTICALLY - for (int xx=0; xx firstClr) - firstFull = firstClr; // only move items "down" the column - - // find the lowest non-cleared entry in the column (if it exists) - try { - while (circles[xx][firstFull].isCleared()) - firstFull--; - } catch (ArrayIndexOutOfBoundsException e) { - moveOn = true; - continue; // i.e. the whole column is clear --- for now, go to the next column - } - - moveCircle(circles[xx][firstFull],circles[xx][firstClr]); - - firstFull--; firstClr--; // iterate - } - } - - // 2. SHIFT HORIZONTALLY - // Check to see if any column is now empty - // ... this could have been done within the loop above, but it would detract from readability of the code - boolean emptySoFar=true; // remains true if all columns seen so far have only cleared circles - for (int xx=width-1; xx>=0; xx--) { - boolean allCleared=true; // remains true if all circles in column xx have been cleared - for (int yy=0; yy=width || yy>=height || circles[xx][yy].isCleared()) + return false; + else + return circles[xx][yy].getColor().equals(theColor); + } + + /* + * Moves circle c1 into location c2, leaving c1 as a clear circle that + * does not receive mouse events + */ + private void moveCircle(SelfAwareCircle orig, SelfAwareCircle dest) { + // copy the immutable, position independent values + orig.copy(dest); + + // clear the top item + orig.setClear(); + } + + /* + * Called to request a reshifting of the board (as necessary). + * This should happen if some circles are rendered "clear"ed + * @return true if game continues; false otherwise + */ + + final boolean shiftCircles() { + /* start at the bottom and move up ... all cleared circles are + * removed, with upper circles falling into their positions; + * if a column is totally empty, then its rightmost columns + * shift into it + */ + + // 1. SHIFT VERTICALLY + for (int xx=0; xx firstClr) + firstFull = firstClr; // only move items "down" the column + + // find the lowest non-cleared entry in the column (if it exists) + try { + while (circles[xx][firstFull].isCleared()) + firstFull--; + } catch (ArrayIndexOutOfBoundsException e) { + moveOn = true; + continue; // i.e. the whole column is clear --- for now, go to the next column + } + + moveCircle(circles[xx][firstFull],circles[xx][firstClr]); + + firstFull--; firstClr--; // iterate + } + } + + // 2. SHIFT HORIZONTALLY + // Check to see if any column is now empty + // ... this could have been done within the loop above, but it would detract from readability of the code + boolean emptySoFar=true; // remains true if all columns seen so far have only cleared circles + for (int xx=width-1; xx>=0; xx--) { + boolean allCleared=true; // remains true if all circles in column xx have been cleared + for (int yy=0; yy