ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/Microscope.java
(Generate patch)

Comparing jsr166/src/test/loops/Microscope.java (file contents):
Revision 1.1 by dl, Sun Sep 19 12:55:37 2010 UTC vs.
Revision 1.17 by jsr166, Thu Sep 15 06:45:56 2016 UTC

# Line 1 | Line 1
1   /*
2   * Written by Doug Lea with assistance from members of JCP JSR-166
3   * Expert Group and released to the public domain, as explained at
4 < * http://creativecommons.org/licenses/publicdomain
4 > * http://creativecommons.org/publicdomain/zero/1.0/
5   */
6  
7   import java.awt.*;
8 import javax.swing.*;
9 import java.util.*;
8   import java.awt.event.*;
9 < import javax.swing.event.*;
9 > import java.util.*;
10   import java.util.concurrent.*;
11 <
11 > import javax.swing.*;
12 > import javax.swing.event.*;
13  
14   /**
15   * Microscope implements a version of the 7th Guest
# Line 18 | Line 17 | import java.util.concurrent.*;
17   * See <a href="http://gee.cs.oswego.edu/dl/applets/micro.html">
18   * Microscope</a> version for instructions.
19   * <p>
20 < * The code has been mangled beyond recognition
21 < * as a test of ForkJoin
22 < **/
24 <
20 > * The code has been mangled beyond recognition
21 > * as a test of ForkJoin.
22 > */
23   public class Microscope extends JPanel {
24  
25      static final CountDownLatch cd = new CountDownLatch(1);
# Line 72 | Line 70 | public class Microscope extends JPanel {
70          System.exit(0);
71      }
72  
73 <    static void onExit() {
73 >    static void onExit() {
74          long now = System.currentTimeMillis();
75          System.out.println("time: " + (now - startTime) + "ms");
76          System.out.println(group.toString());
77          System.exit(0);
78 <    }        
79 <    
78 >    }
79 >
80      static void oneRun() {
81          if (java.awt.GraphicsEnvironment.isHeadless()) {
82              headless = true;
# Line 89 | Line 87 | public class Microscope extends JPanel {
87              JFrame frame = new JFrame();
88              frame.addWindowListener(new WindowAdapter() {
89                      public void windowClosing(WindowEvent e) {onExit();}});
90 <            
90 >
91              Microscope t = new Microscope();
92              frame.setSize(new Dimension(400, 400));
93              frame.getContentPane().add(t);
# Line 104 | Line 102 | public class Microscope extends JPanel {
102      Board board = new Board();        // The current board representation
103  
104      synchronized Board getBoard() { return board; }
105 <    synchronized void  setBoard(Board b) {
106 <        board = b;
105 >    synchronized void  setBoard(Board b) {
106 >        board = b;
107          System.out.print(b.score(player) + " ");
108          if (boardPanel != null)
109 <            boardPanel.repaint();
109 >            boardPanel.repaint();
110      }
111  
112      Player player = Player.Blue;      // current player (BLUE, GREEN)
# Line 116 | Line 114 | public class Microscope extends JPanel {
114      synchronized Player getPlayer() { return player; }
115      synchronized void setPlayer(Player p) { player = p; }
116  
119
117      final AutoMover auto;                  // The move finder.
118      final User user;                       // Mover for user moves
119      Mover mover = null;    // the current Mover (always == auto or user or null)
# Line 140 | Line 137 | public class Microscope extends JPanel {
137      JButton modeButton;
138      JSlider levelSlider;
139  
140 <    public Microscope() {  
140 >    public Microscope() {
141          if (headless) {
142              boardPanel = null;
143              auto = new AutoMover(this);
# Line 166 | Line 163 | public class Microscope extends JPanel {
163                      }
164                      else {
165                          stopMover();
166 <                        if (getDemoMode())
166 >                        if (getDemoMode())
167                              autoButton.setText(" Start ");
168                          else
169                              autoButton.setText(" Find ");
# Line 177 | Line 174 | public class Microscope extends JPanel {
174                  public synchronized void actionPerformed(ActionEvent e) {
175                      toggleDemoMode();
176                      updateStatus();
180
177                  }});
178  
179          undoButton.addActionListener(new ActionListener() {
180                  public void actionPerformed(ActionEvent e) {
181                      undo();
182                  }});
183 <
183 >
184          levelSlider.addChangeListener(new ChangeListener() {
185                  public void stateChanged(ChangeEvent e) {
186                      setLevel(((JSlider)(e.getSource())).getValue());
# Line 194 | Line 190 | public class Microscope extends JPanel {
190          //        Dimension labDim = new Dimension(72, 24);
191          //        scoreLabel.setMinimumSize(labDim);
192          //        scoreLabel.setPreferredSize(labDim);
197    
193  
194          topPanel.add(autoButton);
195          topPanel.add(modeButton);
196          topPanel.add(undoButton);
197          topPanel.add(scoreLabel);
198          add(topPanel);
204    
199  
200          levelSlider.setLabelTable(levelSlider.createStandardLabels(1));
201          levelSlider.setPaintLabels(true);
# Line 215 | Line 209 | public class Microscope extends JPanel {
209          sliderPanel.add(new JLabel("Level"));
210  
211          botPanel.add(sliderPanel);
212 <    
212 >
213          add(botPanel);
214      }
215  
# Line 230 | Line 224 | public class Microscope extends JPanel {
224              boardPanel.repaint();
225      }
226  
227 <    public void init()  {
227 >    public void init() {
228          initializeBoard();
229          if (autostart) {
230              startMover(auto);
231          }
232      }
233  
240
234      synchronized void setLevel(int l) {
235          lookAheads = l;
236          if (lookAheads <= 1) lookAheads = 2;
237      }
245    
246    public int level () { return Microscope.lookAheads; }
247    
238  
239 <    // process a move (called only from mover)
239 >    public int level() { return Microscope.lookAheads; }
240  
241 +    // process a move (called only from mover)
242      public void move(Move m, Mover mvr) {
243 <        if (mvr != mover ||
243 >        if (mvr != mover ||
244              m == null ||
245              (mvr == user && !m.isLegal())) {
246              setMover(null);
# Line 265 | Line 256 | public class Microscope extends JPanel {
256  
257              history.addElement(m);
258  
259 <            if (mvr == auto &&
260 <                getDemoMode() &&
259 >            if (mvr == auto &&
260 >                getDemoMode() &&
261                  !m.isPass()) {
262                  if (getBoard().gameOver()) {
263                      if (autostart) {
# Line 303 | Line 294 | public class Microscope extends JPanel {
294              mvr.cancel();
295          }
296      }
306
297  
298      // handle Undo button
299      synchronized void undo() {
# Line 326 | Line 316 | public class Microscope extends JPanel {
316          startMover(user);
317          user.choose(row, col);
318      }
319 <  
319 >
320      void updateStatus() { // normally called from board update
321          Player p = getPlayer();
322          int s = getBoard().score(p);
# Line 334 | Line 324 | public class Microscope extends JPanel {
324              System.out.print(s + " ");
325              return;
326          }
327 <        
327 >
328          scoreLabel.setForeground(displayColor(p));
329          scoreLabel.setText("Score: " +  s);
330  
331 <        if (getDemoMode())
331 >        if (getDemoMode())
332              modeButton.setText("Demo  mode");
333          else {
334              if (getPlayer().isBlue())
# Line 349 | Line 339 | public class Microscope extends JPanel {
339  
340      }
341  
342 +    static final int CELL_SIZE = 40; // size of a tile/cell
343  
353    static final int CELL_SIZE = 40; // size of a tile/cell
354  
344      static final Color paleGreen = new Color(152, 251, 152);
345      static final Color darkGreen = new Color(60, 179, 113);
346 <    
346 >
347      static final Color possibleMoveColor = Color.yellow;
359    
348  
349      public static Color displayColor(Player pl) {
350          if (pl.isBlue()) return Color.blue;
# Line 370 | Line 358 | public class Microscope extends JPanel {
358          else return Color.gray;
359      }
360  
373
361      class BoardPanel extends Canvas implements MouseListener {
362 <    
363 <        BoardPanel() {
364 <            setSize(new Dimension(Board.RANKS * CELL_SIZE + 5,
362 >
363 >        BoardPanel() {
364 >            setSize(new Dimension(Board.RANKS * CELL_SIZE + 5,
365                                    Board.RANKS * CELL_SIZE + 5));
366              addMouseListener(BoardPanel.this);
367          }
368 <    
368 >
369          public void paint(Graphics g) {
370 <      
370 >
371              Board b = getBoard();
372              Player p = getPlayer();
373 <      
373 >
374              // the cells
375              for (int row = 0; row < Board.RANKS; row++) {
376                  for (int col = 0; col < Board.RANKS; col++) {
377 <          
377 >
378                      // Highlight selected tile and legal destinations
379                      if (user.placing()) {
380 <                        if (user.hasMovedFrom(row, col))
380 >                        if (user.hasMovedFrom(row, col))
381                              g.setColor(lightDisplayColor(p));
382                          else if (user.canMoveTo(row, col))
383                              g.setColor(possibleMoveColor);
384                          else
385                              g.setColor(displayColor(b.occupant(row, col)));
386                      }
387 <          
387 >
388                      else
389                          g.setColor(displayColor(b.occupant(row, col)));
390 <          
390 >
391                      // tiles are just filled rectangles
392                      g.fillRect(row * CELL_SIZE, col * CELL_SIZE, CELL_SIZE, CELL_SIZE);
393                  }
394              }
395 <      
395 >
396              // the grid over the cells
397              g.setColor(Color.black);
398              for ( int i = 0; i <= Board.RANKS; i++) {
399                  g.drawLine(0, i * CELL_SIZE, Board.RANKS * CELL_SIZE, i * CELL_SIZE);
400                  g.drawLine(i * CELL_SIZE, 0, i * CELL_SIZE, Board.RANKS * CELL_SIZE);
401              }
402 <      
402 >
403              updateStatus();
404          }
405 <    
405 >
406          public void mouseReleased(MouseEvent evt) {
407 <      
407 >
408              int x = evt.getX();
409              int y = evt.getY();
410 <      
410 >
411              int row = x / CELL_SIZE;
412              int col = y / CELL_SIZE;
413 <      
413 >
414              if (Board.inBounds(row, col)) { // cell selection
415                  userMove(row, col);
416                  repaint();
417              }
418          }
419 <    
419 >
420          public void mouseClicked(MouseEvent e) {}
421          public void mousePressed(MouseEvent e) {}
422          public void mouseEntered(MouseEvent e) {}
# Line 438 | Line 425 | public class Microscope extends JPanel {
425  
426      /**
427       *  Player is just a glorified enumeration
428 <     **/
442 <
428 >     */
429      static final class Player {
430  
431          public static final int EMPTY = 0;
432          public static final int BLUE = 1;
433          public static final int GREEN = 2;
434          public static final int ILLEGAL_PLAYER_VALUE = 3;
435 <    
435 >
436          public static final Player Empty   = new Player(EMPTY);
437          public static final Player Blue    = new Player(BLUE);
438          public static final Player Green   = new Player(GREEN);
439          public static final Player Illegal = new Player(ILLEGAL_PLAYER_VALUE);
440 <    
440 >
441          /* private */ int code_;
442 <    
442 >
443          public Player(int code)       { code_ = code; }
444          public Player(Player p)       { code_ = p.code_; }
445 <    
445 >
446          public boolean same(Player p) { return code_ == p.code_; }
447 <    
447 >
448          public boolean isEmpty()      { return code_ == EMPTY; }
449          public boolean isBlue()       { return code_ == BLUE; }
450          public boolean isGreen()      { return code_ == GREEN; }
451          public boolean isLegal()      { return code_ <= GREEN; }
452 <    
453 <        public Player opponent() {
452 >
453 >        public Player opponent() {
454              if (code_ == GREEN) return Blue;
455              else if (code_ == BLUE) return Green;
456              else return Illegal;
457          }
458 <    
458 >
459      }
460 <  
460 >
461      /**
462       *   Board configurations are represented by bit vectors.
463       *   Since there are only 49 cells, the bits can be held in `longs',
# Line 480 | Line 466 | public class Microscope extends JPanel {
466       * Boards are not immutable, but are never passed around across
467       * threads (instead new ones are constructed), so don't
468       * need any synch.
469 <     **/
470 <  
485 <    static final class Board   {
469 >     */
470 >    static final class Board {
471  
472 <        /*
472 >        /*
473             First, some Constants and utilities that might as well be here
474          */
475 <    
475 >
476          public static final int RANKS = 7;
477          public static final int CELLS = RANKS * RANKS;
478 <    
478 >
479          static final long FULL = (1L << CELLS) - 1;
480 <    
480 >
481          // The finder uses a spare bit to remember whose move it is.
482          static final long BLUEBIT = (1L << CELLS);
483 <    
483 >
484          // Bits representing the adjacent cells for every position
485          static final long[] adjacentMasks = new long[CELLS];
486 <    
486 >
487          // bit pattern associated with each tile
488          static final long[] cellBits = new long[CELLS];
489  
# Line 537 | Line 522 | public class Microscope extends JPanel {
522              }
523  
524          }
525 <    
541 <    
525 >
526          public static boolean inBounds(int row, int col) {
527 <            return (0 <= row)  && (row < RANKS) && (0 <= col) && (col < RANKS);
527 >            return (0 <= row) && (row < RANKS) && (0 <= col) && (col < RANKS);
528          }
529 <    
529 >
530          // The representation
531 <    
531 >
532          long blue_;      // bit vector; true if occupied by blue
533          long green_;     // same for green;
534 <    
534 >
535          // constructors and intializers:
536 <    
536 >
537          public Board()               { blue_ = 0L; green_ = 0L; }
538          public Board(Board b)        { blue_ = b.blue_; green_ = b.green_; }
539          public Board(long b, long g) { blue_ = b; green_ = g; }
540 <    
540 >
541          public void copyState(Board b) {
542 <            blue_ = b.blue_;
543 <            green_ = b.green_;
542 >            blue_ = b.blue_;
543 >            green_ = b.green_;
544          }
545  
546 <        void reset() {
547 <            blue_ = 0L; green_ = 0L;
546 >        void reset() {
547 >            blue_ = 0L; green_ = 0L;
548          }
549 <    
549 >
550          long getBlue() { return blue_; }
551          long getGreen() { return green_; }
552  
569
553          public Player occupant(int row, int col) {
554 <            if ((0 <= row)  && (row < RANKS) && (0 <= col) && (col < RANKS)) {
554 >            if ((0 <= row) && (row < RANKS) && (0 <= col) && (col < RANKS)) {
555                  long m = 1L << (row + col * RANKS);
556                  if ((blue_ & m) != 0L) return Player.Blue;
557                  else if ((green_ &m) != 0L) return Player.Green;
# Line 577 | Line 560 | public class Microscope extends JPanel {
560              else
561                  return Player.Illegal;
562          }
563 <    
564 <    
582 <        // place a tile without taking opponent tiles
583 <    
563 >
564 >        /** Places a tile without taking opponent tiles. */
565          public void occupy(Player player, int row, int col) {
566              long m = 1L << (row + col * RANKS);
567              long nm = ~m;
568 <            if (player.code_ == Player.BLUE)  {
568 >            if (player.code_ == Player.BLUE) {
569                  blue_ |= m;
570                  green_ &= nm;
571              }
572 <            else if (player.code_ == Player.GREEN) {
572 >            else if (player.code_ == Player.GREEN) {
573                  blue_ &=  nm;
574                  green_ |= m;
575              }
576 <            else {
576 >            else {
577                  blue_ &= nm;
578                  green_ &= nm;
579              }
580          }
581 <    
581 >
582          public void unoccupy(int row, int col) {
583              long nm = ~(1L << (row + col * RANKS));
584              blue_ &=  nm;
585              green_ &= nm;
586          }
587 <    
588 <    
608 <    
609 <        // place a tile, taking all adjacent tiles of opponent
610 <    
587 >
588 >        /** Places a tile, taking all adjacent tiles of opponent. */
589          public void take(Player player, int row, int col) {
590 <            int k =  (row + col * RANKS);
590 >            int k = row + col * RANKS;
591              long dest = 1L << k;
592              long nbrMask = adjacentMasks[k];
593              long sourceBlue = blue_;
# Line 620 | Line 598 | public class Microscope extends JPanel {
598              }
599              else {
600                  blue_ = sourceBlue & ~(sourceBlue & nbrMask);
601 <                green_ =  sourceGreen | dest | (sourceBlue & nbrMask);
601 >                green_ = sourceGreen | dest | (sourceBlue & nbrMask);
602              }
603          }
604 <    
604 >
605          public boolean gameOver() {
606 <            return
606 >            return
607                  (((blue_ | green_) & FULL) == FULL) ||
608                  ((blue_ & ~BLUEBIT) == 0) ||
609                  ((green_ & ~BLUEBIT) == 0);
610          }
611 <    
634 <    
611 >
612          public int score(Player player) {
613              if (player.isBlue()) {
614                  return score(blue_, green_);
# Line 640 | Line 617 | public class Microscope extends JPanel {
617                  return score(green_, blue_);
618              }
619          }
620 <    
620 >
621          static int score(long b, long g) {
622 <      
622 >
623              // much faster by splitting into ints
624              // and using clever shift-based bit counter
625 <      
625 >
626              int lb = (int)(b & ((1L << 32) - 1));
627              int hb = ((int)(b >>> 32)) & ((1 << (CELLS - 32)) - 1);
628  
# Line 680 | Line 657 | public class Microscope extends JPanel {
657  
658              return hb - ((lg + hg) & 0xff);
659          }
660 <    
684 <    
685 <    
660 >
661          static int slowscore(long b, long g) {
662              int score = 0;
663              for (int l = 0; l < CELLS; ++l) {
# Line 693 | Line 668 | public class Microscope extends JPanel {
668              }
669              return score;
670          }
696  
697    
671      }
672 <  
672 >
673      /**
674       * Moves represent transitions across Board states
675 <     **/
676 <
704 <
705 <    static final class Move  {
675 >     */
676 >    static final class Move {
677  
678          static final int NO_VALUE = -1;     // row/col value if not yet set
679          static final int PASS_VALUE = -2;   // special value for pass moves
680 <    
680 >
681          // utilities for classifying moves
682 <    
683 <        public static boolean twoFrom(int a, int b) {
684 <            return (a - b == 2) || (b - a == 2);
682 >
683 >        public static boolean twoFrom(int a, int b) {
684 >            return (a - b == 2) || (b - a == 2);
685          }
686 <    
687 <        public static boolean withinTwo(int a, int b) {
686 >
687 >        public static boolean withinTwo(int a, int b) {
688              int diff = a - b; return -2 <= diff && diff <= 2;
689          }
690 <    
690 >
691          // representations
692 <    
692 >
693          int fromRow;
694          int fromCol;
695 <    
695 >
696          int toRow;
697          int toCol;
698 <    
698 >
699          Player player_;
700          Board board_;
701 <    
701 >
702          boolean committed = false; // true if board reflects move
703 <    
703 >
704          // constructors and intializers
705 <    
706 <        public Move(Player turn, Board board) {
705 >
706 >        public Move(Player turn, Board board) {
707              fromRow = NO_VALUE; fromCol = NO_VALUE;
708              toRow = NO_VALUE;   toCol = NO_VALUE;
709              player_ = turn;
710              board_ = board;
711          }
712 <    
713 <        public Move(Player turn, Board board, boolean isCommitted) {
712 >
713 >        public Move(Player turn, Board board, boolean isCommitted) {
714              fromRow = NO_VALUE; fromCol = NO_VALUE;
715              toRow = NO_VALUE;   toCol = NO_VALUE;
716              player_ = turn;
717              board_ = board;
718              committed = isCommitted;
719          }
720 <    
720 >
721          synchronized void reset() {
722              fromRow = NO_VALUE;
723              fromCol = NO_VALUE;
724              toRow = NO_VALUE;
725              toCol = NO_VALUE;
726          }
727 <    
727 >
728          // setters:
729 <    
730 <        synchronized void player(Player p)       { player_ = p;  }
731 <        synchronized void board(Board b)         { board_ = b;  }
732 <        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc;  }
729 >
730 >        synchronized void player(Player p)       { player_ = p; }
731 >        synchronized void board(Board b)         { board_ = b; }
732 >        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc; }
733          synchronized void to(int dr, int dc)     { toRow = dr;   toCol = dc; }
734 <  
734 >
735          //  accessors:
736 <    
737 <        synchronized boolean isFrom(int r, int c) {
738 <            return fromRow== r && fromCol == c;
736 >
737 >        synchronized boolean isFrom(int r, int c) {
738 >            return fromRow== r && fromCol == c;
739          }
740 <        synchronized boolean isTo(int r, int c)   {
741 <            return toRow == r && toCol == c;
740 >        synchronized boolean isTo(int r, int c) {
741 >            return toRow == r && toCol == c;
742          }
743 <        synchronized Board board() {
744 <            return board_;
743 >        synchronized Board board() {
744 >            return board_;
745          }
746 <        synchronized Player player() {
747 <            return player_;
746 >        synchronized Player player() {
747 >            return player_;
748          }
749 <    
749 >
750  
751          // status checks:
752 <    
752 >
753          synchronized boolean isPass() { // is this a `pass' move?
754              return (toRow == PASS_VALUE || fromRow == PASS_VALUE);
755          }
756 <    
756 >
757          synchronized boolean isJump() {
758 <            return
758 >            return
759                  (fromRow - toRow == 2) || (toRow - fromRow == 2) ||
760                  (fromCol - toCol == 2) || (toCol - fromCol == 2);
761          }
762 <    
762 >
763          synchronized boolean hasFrom() { // is from set?
764              return fromRow != NO_VALUE && fromCol != NO_VALUE;
765          }
766 <    
766 >
767          synchronized boolean hasTo() { // is to set?
768              return toRow != NO_VALUE && toCol != NO_VALUE;
769          }
770 <    
800 <    
770 >
771          synchronized boolean possibleTo(int r, int c) { // is (r, c) a legal `to'?
772              return hasFrom() &&
773                  withinTwo(fromRow, r) &&
774                  withinTwo(fromCol, c) &&
775                  board_.occupant(r, c).isEmpty();
776          }
777 <    
777 >
778          synchronized boolean isLegal() {
779 <            if (isPass())
779 >            if (isPass())
780                  return true;
781 <            else if (!board_.occupant(toRow, toCol).isEmpty())
781 >            else if (!board_.occupant(toRow, toCol).isEmpty())
782                  return false;
783 <            else if (!board_.occupant(fromRow, fromCol).same(player_))
783 >            else if (!board_.occupant(fromRow, fromCol).same(player_))
784                  return false;
785 <            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
785 >            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
786                  return false;
787              else
788                  return true;
789          }
790 <    
790 >
791          synchronized void commit() { // update board to reflect move
792              if (!committed) {
793                  committed = true;
794 <                if (isLegal() && !isPass())  {
794 >                if (isLegal() && !isPass()) {
795                      if (isJump()) board_.occupy(Player.Empty, fromRow, fromCol);
796                      board_.take(player_, toRow, toCol);
797                  }
798              }
799          }
800 <    
800 >
801      }
802 <  
802 >
803      /**
804       *  Mover is an abstract class to simplify code dealing with
805       *  either user moves or auto moves.
806 <     **/
807 <  
806 >     */
807 >    abstract static class Mover {
808  
839    static abstract class Mover {
840    
809          // caller for move callbacks
810          protected Microscope game;
811 <    
811 >
812          protected Mover(Microscope ap) { game = ap; }
813 <    
813 >
814          // start a turn as player on given board
815          public abstract void startTurn(Board b, Player p);
816 <    
816 >
817          // cancel current partial move
818          public abstract void cancel();
819 <    
819 >
820          // return true if move not yet ready
821          public abstract boolean placing();
822 <    
822 >
823      }
856  
857    /**
858     *  User builds moves via instructions/clicks by users
859     **/
824  
825 +    /**
826 +     * User builds moves via instructions/clicks by users
827 +     */
828      static class User extends Mover {
829  
830          private Move current;
831 <    
831 >
832          public User(Microscope ap) { super(ap); current = null; }
833 <    
833 >
834          public synchronized void startTurn(Board b, Player p) {
835              current = new Move(p, b);
836          }
837 <    
838 <        public boolean placing() {
839 <            return current != null && current.hasFrom() && !current.hasTo();
837 >
838 >        public boolean placing() {
839 >            return current != null && current.hasFrom() && !current.hasTo();
840          }
841 <    
842 <        public synchronized void cancel() {
841 >
842 >        public synchronized void cancel() {
843              if (current != null) {
844 <                current.reset();
845 <                current = null;
844 >                current.reset();
845 >                current = null;
846              }
847          }
848 <    
848 >
849          public synchronized void choose(int row, int col) {
850              if (current != null) {
851                  if (row == Move.PASS_VALUE) {
# Line 898 | Line 865 | public class Microscope extends JPanel {
865                  }
866              }
867          }
868 <    
868 >
869          public synchronized boolean canMoveTo(int row, int col) {
870              return placing() && current.possibleTo(row, col);
871          }
872 <    
872 >
873          public synchronized boolean hasMovedFrom(int row, int col) {
874              return current != null && current.isFrom(row, col);
875          }
909    
910    }
876  
877 +    }
878  
879      /**
880 <     *     AutoMover constructs Finders that compute actual moves
881 <     **/
916 <
880 >     * AutoMover constructs Finders that compute actual moves
881 >     */
882      static class AutoMover extends Mover {
883  
884          boolean cancelled = false;
# Line 922 | Line 887 | public class Microscope extends JPanel {
887          public AutoMover(Microscope ap) {
888              super(ap);
889          }
890 <  
891 <    
892 <        public synchronized boolean placing() {
928 <            return currentFinder != null;
890 >
891 >        public synchronized boolean placing() {
892 >            return currentFinder != null;
893          }
894  
895 <        synchronized void stopPlacing() {
895 >        synchronized void stopPlacing() {
896              currentFinder = null;
897          }
898 <    
935 <    
898 >
899          public synchronized void cancel() {
900 <            if (placing())  {
900 >            if (placing()) {
901                  currentFinder.cancel(false);
902                  stopPlacing();
903              }
# Line 942 | Line 905 | public class Microscope extends JPanel {
905  
906          public synchronized void startTurn(Board board, Player player) {
907              if (!placing()) {
908 <                currentFinder = new RootFinder(board, player,
908 >                currentFinder = new RootFinder(board, player,
909                                                 Microscope.lookAheads, this);
910                  group.execute(currentFinder);
911              }
912          }
913 <    
913 >
914          synchronized void relay(Move move) { // relay callback from finder
915              if (placing()) {
916                  stopPlacing();
917                  game.move(move, this);
918              }
919          }
920 <    
920 >
921      }
959  
922  
923      /**
924 <     * Implements a classic all-possible-move search algorith using
924 >     * Implements a classic all-possible-move search algorithm using
925       * ForkJoinTasks.  The move finder is not all that smart. Among
926       * other possible improvements, it could keep a cache of explored
927       * moves and avoid repeating them. This would likely speed it up
928       * since most expansions are duplicates of others. It could also
929       * be changed to prune moves, although this is unlikely to work
930       * well without better partial evaluation functions.
931 <     **/
970 <  
931 >     */
932      static class Finder extends RecursiveAction {
933  
934          static final int NOMOVE = Integer.MIN_VALUE;
935          static final int LOSE   = NOMOVE+1;
936          static final int WIN    = -LOSE;
937 <    
937 >
938          final long ours;     // bits for our tiles
939          final long theirs;   // bits for opponent tiles
940          final int level;     // current number of lookAheads
# Line 992 | Line 953 | public class Microscope extends JPanel {
953          protected final void compute() {
954  
955              // Handle sure wins and losses here
956 <            if ((ours & ~Board.BLUEBIT) == 0)  
956 >            if ((ours & ~Board.BLUEBIT) == 0)
957                  bestScore = LOSE;
958  
959 <            else if ((theirs & ~Board.BLUEBIT) == 0)
959 >            else if ((theirs & ~Board.BLUEBIT) == 0)
960                  bestScore = WIN;
961  
962              else if (((ours | theirs) & Board.FULL) == Board.FULL) {
# Line 1005 | Line 966 | public class Microscope extends JPanel {
966                  else bestScore = 0;
967              }
968  
969 <            else
969 >            else
970                  search();
971          }
1011    
972  
973          final void search() {
974              int best = NOMOVE;    // For direct evaluation when level == 1
975              Finder forked = null; // list of forked subtasks when level > 1
976 <      
976 >
977              long open = ~(ours | theirs);  // currently empty cells
978 <            long here = 1;                 // travserse through bits
979 <      
978 >            long here = 1;                 // traverse through bits
979 >
980              for (int k = 0; k < Board.CELLS; ++k, here <<= 1) {
981                  if ((here & ours) != 0) {
982                      /*
# Line 1027 | Line 987 | public class Microscope extends JPanel {
987                      for (int j = 0; j < dests.length; ++j) {
988                          byte d = dests[j];
989                          long dest = 1L << d;
990 <                        
990 >
991                          if ( (dest & open) != 0) {
992                              long adjacent = Board.adjacentMasks[d];
993                              long nTheirs = theirs & ~adjacent;
994                              long nOurs = (ours & ~here) | dest | (theirs & adjacent);
995  
996 <                            if (level > 1)
997 <                                (forked =
996 >                            if (level > 1)
997 >                                (forked =
998                                   new Finder(nTheirs, nOurs, level-1, forked)).fork();
999                              else {
1000                                  int sc = Board.score(nOurs, nTheirs);
# Line 1054 | Line 1014 | public class Microscope extends JPanel {
1014                      if ((ours & adjacent) != 0) {
1015                          long nTheirs = theirs & ~adjacent;
1016                          long nOurs = ours | here | (theirs & adjacent);
1017 <                        if (level > 1)
1017 >                        if (level > 1)
1018                              (forked = new Finder(nTheirs, nOurs, level-1, forked)).fork();
1019                          else {
1020                              int sc = Board.score(nOurs, nTheirs);
# Line 1072 | Line 1032 | public class Microscope extends JPanel {
1032  
1033          /**
1034           * Join all subtasks and evaluate moves. Default is sub-finder version.
1035 <         * Overridden in RootFinder
1036 <         **/
1077 <
1035 >         * Overridden in RootFinder.
1036 >         */
1037          void collect(Finder forked) {
1038              int best = NOMOVE;
1039              while (forked != null) {
1040 <                while (!forked.isDone()) {
1041 <                    // interleave joins with status checks                    
1040 >                while (!forked.isDone()) {
1041 >                    // interleave joins with status checks
1042                      if (isDone()) {
1043                          cancelAll(forked);
1044                          return;
# Line 1105 | Line 1064 | public class Microscope extends JPanel {
1064          }
1065  
1066          /**
1067 <         * Cancel all forked subtasks in list
1068 <         **/
1110 <
1067 >         * Cancels all forked subtasks in list.
1068 >         */
1069          void cancelAll(Finder forked) {
1070              while (forked != null) {
1071                  forked.cancel(false);
# Line 1119 | Line 1077 | public class Microscope extends JPanel {
1077  
1078      /**
1079       * Root Finder class -- wait out other finders and issue callback to game.
1080 <     **/
1123 <
1080 >     */
1081      static class RootFinder extends Finder {
1082 <        final AutoMover automover;
1082 >        final AutoMover automover;
1083          final Player player;
1084          RootFinder(Board board, Player p, int level, AutoMover automover) {
1085 <            super( (p.isBlue()? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1086 <                   (p.isBlue()? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1085 >            super( (p.isBlue() ? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1086 >                   (p.isBlue() ? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1087                     level,
1088                     null);
1089 <            
1089 >
1090              this.player = p;
1091              this.automover = automover;
1092          }
1093  
1137
1094          /**
1095           * This differs from default version by recording
1096           * and calling back with best move
1097 <         **/
1097 >         */
1098          void collect(Finder forked) {
1099              int best = NOMOVE;
1100              Finder bestFinder = null;
# Line 1163 | Line 1119 | public class Microscope extends JPanel {
1119                          break;
1120                      }
1121                  }
1122 <        
1122 >
1123                  // Just for fun, introduce a little randomness via hashcodes
1124                  else if (score == best &&
1125                           !Microscope.DETERMINISTIC &&
1126 <                         (System.identityHashCode(forked) >
1126 >                         (System.identityHashCode(forked) >
1127                            System.identityHashCode(bestFinder))) {
1128                      bestFinder = forked;
1129                  }
1130                  forked = forked.next;
1131              }
1132 <      
1132 >
1133              Move move = null;
1134              if (bestFinder != null) {
1135 <                /*
1135 >                /*
1136                     Even though accessed here,
1137                     the ours and theirs vars of Finders do not
1138                     need to be volatile because they are immutably
1139                     established in constructors.
1140                  */
1141 <        
1141 >
1142                  long nextOurs = bestFinder.theirs;
1143                  long nextTheirs = bestFinder.ours;
1144 <                long blue = (player.isBlue())? nextOurs : nextTheirs;
1145 <                long green = (player.isBlue())? nextTheirs: nextOurs;
1144 >                long blue = player.isBlue() ? nextOurs : nextTheirs;
1145 >                long green = player.isBlue() ? nextTheirs : nextOurs;
1146                  move = new Move(player, new Board(blue, green), true);
1147              }
1148              automover.relay(move);
1149          }
1150      }
1195
1196  
1151   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines