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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines