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.12 by jsr166, Wed Dec 31 17:00:58 2014 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 + import javax.swing.*;
12 + import javax.swing.event.*;
13  
14  
15   /**
# Line 18 | Line 18 | import java.util.concurrent.*;
18   * See <a href="http://gee.cs.oswego.edu/dl/applets/micro.html">
19   * Microscope</a> version for instructions.
20   * <p>
21 < * The code has been mangled beyond recognition
22 < * as a test of ForkJoin
23 < **/
24 <
21 > * The code has been mangled beyond recognition
22 > * as a test of ForkJoin.
23 > */
24   public class Microscope extends JPanel {
25  
26      static final CountDownLatch cd = new CountDownLatch(1);
# Line 72 | Line 71 | public class Microscope extends JPanel {
71          System.exit(0);
72      }
73  
74 <    static void onExit() {
74 >    static void onExit() {
75          long now = System.currentTimeMillis();
76          System.out.println("time: " + (now - startTime) + "ms");
77          System.out.println(group.toString());
78          System.exit(0);
79 <    }        
80 <    
79 >    }
80 >
81      static void oneRun() {
82          if (java.awt.GraphicsEnvironment.isHeadless()) {
83              headless = true;
# Line 89 | Line 88 | public class Microscope extends JPanel {
88              JFrame frame = new JFrame();
89              frame.addWindowListener(new WindowAdapter() {
90                      public void windowClosing(WindowEvent e) {onExit();}});
91 <            
91 >
92              Microscope t = new Microscope();
93              frame.setSize(new Dimension(400, 400));
94              frame.getContentPane().add(t);
# Line 104 | Line 103 | public class Microscope extends JPanel {
103      Board board = new Board();        // The current board representation
104  
105      synchronized Board getBoard() { return board; }
106 <    synchronized void  setBoard(Board b) {
107 <        board = b;
106 >    synchronized void  setBoard(Board b) {
107 >        board = b;
108          System.out.print(b.score(player) + " ");
109          if (boardPanel != null)
110 <            boardPanel.repaint();
110 >            boardPanel.repaint();
111      }
112  
113      Player player = Player.Blue;      // current player (BLUE, GREEN)
# Line 140 | Line 139 | public class Microscope extends JPanel {
139      JButton modeButton;
140      JSlider levelSlider;
141  
142 <    public Microscope() {  
142 >    public Microscope() {
143          if (headless) {
144              boardPanel = null;
145              auto = new AutoMover(this);
# Line 166 | Line 165 | public class Microscope extends JPanel {
165                      }
166                      else {
167                          stopMover();
168 <                        if (getDemoMode())
168 >                        if (getDemoMode())
169                              autoButton.setText(" Start ");
170                          else
171                              autoButton.setText(" Find ");
# Line 184 | Line 183 | public class Microscope extends JPanel {
183                  public void actionPerformed(ActionEvent e) {
184                      undo();
185                  }});
186 <
186 >
187          levelSlider.addChangeListener(new ChangeListener() {
188                  public void stateChanged(ChangeEvent e) {
189                      setLevel(((JSlider)(e.getSource())).getValue());
# Line 194 | Line 193 | public class Microscope extends JPanel {
193          //        Dimension labDim = new Dimension(72, 24);
194          //        scoreLabel.setMinimumSize(labDim);
195          //        scoreLabel.setPreferredSize(labDim);
196 <    
196 >
197  
198          topPanel.add(autoButton);
199          topPanel.add(modeButton);
200          topPanel.add(undoButton);
201          topPanel.add(scoreLabel);
202          add(topPanel);
203 <    
203 >
204  
205          levelSlider.setLabelTable(levelSlider.createStandardLabels(1));
206          levelSlider.setPaintLabels(true);
# Line 215 | Line 214 | public class Microscope extends JPanel {
214          sliderPanel.add(new JLabel("Level"));
215  
216          botPanel.add(sliderPanel);
217 <    
217 >
218          add(botPanel);
219      }
220  
# Line 230 | Line 229 | public class Microscope extends JPanel {
229              boardPanel.repaint();
230      }
231  
232 <    public void init()  {
232 >    public void init() {
233          initializeBoard();
234          if (autostart) {
235              startMover(auto);
# Line 242 | Line 241 | public class Microscope extends JPanel {
241          lookAheads = l;
242          if (lookAheads <= 1) lookAheads = 2;
243      }
244 <    
245 <    public int level () { return Microscope.lookAheads; }
246 <    
244 >
245 >    public int level() { return Microscope.lookAheads; }
246 >
247  
248      // process a move (called only from mover)
249  
250      public void move(Move m, Mover mvr) {
251 <        if (mvr != mover ||
251 >        if (mvr != mover ||
252              m == null ||
253              (mvr == user && !m.isLegal())) {
254              setMover(null);
# Line 265 | Line 264 | public class Microscope extends JPanel {
264  
265              history.addElement(m);
266  
267 <            if (mvr == auto &&
268 <                getDemoMode() &&
267 >            if (mvr == auto &&
268 >                getDemoMode() &&
269                  !m.isPass()) {
270                  if (getBoard().gameOver()) {
271                      if (autostart) {
# Line 303 | Line 302 | public class Microscope extends JPanel {
302              mvr.cancel();
303          }
304      }
305 <
305 >
306  
307      // handle Undo button
308      synchronized void undo() {
# Line 326 | Line 325 | public class Microscope extends JPanel {
325          startMover(user);
326          user.choose(row, col);
327      }
328 <  
328 >
329      void updateStatus() { // normally called from board update
330          Player p = getPlayer();
331          int s = getBoard().score(p);
# Line 334 | Line 333 | public class Microscope extends JPanel {
333              System.out.print(s + " ");
334              return;
335          }
336 <        
336 >
337          scoreLabel.setForeground(displayColor(p));
338          scoreLabel.setText("Score: " +  s);
339  
340 <        if (getDemoMode())
340 >        if (getDemoMode())
341              modeButton.setText("Demo  mode");
342          else {
343              if (getPlayer().isBlue())
# Line 350 | Line 349 | public class Microscope extends JPanel {
349      }
350  
351  
352 <    static final int CELL_SIZE = 40; // size of a tile/cell
353 <  
352 >    static final int CELL_SIZE = 40; // size of a tile/cell
353 >
354      static final Color paleGreen = new Color(152, 251, 152);
355      static final Color darkGreen = new Color(60, 179, 113);
356 <    
356 >
357      static final Color possibleMoveColor = Color.yellow;
358 <    
358 >
359  
360      public static Color displayColor(Player pl) {
361          if (pl.isBlue()) return Color.blue;
# Line 372 | Line 371 | public class Microscope extends JPanel {
371  
372  
373      class BoardPanel extends Canvas implements MouseListener {
374 <    
375 <        BoardPanel() {
376 <            setSize(new Dimension(Board.RANKS * CELL_SIZE + 5,
374 >
375 >        BoardPanel() {
376 >            setSize(new Dimension(Board.RANKS * CELL_SIZE + 5,
377                                    Board.RANKS * CELL_SIZE + 5));
378              addMouseListener(BoardPanel.this);
379          }
380 <    
380 >
381          public void paint(Graphics g) {
382 <      
382 >
383              Board b = getBoard();
384              Player p = getPlayer();
385 <      
385 >
386              // the cells
387              for (int row = 0; row < Board.RANKS; row++) {
388                  for (int col = 0; col < Board.RANKS; col++) {
389 <          
389 >
390                      // Highlight selected tile and legal destinations
391                      if (user.placing()) {
392 <                        if (user.hasMovedFrom(row, col))
392 >                        if (user.hasMovedFrom(row, col))
393                              g.setColor(lightDisplayColor(p));
394                          else if (user.canMoveTo(row, col))
395                              g.setColor(possibleMoveColor);
396                          else
397                              g.setColor(displayColor(b.occupant(row, col)));
398                      }
399 <          
399 >
400                      else
401                          g.setColor(displayColor(b.occupant(row, col)));
402 <          
402 >
403                      // tiles are just filled rectangles
404                      g.fillRect(row * CELL_SIZE, col * CELL_SIZE, CELL_SIZE, CELL_SIZE);
405                  }
406              }
407 <      
407 >
408              // the grid over the cells
409              g.setColor(Color.black);
410              for ( int i = 0; i <= Board.RANKS; i++) {
411                  g.drawLine(0, i * CELL_SIZE, Board.RANKS * CELL_SIZE, i * CELL_SIZE);
412                  g.drawLine(i * CELL_SIZE, 0, i * CELL_SIZE, Board.RANKS * CELL_SIZE);
413              }
414 <      
414 >
415              updateStatus();
416          }
417 <    
417 >
418          public void mouseReleased(MouseEvent evt) {
419 <      
419 >
420              int x = evt.getX();
421              int y = evt.getY();
422 <      
422 >
423              int row = x / CELL_SIZE;
424              int col = y / CELL_SIZE;
425 <      
425 >
426              if (Board.inBounds(row, col)) { // cell selection
427                  userMove(row, col);
428                  repaint();
429              }
430          }
431 <    
431 >
432          public void mouseClicked(MouseEvent e) {}
433          public void mousePressed(MouseEvent e) {}
434          public void mouseEntered(MouseEvent e) {}
# Line 438 | Line 437 | public class Microscope extends JPanel {
437  
438      /**
439       *  Player is just a glorified enumeration
440 <     **/
442 <
440 >     */
441      static final class Player {
442  
443          public static final int EMPTY = 0;
444          public static final int BLUE = 1;
445          public static final int GREEN = 2;
446          public static final int ILLEGAL_PLAYER_VALUE = 3;
447 <    
447 >
448          public static final Player Empty   = new Player(EMPTY);
449          public static final Player Blue    = new Player(BLUE);
450          public static final Player Green   = new Player(GREEN);
451          public static final Player Illegal = new Player(ILLEGAL_PLAYER_VALUE);
452 <    
452 >
453          /* private */ int code_;
454 <    
454 >
455          public Player(int code)       { code_ = code; }
456          public Player(Player p)       { code_ = p.code_; }
457 <    
457 >
458          public boolean same(Player p) { return code_ == p.code_; }
459 <    
459 >
460          public boolean isEmpty()      { return code_ == EMPTY; }
461          public boolean isBlue()       { return code_ == BLUE; }
462          public boolean isGreen()      { return code_ == GREEN; }
463          public boolean isLegal()      { return code_ <= GREEN; }
464 <    
465 <        public Player opponent() {
464 >
465 >        public Player opponent() {
466              if (code_ == GREEN) return Blue;
467              else if (code_ == BLUE) return Green;
468              else return Illegal;
469          }
470 <    
470 >
471      }
472 <  
472 >
473      /**
474       *   Board configurations are represented by bit vectors.
475       *   Since there are only 49 cells, the bits can be held in `longs',
# Line 480 | Line 478 | public class Microscope extends JPanel {
478       * Boards are not immutable, but are never passed around across
479       * threads (instead new ones are constructed), so don't
480       * need any synch.
481 <     **/
482 <  
485 <    static final class Board   {
481 >     */
482 >    static final class Board {
483  
484 <        /*
484 >        /*
485             First, some Constants and utilities that might as well be here
486          */
487 <    
487 >
488          public static final int RANKS = 7;
489          public static final int CELLS = RANKS * RANKS;
490 <    
490 >
491          static final long FULL = (1L << CELLS) - 1;
492 <    
492 >
493          // The finder uses a spare bit to remember whose move it is.
494          static final long BLUEBIT = (1L << CELLS);
495 <    
495 >
496          // Bits representing the adjacent cells for every position
497          static final long[] adjacentMasks = new long[CELLS];
498 <    
498 >
499          // bit pattern associated with each tile
500          static final long[] cellBits = new long[CELLS];
501  
# Line 537 | Line 534 | public class Microscope extends JPanel {
534              }
535  
536          }
537 <    
538 <    
537 >
538 >
539          public static boolean inBounds(int row, int col) {
540              return (0 <= row)  && (row < RANKS) && (0 <= col) && (col < RANKS);
541          }
542 <    
542 >
543          // The representation
544 <    
544 >
545          long blue_;      // bit vector; true if occupied by blue
546          long green_;     // same for green;
547 <    
547 >
548          // constructors and intializers:
549 <    
549 >
550          public Board()               { blue_ = 0L; green_ = 0L; }
551          public Board(Board b)        { blue_ = b.blue_; green_ = b.green_; }
552          public Board(long b, long g) { blue_ = b; green_ = g; }
553 <    
553 >
554          public void copyState(Board b) {
555 <            blue_ = b.blue_;
556 <            green_ = b.green_;
555 >            blue_ = b.blue_;
556 >            green_ = b.green_;
557          }
558  
559 <        void reset() {
560 <            blue_ = 0L; green_ = 0L;
559 >        void reset() {
560 >            blue_ = 0L; green_ = 0L;
561          }
562 <    
562 >
563          long getBlue() { return blue_; }
564          long getGreen() { return green_; }
565  
# Line 577 | Line 574 | public class Microscope extends JPanel {
574              else
575                  return Player.Illegal;
576          }
577 <    
578 <    
577 >
578 >
579          // place a tile without taking opponent tiles
580 <    
580 >
581          public void occupy(Player player, int row, int col) {
582              long m = 1L << (row + col * RANKS);
583              long nm = ~m;
584 <            if (player.code_ == Player.BLUE)  {
584 >            if (player.code_ == Player.BLUE) {
585                  blue_ |= m;
586                  green_ &= nm;
587              }
588 <            else if (player.code_ == Player.GREEN) {
588 >            else if (player.code_ == Player.GREEN) {
589                  blue_ &=  nm;
590                  green_ |= m;
591              }
592 <            else {
592 >            else {
593                  blue_ &= nm;
594                  green_ &= nm;
595              }
596          }
597 <    
597 >
598          public void unoccupy(int row, int col) {
599              long nm = ~(1L << (row + col * RANKS));
600              blue_ &=  nm;
601              green_ &= nm;
602          }
603 <    
604 <    
605 <    
603 >
604 >
605 >
606          // place a tile, taking all adjacent tiles of opponent
607 <    
607 >
608          public void take(Player player, int row, int col) {
609 <            int k =  (row + col * RANKS);
609 >            int k = row + col * RANKS;
610              long dest = 1L << k;
611              long nbrMask = adjacentMasks[k];
612              long sourceBlue = blue_;
# Line 620 | Line 617 | public class Microscope extends JPanel {
617              }
618              else {
619                  blue_ = sourceBlue & ~(sourceBlue & nbrMask);
620 <                green_ =  sourceGreen | dest | (sourceBlue & nbrMask);
620 >                green_ = sourceGreen | dest | (sourceBlue & nbrMask);
621              }
622          }
623 <    
623 >
624          public boolean gameOver() {
625 <            return
625 >            return
626                  (((blue_ | green_) & FULL) == FULL) ||
627                  ((blue_ & ~BLUEBIT) == 0) ||
628                  ((green_ & ~BLUEBIT) == 0);
629          }
630 <    
631 <    
630 >
631 >
632          public int score(Player player) {
633              if (player.isBlue()) {
634                  return score(blue_, green_);
# Line 640 | Line 637 | public class Microscope extends JPanel {
637                  return score(green_, blue_);
638              }
639          }
640 <    
640 >
641          static int score(long b, long g) {
642 <      
642 >
643              // much faster by splitting into ints
644              // and using clever shift-based bit counter
645 <      
645 >
646              int lb = (int)(b & ((1L << 32) - 1));
647              int hb = ((int)(b >>> 32)) & ((1 << (CELLS - 32)) - 1);
648  
# Line 680 | Line 677 | public class Microscope extends JPanel {
677  
678              return hb - ((lg + hg) & 0xff);
679          }
680 <    
681 <    
682 <    
680 >
681 >
682 >
683          static int slowscore(long b, long g) {
684              int score = 0;
685              for (int l = 0; l < CELLS; ++l) {
# Line 693 | Line 690 | public class Microscope extends JPanel {
690              }
691              return score;
692          }
693 <  
694 <    
693 >
694 >
695      }
696 <  
696 >
697      /**
698       * Moves represent transitions across Board states
699 <     **/
700 <
704 <
705 <    static final class Move  {
699 >     */
700 >    static final class Move {
701  
702          static final int NO_VALUE = -1;     // row/col value if not yet set
703          static final int PASS_VALUE = -2;   // special value for pass moves
704 <    
704 >
705          // utilities for classifying moves
706 <    
707 <        public static boolean twoFrom(int a, int b) {
708 <            return (a - b == 2) || (b - a == 2);
706 >
707 >        public static boolean twoFrom(int a, int b) {
708 >            return (a - b == 2) || (b - a == 2);
709          }
710 <    
711 <        public static boolean withinTwo(int a, int b) {
710 >
711 >        public static boolean withinTwo(int a, int b) {
712              int diff = a - b; return -2 <= diff && diff <= 2;
713          }
714 <    
714 >
715          // representations
716 <    
716 >
717          int fromRow;
718          int fromCol;
719 <    
719 >
720          int toRow;
721          int toCol;
722 <    
722 >
723          Player player_;
724          Board board_;
725 <    
725 >
726          boolean committed = false; // true if board reflects move
727 <    
727 >
728          // constructors and intializers
729 <    
730 <        public Move(Player turn, Board board) {
729 >
730 >        public Move(Player turn, Board board) {
731              fromRow = NO_VALUE; fromCol = NO_VALUE;
732              toRow = NO_VALUE;   toCol = NO_VALUE;
733              player_ = turn;
734              board_ = board;
735          }
736 <    
737 <        public Move(Player turn, Board board, boolean isCommitted) {
736 >
737 >        public Move(Player turn, Board board, boolean isCommitted) {
738              fromRow = NO_VALUE; fromCol = NO_VALUE;
739              toRow = NO_VALUE;   toCol = NO_VALUE;
740              player_ = turn;
741              board_ = board;
742              committed = isCommitted;
743          }
744 <    
744 >
745          synchronized void reset() {
746              fromRow = NO_VALUE;
747              fromCol = NO_VALUE;
748              toRow = NO_VALUE;
749              toCol = NO_VALUE;
750          }
751 <    
751 >
752          // setters:
753 <    
754 <        synchronized void player(Player p)       { player_ = p;  }
755 <        synchronized void board(Board b)         { board_ = b;  }
756 <        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc;  }
753 >
754 >        synchronized void player(Player p)       { player_ = p; }
755 >        synchronized void board(Board b)         { board_ = b; }
756 >        synchronized void from(int sr, int sc)   { fromRow = sr; fromCol = sc; }
757          synchronized void to(int dr, int dc)     { toRow = dr;   toCol = dc; }
758 <  
758 >
759          //  accessors:
760 <    
761 <        synchronized boolean isFrom(int r, int c) {
762 <            return fromRow== r && fromCol == c;
760 >
761 >        synchronized boolean isFrom(int r, int c) {
762 >            return fromRow== r && fromCol == c;
763          }
764 <        synchronized boolean isTo(int r, int c)   {
765 <            return toRow == r && toCol == c;
764 >        synchronized boolean isTo(int r, int c) {
765 >            return toRow == r && toCol == c;
766          }
767 <        synchronized Board board() {
768 <            return board_;
767 >        synchronized Board board() {
768 >            return board_;
769          }
770 <        synchronized Player player() {
771 <            return player_;
770 >        synchronized Player player() {
771 >            return player_;
772          }
773 <    
773 >
774  
775          // status checks:
776 <    
776 >
777          synchronized boolean isPass() { // is this a `pass' move?
778              return (toRow == PASS_VALUE || fromRow == PASS_VALUE);
779          }
780 <    
780 >
781          synchronized boolean isJump() {
782 <            return
782 >            return
783                  (fromRow - toRow == 2) || (toRow - fromRow == 2) ||
784                  (fromCol - toCol == 2) || (toCol - fromCol == 2);
785          }
786 <    
786 >
787          synchronized boolean hasFrom() { // is from set?
788              return fromRow != NO_VALUE && fromCol != NO_VALUE;
789          }
790 <    
790 >
791          synchronized boolean hasTo() { // is to set?
792              return toRow != NO_VALUE && toCol != NO_VALUE;
793          }
794 <    
795 <    
794 >
795 >
796          synchronized boolean possibleTo(int r, int c) { // is (r, c) a legal `to'?
797              return hasFrom() &&
798                  withinTwo(fromRow, r) &&
799                  withinTwo(fromCol, c) &&
800                  board_.occupant(r, c).isEmpty();
801          }
802 <    
802 >
803          synchronized boolean isLegal() {
804 <            if (isPass())
804 >            if (isPass())
805                  return true;
806 <            else if (!board_.occupant(toRow, toCol).isEmpty())
806 >            else if (!board_.occupant(toRow, toCol).isEmpty())
807                  return false;
808 <            else if (!board_.occupant(fromRow, fromCol).same(player_))
808 >            else if (!board_.occupant(fromRow, fromCol).same(player_))
809                  return false;
810 <            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
810 >            else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
811                  return false;
812              else
813                  return true;
814          }
815 <    
815 >
816          synchronized void commit() { // update board to reflect move
817              if (!committed) {
818                  committed = true;
819 <                if (isLegal() && !isPass())  {
819 >                if (isLegal() && !isPass()) {
820                      if (isJump()) board_.occupy(Player.Empty, fromRow, fromCol);
821                      board_.take(player_, toRow, toCol);
822                  }
823              }
824          }
825 <    
825 >
826      }
827 <  
827 >
828      /**
829       *  Mover is an abstract class to simplify code dealing with
830       *  either user moves or auto moves.
831 <     **/
832 <  
831 >     */
832 >    abstract static class Mover {
833  
839    static abstract class Mover {
840    
834          // caller for move callbacks
835          protected Microscope game;
836 <    
836 >
837          protected Mover(Microscope ap) { game = ap; }
838 <    
838 >
839          // start a turn as player on given board
840          public abstract void startTurn(Board b, Player p);
841 <    
841 >
842          // cancel current partial move
843          public abstract void cancel();
844 <    
844 >
845          // return true if move not yet ready
846          public abstract boolean placing();
847 <    
847 >
848      }
856  
857    /**
858     *  User builds moves via instructions/clicks by users
859     **/
849  
850 +    /**
851 +     * User builds moves via instructions/clicks by users
852 +     */
853      static class User extends Mover {
854  
855          private Move current;
856 <    
856 >
857          public User(Microscope ap) { super(ap); current = null; }
858 <    
858 >
859          public synchronized void startTurn(Board b, Player p) {
860              current = new Move(p, b);
861          }
862 <    
863 <        public boolean placing() {
864 <            return current != null && current.hasFrom() && !current.hasTo();
862 >
863 >        public boolean placing() {
864 >            return current != null && current.hasFrom() && !current.hasTo();
865          }
866 <    
867 <        public synchronized void cancel() {
866 >
867 >        public synchronized void cancel() {
868              if (current != null) {
869 <                current.reset();
870 <                current = null;
869 >                current.reset();
870 >                current = null;
871              }
872          }
873 <    
873 >
874          public synchronized void choose(int row, int col) {
875              if (current != null) {
876                  if (row == Move.PASS_VALUE) {
# Line 898 | Line 890 | public class Microscope extends JPanel {
890                  }
891              }
892          }
893 <    
893 >
894          public synchronized boolean canMoveTo(int row, int col) {
895              return placing() && current.possibleTo(row, col);
896          }
897 <    
897 >
898          public synchronized boolean hasMovedFrom(int row, int col) {
899              return current != null && current.isFrom(row, col);
900          }
901 <    
901 >
902      }
903  
904  
905      /**
906 <     *     AutoMover constructs Finders that compute actual moves
907 <     **/
916 <
906 >     * AutoMover constructs Finders that compute actual moves
907 >     */
908      static class AutoMover extends Mover {
909  
910          boolean cancelled = false;
# Line 922 | Line 913 | public class Microscope extends JPanel {
913          public AutoMover(Microscope ap) {
914              super(ap);
915          }
916 <  
917 <    
918 <        public synchronized boolean placing() {
919 <            return currentFinder != null;
916 >
917 >
918 >        public synchronized boolean placing() {
919 >            return currentFinder != null;
920          }
921  
922 <        synchronized void stopPlacing() {
922 >        synchronized void stopPlacing() {
923              currentFinder = null;
924          }
925 <    
926 <    
925 >
926 >
927          public synchronized void cancel() {
928 <            if (placing())  {
928 >            if (placing()) {
929                  currentFinder.cancel(false);
930                  stopPlacing();
931              }
# Line 942 | Line 933 | public class Microscope extends JPanel {
933  
934          public synchronized void startTurn(Board board, Player player) {
935              if (!placing()) {
936 <                currentFinder = new RootFinder(board, player,
936 >                currentFinder = new RootFinder(board, player,
937                                                 Microscope.lookAheads, this);
938                  group.execute(currentFinder);
939              }
940          }
941 <    
941 >
942          synchronized void relay(Move move) { // relay callback from finder
943              if (placing()) {
944                  stopPlacing();
945                  game.move(move, this);
946              }
947          }
948 <    
948 >
949      }
950 <  
950 >
951  
952      /**
953       * Implements a classic all-possible-move search algorith using
# Line 966 | Line 957 | public class Microscope extends JPanel {
957       * since most expansions are duplicates of others. It could also
958       * be changed to prune moves, although this is unlikely to work
959       * well without better partial evaluation functions.
960 <     **/
970 <  
960 >     */
961      static class Finder extends RecursiveAction {
962  
963          static final int NOMOVE = Integer.MIN_VALUE;
964          static final int LOSE   = NOMOVE+1;
965          static final int WIN    = -LOSE;
966 <    
966 >
967          final long ours;     // bits for our tiles
968          final long theirs;   // bits for opponent tiles
969          final int level;     // current number of lookAheads
# Line 992 | Line 982 | public class Microscope extends JPanel {
982          protected final void compute() {
983  
984              // Handle sure wins and losses here
985 <            if ((ours & ~Board.BLUEBIT) == 0)  
985 >            if ((ours & ~Board.BLUEBIT) == 0)
986                  bestScore = LOSE;
987  
988 <            else if ((theirs & ~Board.BLUEBIT) == 0)
988 >            else if ((theirs & ~Board.BLUEBIT) == 0)
989                  bestScore = WIN;
990  
991              else if (((ours | theirs) & Board.FULL) == Board.FULL) {
# Line 1005 | Line 995 | public class Microscope extends JPanel {
995                  else bestScore = 0;
996              }
997  
998 <            else
998 >            else
999                  search();
1000          }
1001 <    
1001 >
1002  
1003          final void search() {
1004              int best = NOMOVE;    // For direct evaluation when level == 1
1005              Finder forked = null; // list of forked subtasks when level > 1
1006 <      
1006 >
1007              long open = ~(ours | theirs);  // currently empty cells
1008 <            long here = 1;                 // travserse through bits
1009 <      
1008 >            long here = 1;                 // traverse through bits
1009 >
1010              for (int k = 0; k < Board.CELLS; ++k, here <<= 1) {
1011                  if ((here & ours) != 0) {
1012                      /*
# Line 1027 | Line 1017 | public class Microscope extends JPanel {
1017                      for (int j = 0; j < dests.length; ++j) {
1018                          byte d = dests[j];
1019                          long dest = 1L << d;
1020 <                        
1020 >
1021                          if ( (dest & open) != 0) {
1022                              long adjacent = Board.adjacentMasks[d];
1023                              long nTheirs = theirs & ~adjacent;
1024                              long nOurs = (ours & ~here) | dest | (theirs & adjacent);
1025  
1026 <                            if (level > 1)
1027 <                                (forked =
1026 >                            if (level > 1)
1027 >                                (forked =
1028                                   new Finder(nTheirs, nOurs, level-1, forked)).fork();
1029                              else {
1030                                  int sc = Board.score(nOurs, nTheirs);
# Line 1054 | Line 1044 | public class Microscope extends JPanel {
1044                      if ((ours & adjacent) != 0) {
1045                          long nTheirs = theirs & ~adjacent;
1046                          long nOurs = ours | here | (theirs & adjacent);
1047 <                        if (level > 1)
1047 >                        if (level > 1)
1048                              (forked = new Finder(nTheirs, nOurs, level-1, forked)).fork();
1049                          else {
1050                              int sc = Board.score(nOurs, nTheirs);
# Line 1072 | Line 1062 | public class Microscope extends JPanel {
1062  
1063          /**
1064           * Join all subtasks and evaluate moves. Default is sub-finder version.
1065 <         * Overridden in RootFinder
1066 <         **/
1077 <
1065 >         * Overridden in RootFinder.
1066 >         */
1067          void collect(Finder forked) {
1068              int best = NOMOVE;
1069              while (forked != null) {
1070 <                while (!forked.isDone()) {
1071 <                    // interleave joins with status checks                    
1070 >                while (!forked.isDone()) {
1071 >                    // interleave joins with status checks
1072                      if (isDone()) {
1073                          cancelAll(forked);
1074                          return;
# Line 1105 | Line 1094 | public class Microscope extends JPanel {
1094          }
1095  
1096          /**
1097 <         * Cancel all forked subtasks in list
1098 <         **/
1110 <
1097 >         * Cancels all forked subtasks in list.
1098 >         */
1099          void cancelAll(Finder forked) {
1100              while (forked != null) {
1101                  forked.cancel(false);
# Line 1119 | Line 1107 | public class Microscope extends JPanel {
1107  
1108      /**
1109       * Root Finder class -- wait out other finders and issue callback to game.
1110 <     **/
1123 <
1110 >     */
1111      static class RootFinder extends Finder {
1112 <        final AutoMover automover;
1112 >        final AutoMover automover;
1113          final Player player;
1114          RootFinder(Board board, Player p, int level, AutoMover automover) {
1115 <            super( (p.isBlue()? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1116 <                   (p.isBlue()? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1115 >            super( (p.isBlue() ? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
1116 >                   (p.isBlue() ? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
1117                     level,
1118                     null);
1119 <            
1119 >
1120              this.player = p;
1121              this.automover = automover;
1122          }
# Line 1138 | Line 1125 | public class Microscope extends JPanel {
1125          /**
1126           * This differs from default version by recording
1127           * and calling back with best move
1128 <         **/
1128 >         */
1129          void collect(Finder forked) {
1130              int best = NOMOVE;
1131              Finder bestFinder = null;
# Line 1163 | Line 1150 | public class Microscope extends JPanel {
1150                          break;
1151                      }
1152                  }
1153 <        
1153 >
1154                  // Just for fun, introduce a little randomness via hashcodes
1155                  else if (score == best &&
1156                           !Microscope.DETERMINISTIC &&
1157 <                         (System.identityHashCode(forked) >
1157 >                         (System.identityHashCode(forked) >
1158                            System.identityHashCode(bestFinder))) {
1159                      bestFinder = forked;
1160                  }
1161                  forked = forked.next;
1162              }
1163 <      
1163 >
1164              Move move = null;
1165              if (bestFinder != null) {
1166 <                /*
1166 >                /*
1167                     Even though accessed here,
1168                     the ours and theirs vars of Finders do not
1169                     need to be volatile because they are immutably
1170                     established in constructors.
1171                  */
1172 <        
1172 >
1173                  long nextOurs = bestFinder.theirs;
1174                  long nextTheirs = bestFinder.ours;
1175 <                long blue = (player.isBlue())? nextOurs : nextTheirs;
1176 <                long green = (player.isBlue())? nextTheirs: nextOurs;
1175 >                long blue = player.isBlue() ? nextOurs : nextTheirs;
1176 >                long green = player.isBlue() ? nextTheirs : nextOurs;
1177                  move = new Move(player, new Board(blue, green), true);
1178              }
1179              automover.relay(move);
1180          }
1181      }
1182  
1183 <  
1183 >
1184   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines