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.15 by jsr166, Mon Aug 10 03:13:33 2015 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);
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)) {
555                  long m = 1L << (row + col * RANKS);
# Line 577 | Line 560 | public class Microscope extends JPanel {
560              else
561                  return Player.Illegal;
562          }
563 <    
564 <    
563 >
564 >
565          // place a tile without taking opponent tiles
583    
566          public void occupy(Player player, int row, int col) {
567              long m = 1L << (row + col * RANKS);
568              long nm = ~m;
569 <            if (player.code_ == Player.BLUE)  {
569 >            if (player.code_ == Player.BLUE) {
570                  blue_ |= m;
571                  green_ &= nm;
572              }
573 <            else if (player.code_ == Player.GREEN) {
573 >            else if (player.code_ == Player.GREEN) {
574                  blue_ &=  nm;
575                  green_ |= m;
576              }
577 <            else {
577 >            else {
578                  blue_ &= nm;
579                  green_ &= nm;
580              }
581          }
582 <    
582 >
583          public void unoccupy(int row, int col) {
584              long nm = ~(1L << (row + col * RANKS));
585              blue_ &=  nm;
586              green_ &= nm;
587          }
588 <    
607 <    
608 <    
588 >
589          // place a tile, taking all adjacent tiles of opponent
610    
590          public void take(Player player, int row, int col) {
591 <            int k =  (row + col * RANKS);
591 >            int k = row + col * RANKS;
592              long dest = 1L << k;
593              long nbrMask = adjacentMasks[k];
594              long sourceBlue = blue_;
# Line 620 | Line 599 | public class Microscope extends JPanel {
599              }
600              else {
601                  blue_ = sourceBlue & ~(sourceBlue & nbrMask);
602 <                green_ =  sourceGreen | dest | (sourceBlue & nbrMask);
602 >                green_ = sourceGreen | dest | (sourceBlue & nbrMask);
603              }
604          }
605 <    
605 >
606          public boolean gameOver() {
607 <            return
607 >            return
608                  (((blue_ | green_) & FULL) == FULL) ||
609                  ((blue_ & ~BLUEBIT) == 0) ||
610                  ((green_ & ~BLUEBIT) == 0);
611          }
612 <    
634 <    
612 >
613          public int score(Player player) {
614              if (player.isBlue()) {
615                  return score(blue_, green_);
# Line 640 | Line 618 | public class Microscope extends JPanel {
618                  return score(green_, blue_);
619              }
620          }
621 <    
621 >
622          static int score(long b, long g) {
623 <      
623 >
624              // much faster by splitting into ints
625              // and using clever shift-based bit counter
626 <      
626 >
627              int lb = (int)(b & ((1L << 32) - 1));
628              int hb = ((int)(b >>> 32)) & ((1 << (CELLS - 32)) - 1);
629  
# Line 680 | Line 658 | public class Microscope extends JPanel {
658  
659              return hb - ((lg + hg) & 0xff);
660          }
661 <    
684 <    
685 <    
661 >
662          static int slowscore(long b, long g) {
663              int score = 0;
664              for (int l = 0; l < CELLS; ++l) {
# Line 693 | Line 669 | public class Microscope extends JPanel {
669              }
670              return score;
671          }
696  
697    
672      }
673 <  
673 >
674      /**
675       * Moves represent transitions across Board states
676 <     **/
677 <
704 <
705 <    static final class Move  {
676 >     */
677 >    static final class Move {
678  
679          static final int NO_VALUE = -1;     // row/col value if not yet set
680          static final int PASS_VALUE = -2;   // special value for pass moves
681 <    
681 >
682          // utilities for classifying moves
683 <    
684 <        public static boolean twoFrom(int a, int b) {
685 <            return (a - b == 2) || (b - a == 2);
683 >
684 >        public static boolean twoFrom(int a, int b) {
685 >            return (a - b == 2) || (b - a == 2);
686          }
687 <    
688 <        public static boolean withinTwo(int a, int b) {
687 >
688 >        public static boolean withinTwo(int a, int b) {
689              int diff = a - b; return -2 <= diff && diff <= 2;
690          }
691 <    
691 >
692          // representations
693 <    
693 >
694          int fromRow;
695          int fromCol;
696 <    
696 >
697          int toRow;
698          int toCol;
699 <    
699 >
700          Player player_;
701          Board board_;
702 <    
702 >
703          boolean committed = false; // true if board reflects move
704 <    
704 >
705          // constructors and intializers
706 <    
707 <        public Move(Player turn, Board board) {
706 >
707 >        public Move(Player turn, Board board) {
708              fromRow = NO_VALUE; fromCol = NO_VALUE;
709              toRow = NO_VALUE;   toCol = NO_VALUE;
710              player_ = turn;
711              board_ = board;
712          }
713 <    
714 <        public Move(Player turn, Board board, boolean isCommitted) {
713 >
714 >        public Move(Player turn, Board board, boolean isCommitted) {
715              fromRow = NO_VALUE; fromCol = NO_VALUE;
716              toRow = NO_VALUE;   toCol = NO_VALUE;
717              player_ = turn;
718              board_ = board;
719              committed = isCommitted;
720          }
721 <    
721 >
722          synchronized void reset() {
723              fromRow = NO_VALUE;
724              fromCol = NO_VALUE;
725              toRow = NO_VALUE;
726              toCol = NO_VALUE;
727          }
728 <    
728 >
729          // setters:
730 <    
731 <        synchronized void player(Player p)       { player_ = p;  }
732 <        synchronized void board(Board b)         { board_ = b;  }
733 <        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc;  }
730 >
731 >        synchronized void player(Player p)       { player_ = p; }
732 >        synchronized void board(Board b)         { board_ = b; }
733 >        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc; }
734          synchronized void to(int dr, int dc)     { toRow = dr;   toCol = dc; }
735 <  
735 >
736          //  accessors:
737 <    
738 <        synchronized boolean isFrom(int r, int c) {
739 <            return fromRow== r && fromCol == c;
737 >
738 >        synchronized boolean isFrom(int r, int c) {
739 >            return fromRow== r && fromCol == c;
740          }
741 <        synchronized boolean isTo(int r, int c)   {
742 <            return toRow == r && toCol == c;
741 >        synchronized boolean isTo(int r, int c) {
742 >            return toRow == r && toCol == c;
743          }
744 <        synchronized Board board() {
745 <            return board_;
744 >        synchronized Board board() {
745 >            return board_;
746          }
747 <        synchronized Player player() {
748 <            return player_;
747 >        synchronized Player player() {
748 >            return player_;
749          }
750 <    
750 >
751  
752          // status checks:
753 <    
753 >
754          synchronized boolean isPass() { // is this a `pass' move?
755              return (toRow == PASS_VALUE || fromRow == PASS_VALUE);
756          }
757 <    
757 >
758          synchronized boolean isJump() {
759 <            return
759 >            return
760                  (fromRow - toRow == 2) || (toRow - fromRow == 2) ||
761                  (fromCol - toCol == 2) || (toCol - fromCol == 2);
762          }
763 <    
763 >
764          synchronized boolean hasFrom() { // is from set?
765              return fromRow != NO_VALUE && fromCol != NO_VALUE;
766          }
767 <    
767 >
768          synchronized boolean hasTo() { // is to set?
769              return toRow != NO_VALUE && toCol != NO_VALUE;
770          }
771 <    
800 <    
771 >
772          synchronized boolean possibleTo(int r, int c) { // is (r, c) a legal `to'?
773              return hasFrom() &&
774                  withinTwo(fromRow, r) &&
775                  withinTwo(fromCol, c) &&
776                  board_.occupant(r, c).isEmpty();
777          }
778 <    
778 >
779          synchronized boolean isLegal() {
780 <            if (isPass())
780 >            if (isPass())
781                  return true;
782 <            else if (!board_.occupant(toRow, toCol).isEmpty())
782 >            else if (!board_.occupant(toRow, toCol).isEmpty())
783                  return false;
784 <            else if (!board_.occupant(fromRow, fromCol).same(player_))
784 >            else if (!board_.occupant(fromRow, fromCol).same(player_))
785                  return false;
786 <            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
786 >            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
787                  return false;
788              else
789                  return true;
790          }
791 <    
791 >
792          synchronized void commit() { // update board to reflect move
793              if (!committed) {
794                  committed = true;
795 <                if (isLegal() && !isPass())  {
795 >                if (isLegal() && !isPass()) {
796                      if (isJump()) board_.occupy(Player.Empty, fromRow, fromCol);
797                      board_.take(player_, toRow, toCol);
798                  }
799              }
800          }
801 <    
801 >
802      }
803 <  
803 >
804      /**
805       *  Mover is an abstract class to simplify code dealing with
806       *  either user moves or auto moves.
807 <     **/
808 <  
807 >     */
808 >    abstract static class Mover {
809  
839    static abstract class Mover {
840    
810          // caller for move callbacks
811          protected Microscope game;
812 <    
812 >
813          protected Mover(Microscope ap) { game = ap; }
814 <    
814 >
815          // start a turn as player on given board
816          public abstract void startTurn(Board b, Player p);
817 <    
817 >
818          // cancel current partial move
819          public abstract void cancel();
820 <    
820 >
821          // return true if move not yet ready
822          public abstract boolean placing();
823 <    
823 >
824      }
856  
857    /**
858     *  User builds moves via instructions/clicks by users
859     **/
825  
826 +    /**
827 +     * User builds moves via instructions/clicks by users
828 +     */
829      static class User extends Mover {
830  
831          private Move current;
832 <    
832 >
833          public User(Microscope ap) { super(ap); current = null; }
834 <    
834 >
835          public synchronized void startTurn(Board b, Player p) {
836              current = new Move(p, b);
837          }
838 <    
839 <        public boolean placing() {
840 <            return current != null && current.hasFrom() && !current.hasTo();
838 >
839 >        public boolean placing() {
840 >            return current != null && current.hasFrom() && !current.hasTo();
841          }
842 <    
843 <        public synchronized void cancel() {
842 >
843 >        public synchronized void cancel() {
844              if (current != null) {
845 <                current.reset();
846 <                current = null;
845 >                current.reset();
846 >                current = null;
847              }
848          }
849 <    
849 >
850          public synchronized void choose(int row, int col) {
851              if (current != null) {
852                  if (row == Move.PASS_VALUE) {
# Line 898 | Line 866 | public class Microscope extends JPanel {
866                  }
867              }
868          }
869 <    
869 >
870          public synchronized boolean canMoveTo(int row, int col) {
871              return placing() && current.possibleTo(row, col);
872          }
873 <    
873 >
874          public synchronized boolean hasMovedFrom(int row, int col) {
875              return current != null && current.isFrom(row, col);
876          }
909    
910    }
877  
878 +    }
879  
880      /**
881 <     *     AutoMover constructs Finders that compute actual moves
882 <     **/
916 <
881 >     * AutoMover constructs Finders that compute actual moves
882 >     */
883      static class AutoMover extends Mover {
884  
885          boolean cancelled = false;
# Line 922 | Line 888 | public class Microscope extends JPanel {
888          public AutoMover(Microscope ap) {
889              super(ap);
890          }
891 <  
892 <    
893 <        public synchronized boolean placing() {
928 <            return currentFinder != null;
891 >
892 >        public synchronized boolean placing() {
893 >            return currentFinder != null;
894          }
895  
896 <        synchronized void stopPlacing() {
896 >        synchronized void stopPlacing() {
897              currentFinder = null;
898          }
899 <    
935 <    
899 >
900          public synchronized void cancel() {
901 <            if (placing())  {
901 >            if (placing()) {
902                  currentFinder.cancel(false);
903                  stopPlacing();
904              }
# Line 942 | Line 906 | public class Microscope extends JPanel {
906  
907          public synchronized void startTurn(Board board, Player player) {
908              if (!placing()) {
909 <                currentFinder = new RootFinder(board, player,
909 >                currentFinder = new RootFinder(board, player,
910                                                 Microscope.lookAheads, this);
911                  group.execute(currentFinder);
912              }
913          }
914 <    
914 >
915          synchronized void relay(Move move) { // relay callback from finder
916              if (placing()) {
917                  stopPlacing();
918                  game.move(move, this);
919              }
920          }
921 <    
921 >
922      }
959  
923  
924      /**
925 <     * Implements a classic all-possible-move search algorith using
925 >     * Implements a classic all-possible-move search algorithm using
926       * ForkJoinTasks.  The move finder is not all that smart. Among
927       * other possible improvements, it could keep a cache of explored
928       * moves and avoid repeating them. This would likely speed it up
929       * since most expansions are duplicates of others. It could also
930       * be changed to prune moves, although this is unlikely to work
931       * well without better partial evaluation functions.
932 <     **/
970 <  
932 >     */
933      static class Finder extends RecursiveAction {
934  
935          static final int NOMOVE = Integer.MIN_VALUE;
936          static final int LOSE   = NOMOVE+1;
937          static final int WIN    = -LOSE;
938 <    
938 >
939          final long ours;     // bits for our tiles
940          final long theirs;   // bits for opponent tiles
941          final int level;     // current number of lookAheads
# Line 992 | Line 954 | public class Microscope extends JPanel {
954          protected final void compute() {
955  
956              // Handle sure wins and losses here
957 <            if ((ours & ~Board.BLUEBIT) == 0)  
957 >            if ((ours & ~Board.BLUEBIT) == 0)
958                  bestScore = LOSE;
959  
960 <            else if ((theirs & ~Board.BLUEBIT) == 0)
960 >            else if ((theirs & ~Board.BLUEBIT) == 0)
961                  bestScore = WIN;
962  
963              else if (((ours | theirs) & Board.FULL) == Board.FULL) {
# Line 1005 | Line 967 | public class Microscope extends JPanel {
967                  else bestScore = 0;
968              }
969  
970 <            else
970 >            else
971                  search();
972          }
1011    
973  
974          final void search() {
975              int best = NOMOVE;    // For direct evaluation when level == 1
976              Finder forked = null; // list of forked subtasks when level > 1
977 <      
977 >
978              long open = ~(ours | theirs);  // currently empty cells
979 <            long here = 1;                 // travserse through bits
980 <      
979 >            long here = 1;                 // traverse through bits
980 >
981              for (int k = 0; k < Board.CELLS; ++k, here <<= 1) {
982                  if ((here & ours) != 0) {
983                      /*
# Line 1027 | Line 988 | public class Microscope extends JPanel {
988                      for (int j = 0; j < dests.length; ++j) {
989                          byte d = dests[j];
990                          long dest = 1L << d;
991 <                        
991 >
992                          if ( (dest & open) != 0) {
993                              long adjacent = Board.adjacentMasks[d];
994                              long nTheirs = theirs & ~adjacent;
995                              long nOurs = (ours & ~here) | dest | (theirs & adjacent);
996  
997 <                            if (level > 1)
998 <                                (forked =
997 >                            if (level > 1)
998 >                                (forked =
999                                   new Finder(nTheirs, nOurs, level-1, forked)).fork();
1000                              else {
1001                                  int sc = Board.score(nOurs, nTheirs);
# Line 1054 | Line 1015 | public class Microscope extends JPanel {
1015                      if ((ours & adjacent) != 0) {
1016                          long nTheirs = theirs & ~adjacent;
1017                          long nOurs = ours | here | (theirs & adjacent);
1018 <                        if (level > 1)
1018 >                        if (level > 1)
1019                              (forked = new Finder(nTheirs, nOurs, level-1, forked)).fork();
1020                          else {
1021                              int sc = Board.score(nOurs, nTheirs);
# Line 1072 | Line 1033 | public class Microscope extends JPanel {
1033  
1034          /**
1035           * Join all subtasks and evaluate moves. Default is sub-finder version.
1036 <         * Overridden in RootFinder
1037 <         **/
1077 <
1036 >         * Overridden in RootFinder.
1037 >         */
1038          void collect(Finder forked) {
1039              int best = NOMOVE;
1040              while (forked != null) {
1041 <                while (!forked.isDone()) {
1042 <                    // interleave joins with status checks                    
1041 >                while (!forked.isDone()) {
1042 >                    // interleave joins with status checks
1043                      if (isDone()) {
1044                          cancelAll(forked);
1045                          return;
# Line 1105 | Line 1065 | public class Microscope extends JPanel {
1065          }
1066  
1067          /**
1068 <         * Cancel all forked subtasks in list
1069 <         **/
1110 <
1068 >         * Cancels all forked subtasks in list.
1069 >         */
1070          void cancelAll(Finder forked) {
1071              while (forked != null) {
1072                  forked.cancel(false);
# Line 1119 | Line 1078 | public class Microscope extends JPanel {
1078  
1079      /**
1080       * Root Finder class -- wait out other finders and issue callback to game.
1081 <     **/
1123 <
1081 >     */
1082      static class RootFinder extends Finder {
1083 <        final AutoMover automover;
1083 >        final AutoMover automover;
1084          final Player player;
1085          RootFinder(Board board, Player p, int level, AutoMover automover) {
1086 <            super( (p.isBlue()? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1087 <                   (p.isBlue()? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1086 >            super( (p.isBlue() ? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1087 >                   (p.isBlue() ? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1088                     level,
1089                     null);
1090 <            
1090 >
1091              this.player = p;
1092              this.automover = automover;
1093          }
1094  
1137
1095          /**
1096           * This differs from default version by recording
1097           * and calling back with best move
1098 <         **/
1098 >         */
1099          void collect(Finder forked) {
1100              int best = NOMOVE;
1101              Finder bestFinder = null;
# Line 1163 | Line 1120 | public class Microscope extends JPanel {
1120                          break;
1121                      }
1122                  }
1123 <        
1123 >
1124                  // Just for fun, introduce a little randomness via hashcodes
1125                  else if (score == best &&
1126                           !Microscope.DETERMINISTIC &&
1127 <                         (System.identityHashCode(forked) >
1127 >                         (System.identityHashCode(forked) >
1128                            System.identityHashCode(bestFinder))) {
1129                      bestFinder = forked;
1130                  }
1131                  forked = forked.next;
1132              }
1133 <      
1133 >
1134              Move move = null;
1135              if (bestFinder != null) {
1136 <                /*
1136 >                /*
1137                     Even though accessed here,
1138                     the ours and theirs vars of Finders do not
1139                     need to be volatile because they are immutably
1140                     established in constructors.
1141                  */
1142 <        
1142 >
1143                  long nextOurs = bestFinder.theirs;
1144                  long nextTheirs = bestFinder.ours;
1145 <                long blue = (player.isBlue())? nextOurs : nextTheirs;
1146 <                long green = (player.isBlue())? nextTheirs: nextOurs;
1145 >                long blue = player.isBlue() ? nextOurs : nextTheirs;
1146 >                long green = player.isBlue() ? nextTheirs : nextOurs;
1147                  move = new Move(player, new Board(blue, green), true);
1148              }
1149              automover.relay(move);
1150          }
1151      }
1195
1196  
1152   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines