Commit 9101d344 authored by Ari Trachtenberg's avatar Ari Trachtenberg
Browse files

Fixed concurrency issue.

parent 3dadd3ab
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
      <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/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/sameGameTris/SameGameTris.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java" afterDir="false" />
      <change beforePath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SelfAwareCircle.java" afterDir="false" />
    </list>
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -46,10 +47,12 @@
  </component>
  <component name="PropertiesComponent"><![CDATA[{
  "keyToString": {
    "ASKED_ADD_EXTERNAL_FILES": "true",
    "Application.EC504 SameGameTris.executor": "Run",
    "RunOnceActivity.OpenProjectViewOnStart": "true",
    "RunOnceActivity.ShowReadmeOnStart": "true",
    "WebServerToolWindowFactoryState": "false",
    "git-widget-placeholder": "master",
    "kotlin-language-version-configured": "true",
    "node.js.detected.package.eslint": "true",
    "node.js.detected.package.tslint": "true",
@@ -110,6 +113,7 @@
      <workItem from="1706057188033" duration="218000" />
      <workItem from="1706070762735" duration="2123000" />
      <workItem from="1706112889389" duration="6798000" />
      <workItem from="1706139932552" duration="5472000" />
    </task>
    <task id="LOCAL-00001" summary="Apparently working version.">
      <created>1580084914114</created>
@@ -193,8 +197,8 @@
      <breakpoints>
        <line-breakpoint enabled="true" type="java-line">
          <url>file://$PROJECT_DIR$/src/edu/bu/ec504/spr24/sameGameTris/SameGameTris.java</url>
          <line>626</line>
          <option name="timeStamp" value="3" />
          <line>615</line>
          <option name="timeStamp" value="9" />
        </line-breakpoint>
      </breakpoints>
    </breakpoint-manager>
+4 −12
Original line number Diff line number Diff line
@@ -12,10 +12,6 @@ import edu.bu.ec504.spr24.sameGameTris.SameGameTris;
public abstract class Brain implements Runnable {

	// CONSTANTS
	/**
	 * The number of milliseconds between Brain moves
	 */
	private static final long BRAIN_WAIT_MS = 1000;

	// FIELDS
	protected final GUI myGUI; // stores the GUI class attached to this Brain
@@ -38,18 +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
      try {
        Thread.sleep(BRAIN_WAIT_MS);
      } catch (InterruptedException ignored) {}
			myGUI.makeMove(theNextMove.xx, theNextMove.yy);
		}
	}

+49 −11
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.io.Serial;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
@@ -56,6 +56,10 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
   */
  static private long DROP_CIRCLE_US = 5000000;

  /**
   * The number of microseconds between Brain moves
   */
  private static final long BRAIN_WAIT_US = 1000000;
  /**
   * The number of empty rows on the top of the game.
   */
@@ -120,6 +124,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
@@ -269,6 +275,7 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
   */
  @Override
  public void makeMove(int xx, int yy) {
    System.out.println(new Date()+": Moving to "+xx+", "+yy);
    circles[xx][yy].mouseEntered(null);  // pretend the mouse was pressed at location (xx,yy)
    Timer t = new Timer();
    TimerTask tt = new TimerTask() {
@@ -428,17 +435,24 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
   * Cancel schedules for adding / dropping circles.
   */
  private void cancelTetrisingSchedules() {
    if (produceCircleFuture != null) {
    if (produceCircleFuture != null)
      produceCircleFuture.cancel(true);
    if (dropCircleFuture != null)
      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() {
    System.out.println("Restarting tetrising: ");
    // cancel the old schedules
    cancelTetrisingSchedules();

@@ -457,8 +471,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");
@@ -506,9 +519,11 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
  /*
   * Called to request a reshifting of the board (as necessary).
   *    This should happen if some circles are rendered "clear"ed
   * @return true iff the shift succeeded without the game ending,
   *     and false if the game ended as a result of the shift.
   */

  final void shiftCircles() {
  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
@@ -578,11 +593,15 @@ 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
        return false;
      }
    } finally {
      GUIlock.unlock(); // release the circles for other processes
    }

    return true;
  }

  /**
@@ -591,12 +610,15 @@ 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
    cancelTetrisingSchedules(); // cancel Tetrising threads
    stopBrain();                // stop the thinking Brain
    System.out.println("Game over, man!");

    // 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
      _showMessage(null,
          "Game Over (" + feedback + ") - You got a new high score of " + score + " points!\n" +
@@ -643,6 +665,10 @@ public class SameGameTris extends GUI implements ActionListener, ItemListener {
    return JOptionPane.showInputDialog(parent, message);
  }

  /**
   * Handle menu events
   * @param e The event to handle.
   */
  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();

@@ -692,11 +718,23 @@ 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();

+7 −5
Original line number Diff line number Diff line
@@ -199,6 +199,7 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
	 * The mouse button was released.
	 */
	public void mouseReleased(MouseEvent e) {
		System.out.println("Released mouse:"+Thread.currentThread().getName());
			_highlightButton(Visibility.clear);

			// register the score
@@ -207,11 +208,12 @@ class SelfAwareCircle extends Component implements MouseListener, SelfAwareListe
							sameGameTrisGUI.score(SelfAwareCircle.getRegionLength(), getColor())));

			// request that the board be shifted appropriately
			sameGameTrisGUI.shiftCircles();

			if (sameGameTrisGUI.shiftCircles()) { // if shifting concluded without ending the game
				// update Tetrising
				sameGameTrisGUI.updateNumClicks();
			sameGameTrisGUI.updateTetrising();
				if (!sameGameTrisGUI.isTetrisingQ())
					sameGameTrisGUI.restartTetrising();
			}

		}