Skip to content
Commits on Source (6)
......@@ -13,12 +13,6 @@
</component>
<component name="ChangeListManager">
<list default="true" id="78671b20-6a1e-42c8-be28-50b7f38fa7ff" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/Board.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/Board.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/Brain.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/Brain.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/LazyBrain.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/brain/LazyBrain.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/CircleColor.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/CircleColor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
......@@ -50,17 +44,23 @@
</component>
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;ASKED_ADD_EXTERNAL_FILES&quot;: &quot;true&quot;,
&quot;Application.EC504 SameGameTris.executor&quot;: &quot;Run&quot;,
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;project.structure.last.edited&quot;: &quot;Project&quot;,
&quot;project.structure.proportion&quot;: &quot;0.0&quot;,
&quot;project.structure.side.proportion&quot;: &quot;0.36091954&quot;,
&quot;run.code.analysis.last.selected.profile&quot;: &quot;pProject Default&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.lookFeel&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
......@@ -85,6 +85,13 @@
</method>
</configuration>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="jdk-17.0.10-corretto-17.0.10-f644763e9732-24582b8d" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="SvnConfiguration">
<configuration />
......@@ -102,6 +109,9 @@
<workItem from="1706042051986" duration="6820000" />
<workItem from="1706057188033" duration="218000" />
<workItem from="1706070762735" duration="2123000" />
<workItem from="1706112889389" duration="6798000" />
<workItem from="1706139932552" duration="8790000" />
<workItem from="1707268803363" duration="371000" />
</task>
<task id="LOCAL-00001" summary="Apparently working version.">
<created>1580084914114</created>
......@@ -156,7 +166,23 @@
<option name="project" value="LOCAL" />
<updated>1706051180665</updated>
</task>
<option name="localTasksCounter" value="8" />
<task id="LOCAL-00008" summary="Working on concurrency issues.">
<option name="closed" value="true" />
<created>1706114342828</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1706114342829</updated>
</task>
<task id="LOCAL-00009" summary="Fixed concurrency issue.">
<option name="closed" value="true" />
<created>1706152811353</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1706152811353</updated>
</task>
<option name="localTasksCounter" value="10" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
......@@ -169,22 +195,8 @@
<MESSAGE value="Cleaning up." />
<MESSAGE value="Working version ..." />
<MESSAGE value="Nice and clean ..." />
<option name="LAST_COMMIT_MESSAGE" value="Nice and clean ..." />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java</url>
<line>697</line>
<option name="timeStamp" value="1" />
</line-breakpoint>
<line-breakpoint enabled="true" type="java-line">
<url>file://$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java</url>
<line>208</line>
<option name="timeStamp" value="3" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
<MESSAGE value="Working on concurrency issues." />
<MESSAGE value="Fixed concurrency issue." />
<option name="LAST_COMMIT_MESSAGE" value="Fixed concurrency issue." />
</component>
</project>
\ No newline at end of file
......@@ -11,6 +11,8 @@ import edu.bu.ec504.spr24.sameGameTris.SameGameTris;
*/
public abstract class Brain implements Runnable {
// CONSTANTS
// FIELDS
protected final GUI myGUI; // stores the GUI class attached to this Brain
/**
......@@ -32,15 +34,14 @@ public abstract class Brain implements Runnable {
final public void allDone() {allDone = true;}
/**
* Starts the Brain a'thinking.
* This is the code for requests decisions about which circles you Brain selects.
* Asks the Brain to for a move, and effects it on the GUI.
*
* @see java.lang.Runnable#run()
*/
final public void run() {
while (!allDone && !myGUI.gameOverQ()) {
if (!allDone && !myGUI.gameOverQ()) {
Board.Pos theNextMove = nextMove();
myGUI.makeMove(theNextMove.xx, theNextMove.yy); // i.e. click on the lower left corner
myGUI.makeMove(theNextMove.xx, theNextMove.yy);
}
}
......
package edu.bu.ec504.spr24.sameGameTris;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.io.Serial;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
......@@ -45,13 +48,23 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
* Rate at which new "Tetrising" circles are being produced, in microseconds.
* Production rate increases invesely proportional to the number of circle selections clicked so far.
*/
static private long PRODUCT_CICLE_US = 5000000;
static private long PRODUCT_CIRCLE_US = 10000000;
/**
* Rate at which new "Tetrising" circles descend on the board, in microseconds.
* Production rate increases invesely proportional to the number of circle selections clicked so far.
*/
static private long DROP_CIRCLE_US = 5000000;
/**
* The number of microseconds between Brain moves
*/
private static final long BRAIN_WAIT_US = 1000000;
/**
* The amount of time to wait between games, to allow for existing elements to settle.
*/
private static final long TIME_BETWEEN_GAMES_MS = 1000;
/**
* The number of empty rows on the top of the game.
*/
......@@ -68,9 +81,10 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
static public final int NUM_COLORS = 3;
/**
* The number of milliseconds to display (highlight) a move before actually making it.
* The number of milliseconds to wait after selecting a region before disappearing it.
* This allows the user to see the region being selected
*/
static private final int DISPLAY_TIME_MS = 1000;
static private final int DISPLAY_WAIT_MS = 700;
/**
* The file where high scores are stored.
......@@ -96,7 +110,16 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
private SelfAwareCircle[][] circles;
private String highScoreName = null; // the name to use for the high score
static final Random randGen = new Random(); // package-private random number generator used for the entire package (i.e., repeatedly seeding with the same value produces the same randomness).
static private int numClicks = 1; // Must be a positive integer; counts the number of clicks on circles since the last time the board was reset.
/**
* Counts the number of clicks on circles since the last time the board was reset.
* @requires must be a positive integer; c
*/
static private int numClicks = 1;
/**
* true iff the game is over (i.e., not running)
*/
boolean gameOver = false;
/**
* An instance of the SGE GUI.
*/
......@@ -115,6 +138,8 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
// ... Brain elements
Brain theBrain; // the Brain (automated player) for the game
Thread brainThread; // the thread that will run the Brain
final ScheduledExecutorService brainExec = newScheduledThreadPool(2); // set up the brain threads
private ScheduledFuture<?> brainFuture = null; // schedule for Brain events (i.e., make moves)
// ... Tetris executor
final ScheduledExecutorService tetrisExec = newScheduledThreadPool(2); // sets up tetris threads
......@@ -243,6 +268,9 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
* (i.e. every circle is surrounded by cleared circles or circles of a different color)
*/
public boolean gameOverQ() {
if (gameOver)
return true;
for (int xx = 0; xx < width; xx++)
for (int yy = 0; yy < height; yy++) {
if (!circles[xx][yy].isCleared()) {
......@@ -262,17 +290,21 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
/*
* "Clicks" on the circle at location (xx,yy)
*/
@Override
public void makeMove(int xx, int yy) {
circles[xx][yy].mouseEntered(null); // pretend the mouse was pressed at location (xx,yy)
try {
Thread.sleep(DISPLAY_TIME_MS); // wait a bit for the user to register the move
} catch (InterruptedException ignored) {
}
circles[xx][yy].mouseExited(null);
circles[xx][yy].mousePressed(null);
circles[xx][yy].mouseReleased(
null); // pretend that the mouse button was released at the location
Timer t = new Timer();
TimerTask tt = new TimerTask() {
@Override
public void run() {
final SelfAwareCircle theCircle = circles[xx][yy];
theCircle.mouseExited(null);
theCircle.mousePressed(null);
theCircle.mouseReleased(
null); // pretend that the mouse button was released at the location
}
};
t.schedule(tt, DISPLAY_WAIT_MS);
}
/**
......@@ -425,17 +457,23 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
dropCircleFuture.cancel(true);
}
/**
* @return true iff tetrising is going on
*/
public boolean isTetrisingQ() {
return produceCircleFuture!=null && produceCircleFuture.isCancelled()==false;
}
/**
* Sets up threads that drop circles onto the board and move them down over time.
* As {@link #numClicks} gets larger, circles come more often and drop faster.
*/
public void updateTetrising() {
public void restartTetrising() {
// cancel the old schedules
cancelTetrisingSchedules();
// start up the new ones
produceCircleFuture = tetrisExec.scheduleAtFixedRate(new initDropCircles(), 0,
PRODUCT_CICLE_US / numClicks, TimeUnit.MICROSECONDS);
PRODUCT_CIRCLE_US / numClicks, TimeUnit.MICROSECONDS);
dropCircleFuture = tetrisExec.scheduleAtFixedRate(new moveDropCircles(), 0, DROP_CIRCLE_US / numClicks,
TimeUnit.MICROSECONDS);
}
......@@ -448,8 +486,7 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
// close down the brain
highScoreName = null;
if (theBrain != null)
theBrain.allDone();
stopBrain();
// score panel
totalPoints.setText("0");
......@@ -470,6 +507,9 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
// cancel tetrising schedules
numClicks = 1; // reset the number of circle clicks in the system
cancelTetrisingSchedules();
// reset gameOver
gameOver = false;
}
/*
......@@ -509,40 +549,40 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
GUIlock.lock(); // acquire a lock
try {
// 1. SHIFT VERTICALLY
for (int xx = 0; xx < width; xx++) {
int firstClr = height - 1; // the lowest cleared entry in the column
int firstFull =
height - 1; // the lowest uncleared entry in the column that has not yet been processed
boolean moveOn = false; // set to true in order to move on to the next column
while (!moveOn) {
// find the lowest clear entry in the column (if it exists)
try {
while (!circles[xx][firstClr].isCleared())
firstClr--;
} catch (ArrayIndexOutOfBoundsException e) {
moveOn = true;
continue; // i.e. no cleared circle found in this column --- go to the next column
}
if (firstFull > 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
}
}
// // 1. SHIFT VERTICALLY
// for (int xx = 0; xx < width; xx++) {
// int firstClr = height - 1; // the lowest cleared entry in the column
// int firstFull =
// height - 1; // the lowest uncleared entry in the column that has not yet been processed
// boolean moveOn = false; // set to true in order to move on to the next column
// while (!moveOn) {
// // find the lowest clear entry in the column (if it exists)
// try {
// while (!circles[xx][firstClr].isCleared())
// firstClr--;
// } catch (ArrayIndexOutOfBoundsException e) {
// moveOn = true;
// continue; // i.e. no cleared circle found in this column --- go to the next column
// }
//
// if (firstFull > 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
......@@ -569,8 +609,9 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
// 3. (LAST ITEM) CHECK IF THE GAME HAS ENDED
// This happens if every circle is surrounded by cleared circles or circles of a different color
if (gameOverQ())
if (gameOverQ()) {
doGameOver("exhausted all circles"); // all done
}
} finally {
GUIlock.unlock(); // release the circles for other processes
}
......@@ -582,40 +623,78 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
* @param feedback Some string to present to the user; typically the reason that the game is over.
*/
private void doGameOver(String feedback) {
// close out other threads and variables
gameOver = true;
cancelTetrisingSchedules(); // cancel Tetrising threads
stopBrain(); // stop the thinking Brain
// check the high score
int score = Integer.parseInt(totalPoints.getText());
highScore hs = new highScore(HIGH_SCORE_FILE);
// check the high score
if (hs.newRecordQ(score)) { // i.e. a new record
JOptionPane.showMessageDialog(null,
_showMessage(null,
"Game Over (" + feedback + ") - You got a new high score of " + score + " points!\n" +
"Your weighted score for this sized board was " + highScore.hsComp.weightedScore(
new highScore.HSdata("", width, height, score)) + ".");
if (highScoreName == null)
highScoreName = JOptionPane.showInputDialog(null,
highScoreName = _showInput(null,
"You got a new high score!\nPlease enter your name:");
if (highScoreName != null) { // i.e. the user is interested in high scores
if (highScoreName != null) { // i.e. the user is interested in high scores
// populate the high score item
highScore.HSdata datum = new highScore.HSdata(highScoreName, width, height, score);
hs.putScore(datum); // enter the name into the high score list
}
} else
JOptionPane.showMessageDialog(null,
} else {
_showMessage(null,
"Game Over (" + feedback + ") - You did not make the high score. You had " + score
+ " points.\n" +
"Your weighted score for this sized board was " + highScore.hsComp.weightedScore(
new highScore.HSdata("", width, height, score)) + ".");
}
_showMessage(null, "Current high scores:\n" + hs.display());
// // cleanup
// cleanUp();
// setupGUI();
// "that's all folks"
System.exit(0);
}
/**
* Do a task in the future.
* @param task The task to complete.
* @param whenMS How many milliseconds in the future to do the task.
*/
private void _doInFuture(TimerTask task, long whenMS) {
Timer timer = new Timer();
timer.schedule(task, whenMS);
}
JOptionPane.showMessageDialog(null, "Current high scores:\n" + hs.display());
/**
* Shows a message on the parent component and waits for the user to click "OK".
* @param parent The component on which to show the dialog box.
* @param message The message to display.
*/
private void _showMessage(Component parent, String message) {
JOptionPane.showMessageDialog(parent, message);
}
// i.e. time for a new game
cleanUp();
setupGUI();
/**
* Shows an input request on the parent component and returns the user's input.
* @param parent The component on which to show the dialog box.
* @param message The input request
*/
private String _showInput(Component parent, String message) {
return JOptionPane.showInputDialog(parent, message);
}
/**
* Handle menu events
* @param e The event to handle.
*/
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
......@@ -665,11 +744,24 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
private void startBrain(Brain theBrain) {
this.theBrain = theBrain;
highScoreName = theBrain.myName(); // the computer gets credit for any subsequent high score
brainThread = new Thread(theBrain, "Brain Thread");
brainThread.start();
// brainThread = new Thread(theBrain, "Brain Thread");
// brainThread.start();
brainFuture = brainExec.scheduleAtFixedRate(theBrain, 0, BRAIN_WAIT_US, TimeUnit.MICROSECONDS);
}
// For handling the menu checkBox
/**
* Stops the Brain that makes move.
*/
private void stopBrain() {
if (theBrain != null) {
theBrain.allDone();
brainFuture.cancel(true);
}
}
/**
* Handles the menu checkBox
*/
public void itemStateChanged(ItemEvent e) {
Object source = e.getItemSelectable();
......
......@@ -16,7 +16,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
class SelfAwareCircle extends Component implements MouseListener, SelfAwareListener {
// Constants
private final Color _hltColor = new Color(200,200,200); // the color to use for highlighting a button
private final Color _hltColor = new Color(200, 200, 200); // the color to use for highlighting a button
// FIELDS
public final int xx;
......@@ -25,9 +25,9 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
@Serial
private static final long serialVersionUID = 1L;
private final ArrayList<SelfAwareListener> _listeners = new ArrayList<>(); // who is listening to events fired by this circle
private static int _id =0;
private static int _id = 0;
private final int _myID; // the circle's ID
private Visibility _state = Visibility.plain; // the current state of the circle
private Visibility _state = Visibility.plain; // the current state of the circle
private final SameGameTris sameGameTrisGUI; // a link to the GUI that created this circle
/**
......@@ -39,7 +39,7 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
/*
* Records the visibility of an object.
*/
public enum Visibility{
public enum Visibility {
/*
* the circle is highlighted
*/
......@@ -51,7 +51,8 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
/*
* the circle is cleared (i.e. background color)
*/
clear}
clear
}
// CONSTRUCTORS
......@@ -59,203 +60,204 @@ 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 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.
*/
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.sameGameTrisGUI = SameGameTris.getInstance(); // record the GUI that created this button
addMouseListener(this); // register for mouse events
_myID = _id++;
}
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.sameGameTrisGUI = SameGameTris.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) .}
*/
SelfAwareCircle(int xx, int yy) {
this(CircleColor.randColor(), xx, yy);
}
// METHODS
// ... helpers
/**
* Creates a circle of the specified color at the specified location, based on {@link #SelfAwareCircle(CircleColor, int, int) .}
*/
SelfAwareCircle(int xx, int yy) {
this(CircleColor.randColor(), xx, yy);
}
// .. info methods and accessors/setters
static int getRegionLength() {
return regionLength.get();
}
// METHODS
// ... helpers
public int getId() {
return _myID;
}
// .. info methods and accessors/setters
static int getRegionLength() {
return regionLength.get();
}
Visibility get_state() {
return _state;
}
public int getId() {
return _myID;
}
public CircleColor getColor() {
return clr;
}
Visibility get_state() {
return _state;
}
public CircleColor getColor() {
return clr;
}
/**
* Resets the color of this circle to a random color.
*/
void resetColor() {
clr=CircleColor.randColor();
}
void resetColor() {
clr = CircleColor.randColor();
}
void set_state(Visibility _state) {
if (_state == Visibility.clear)
setClear(); // i.e. there is extra overhead in clearing
else
this._state = _state;
repaint();
}
boolean isCleared() {
return this._state == Visibility.clear;
}
void setClear() {
_state = Visibility.clear;
repaint();
}
void set_state(Visibility _state) {
if (_state ==Visibility.clear)
setClear(); // i.e. there is extra overhead in clearing
else
this._state = _state;
repaint();
}
boolean isCleared() {
return this._state == Visibility.clear;
}
/*
* Copies immutable elements of this SelfAwareCircle to "recipient"
* *except* position-dependent items (e.g. _listeners, xx, yy)
*/
void copyTo(SelfAwareCircle recipient) {
recipient.clr = clr;
if (recipient._state == _state)
return; // i.e. nothing to do
void setClear() {
_state = Visibility.clear;
repaint();
}
// special cases
// ... copying a cleared circle to an uncleared circle
if (_state == Visibility.clear)
recipient.setClear(); // includes removing a mouse listener
/*
* Copies immutable elements of this SelfAwareCircle to "recipient"
* *except* position-dependent items (e.g. _listeners, xx, yy)
*/
void copyTo(SelfAwareCircle recipient) {
recipient.clr=clr;
if (recipient._state == _state)
return; // i.e. nothing to do
// special cases
// ... copying a cleared circle to an uncleared circle
if (_state == Visibility.clear)
recipient.setClear(); // includes removing a mouse listener
// copy the state
recipient.set_state(_state);
}
// copy the state
recipient.set_state(_state);
}
// ... Mouse methods
public void mouseClicked(MouseEvent e) {}
// ... Mouse methods
public void mouseClicked(MouseEvent e) {
}
/*
* Highlights the button by changing its icon and firing off an event
* @param state determines whether to highlight or unhighlight the circle
*/
private void _highlightButton(Visibility stt) {
if (isCleared()) // don't go further with already cleared circles
return;
/*
* Highlights the button by changing its icon and firing off an event
* @param state determines whether to highlight or unhighlight the circle
*/
private void _highlightButton(Visibility stt) {
if (isCleared()) // don't go further with already cleared circles
return;
// set the state
if (stt==Visibility.clear) // clear has its own special treatment
setClear(); // properly clear this circle (including removal of mouse listener)
else
set_state(stt); // set the non-cleared state appropriately
// set the state
if (stt == Visibility.clear) // clear has its own special treatment
setClear(); // properly clear this circle (including removal of mouse listener)
else
set_state(stt); // set the non-cleared state appropriately
// deal with the region length
regionLength.getAndIncrement(); // update the region length by the newly highlighted item
// deal with the region length
regionLength.getAndIncrement(); // update the region length by the newly highlighted item
// announce the rollover to other circles
_fireButtonRolloverEvent(stt);
}
// announce the rollover to other circles
_fireButtonRolloverEvent(stt);
}
/*
* Mouse entered the object area:
* * Change its button icon
* * Broadcast the change to other buttons
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
public void mouseEntered(MouseEvent e) {
regionLength.set(0); // i.e. reinitialize
_highlightButton(Visibility.highlight);
}
/*
* Mouse entered the object area:
* * Change its button icon
* * Broadcast the change to other buttons
* @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
public void mouseEntered(MouseEvent e) {
regionLength.set(0); // i.e. reinitialize
_highlightButton(Visibility.highlight);
}
/**
* Mouse exited the object area.
* * Change its button icon
* * Broadcast the change to other buttons
*/
public void mouseExited(MouseEvent e) {
regionLength.set(0); // i.e. reinitialize
_highlightButton(Visibility.plain);
}
public void mouseExited(MouseEvent e) {
regionLength.set(0); // i.e. reinitialize
_highlightButton(Visibility.plain);
}
/**
* The mouse button was pressed.
*/
public void mousePressed(MouseEvent e) {
regionLength.set(0); // i.e. reinitialize
}
regionLength.set(0); // i.e. reinitialize
}
/**
* The mouse button was released.
*/
public void mouseReleased(MouseEvent e) {
_highlightButton(Visibility.clear);
// register the score
sameGameTrisGUI.totalPoints.setText("" +
(Integer.parseInt(sameGameTrisGUI.totalPoints.getText()) +
sameGameTrisGUI.score(SelfAwareCircle.getRegionLength(), getColor())));
_highlightButton(Visibility.clear);
// request that the board be shifted appropriately
sameGameTrisGUI.shiftCircles();
// register the score
sameGameTrisGUI.totalPoints.setText("" +
(Integer.parseInt(sameGameTrisGUI.totalPoints.getText()) +
sameGameTrisGUI.score(SelfAwareCircle.getRegionLength(), getColor())));
// update Tetrising
sameGameTrisGUI.updateNumClicks();
sameGameTrisGUI.updateTetrising();
// request that the board be shifted appropriately
sameGameTrisGUI.shiftCircles();
}
// update Tetrising
sameGameTrisGUI.updateNumClicks();
if (!sameGameTrisGUI.gameOverQ())
sameGameTrisGUI.restartTetrising();
}
// ... event methods
public synchronized void addSelfAwareListener(SelfAwareListener l) {
_listeners.add(l);
}
// ... event methods
public synchronized void addSelfAwareListener(SelfAwareListener l) {
_listeners.add(l);
}
public synchronized void removeSelfAwareListener(SelfAwareListener l) {
_listeners.remove(l);
}
public synchronized void removeSelfAwareListener(SelfAwareListener l) {
_listeners.remove(l);
}
/*
* fires off events to highlight or unhighlight circles
* @param state determines whether to highlight or unhighlight circles
*/
private synchronized void _fireButtonRolloverEvent(SelfAwareCircle.Visibility state) {
CircleRolloverEvent bre = new CircleRolloverEvent(this, xx, yy, clr, state);
for (SelfAwareListener _listener : _listeners) {
SelfAwareCircle temp = (SelfAwareCircle) _listener;
temp.rollingOver(bre);
}
/*
* fires off events to highlight or unhighlight circles
* @param state determines whether to highlight or unhighlight circles
*/
private synchronized void _fireButtonRolloverEvent(SelfAwareCircle.Visibility state) {
CircleRolloverEvent bre = new CircleRolloverEvent(this, xx, yy, clr, state);
for (SelfAwareListener _listener : _listeners) {
SelfAwareCircle temp = (SelfAwareCircle) _listener;
temp.rollingOver(bre);
}
}
/*
* What to do when receiving information from another button of a rolling over event
* @param e the event broadcast by the other button
*/
public void rollingOver(CircleRolloverEvent e) {
if (_state == e.getVisibility() || isCleared()) // i.e. this circle has already been processed
return;
if (e.getColor().equals(clr)) { // check if the color is the same as mine
_highlightButton(e.getVisibility());
}
// in all other cases, only update the text field (i.e. stop the recursion)
sameGameTrisGUI.regionPoints.setText(""+(SelfAwareCircle.getRegionLength())); // update the gui text field
}
/*
* What to do when receiving information from another button of a rolling over event
* @param e the event broadcast by the other button
*/
public void rollingOver(CircleRolloverEvent e) {
if (_state == e.getVisibility() || isCleared()) // i.e. this circle has already been processed
return;
// ... drawing methods
public void paint(Graphics g) {
// set the color, depending on whether this is being highlighted
switch (_state) {
if (e.getColor().equals(clr)) { // check if the color is the same as mine
_highlightButton(e.getVisibility());
}
// in all other cases, only update the text field (i.e. stop the recursion)
sameGameTrisGUI.regionPoints.setText("" + (SelfAwareCircle.getRegionLength())); // update the gui text field
}
// ... drawing methods
public void paint(Graphics g) {
// set the color, depending on whether this is being highlighted
switch (_state) {
case highlight:
g.setColor(_hltColor); // change to highlighting color
break;
......@@ -265,12 +267,12 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
case clear:
g.setColor(getParent().getBackground()); // i.e. set to background color
break;
}
}
// size of component
Dimension size = getSize();
// size of component
Dimension size = getSize();
// draw the circle
g.fillOval(0, 0, size.width, size.height);
}
// draw the circle
g.fillOval(0, 0, size.width, size.height);
}
}