Highlight last move and legal mini-grids for current move
authorCarl Worth <cworth@cworth.org>
Sat, 20 Jun 2020 19:11:50 +0000 (12:11 -0700)
committerCarl Worth <cworth@cworth.org>
Sat, 20 Jun 2020 19:11:50 +0000 (12:11 -0700)
This is the necessary information so that players can actually know
where to play.

At this point, the only feature really missing from the game is
automatic scoring of completed glyphs.

scribe/scribe.css
scribe/scribe.jsx

index 0db57f6d0e3df0d600dfe3e699cf8be034cf62a0..aba532e04b0bd49f65ccb33163c96ab5d77187ba 100644 (file)
     border: 3px solid #999;
 }
 
+.mini-grid.active {
+    border: 3px solid var(--accent-color-bright);
+}
+
 .square {
     display: flex;
     justify-content: center;
     background-color: var(--accent-color-bright);
 }
 
+.square.last-move {
+    color: var(--accent-color-bright);
+}
+
 .glyphs {
     padding-top: 0.5em;
     display: grid;
index 548a0edc826c44258bf05af1e2cdc73325d7da18..07920773c9f79caa371b178639deaa35fea5a040 100644 (file)
@@ -335,6 +335,10 @@ function Square(props) {
     className += " open";
   }
 
+  if (props.last_move) {
+    className += " last-move";
+  }
+
   const onClick = props.active ? props.onClick : null;
 
   return (
@@ -348,17 +352,31 @@ function Square(props) {
 function MiniGrid(props) {
   function grid_square(j) {
     const value = props.squares[j];
+    const last_move = props.last_moves.includes(j);
     return (
       <Square
         value={value}
         active={props.active}
+        last_move={last_move}
         onClick={() => props.onClick(j)}
       />
     );
   }
 
+  /* Even if my parent thinks I'm active because of the last move, I
+   * might not _really_ be active if I'm full. */
+  let occupied = 0;
+  props.squares.forEach(element => {
+    if (element)
+      occupied++;
+  });
+
+  let class_name = "mini-grid";
+  if (props.active && occupied < 9)
+    class_name += " active";
+
   return (
-    <div className="mini-grid">
+    <div className={class_name}>
       {grid_square(0)}
       {grid_square(1)}
       {grid_square(2)}
@@ -374,11 +392,54 @@ function MiniGrid(props) {
 
 class Board extends React.Component {
   mini_grid(i) {
+    /* This mini grid is active only if both:
+     *
+     * 1. It is our turn (this.props.active === true)
+     *
+     * 2. One of the following conditions is met:
+     *
+     *    a. This is this players first turn (last_two_moves[0] === null)
+     *    b. This mini grid corresponds to this players last turn
+     *    c. The mini grid that corresponds to the players last turn is full
+     */
+    let active = false;
+    if (this.props.active) {
+      active = true;
+      if (this.props.last_two_moves[0]) {
+        /* First index (0) gives us our last move, (that is, of the
+         * last two moves, it's the first one, so two moves ago).
+         *
+         * Second index (1) gives us the second number from that move,
+         * (that is, the index within the mini-grid that we last
+         * played).
+         */
+        const target = this.props.last_two_moves[0][1];
+        let occupied = 0;
+        this.props.squares[target].forEach(element => {
+          if (element)
+            occupied++;
+        });
+        /* If the target mini-grid isn't full then this grid is
+         * only active if it is that target. */
+        if (occupied < 9)
+          active = (i === target);
+      }
+    }
+
+    /* We want to highlight each of the last two moves (both "+" and
+     * "o"). So we filter the last two moves that have a first index
+     * that matches this mini_grid and pass down their second index
+     * be highlighted.
+     */
+    const last_moves = this.props.last_two_moves.filter(move => move[0] === i)
+          .map(move => move[1]);
+
     const squares = this.props.squares[i];
     return (
       <MiniGrid
         squares={squares}
-        active={this.props.active}
+        active={active}
+        last_moves={last_moves}
         onClick={(j) => this.props.onClick(i,j)}
       />
     );
@@ -430,8 +491,8 @@ class Game extends React.Component {
       player_info: {},
       other_players: [],
       squares: [...Array(9)].map(() => Array(9).fill(null)),
-      moves: 0,
-      next_to_play: "+"
+      moves: [],
+      next_to_play: "+",
     };
   }
 
@@ -467,12 +528,13 @@ class Game extends React.Component {
   }
 
   receive_move(move) {
-    if (this.state.moves === 81) {
+    if (this.state.moves.length === 81) {
       return;
     }
     const symbol = team_symbol(this.state.next_to_play);
     const new_squares = this.state.squares.map(arr => arr.slice());
     new_squares[move[0]][move[1]] = symbol;
+    const new_moves = [...this.state.moves, move];
     let next_to_play;
     if (this.state.next_to_play === "+")
       next_to_play = "o";
@@ -480,7 +542,7 @@ class Game extends React.Component {
       next_to_play = "+";
     this.setState({
       squares: new_squares,
-      moves: this.state.moves + 1,
+      moves: new_moves,
       next_to_play: next_to_play
     });
   }
@@ -508,7 +570,7 @@ class Game extends React.Component {
 
   render() {
     const state = this.state;
-    const first_move = state.moves === 0;
+    const first_move = state.moves.length === 0;
     const my_team = state.player_info.team;
     var board_active;
 
@@ -573,6 +635,7 @@ class Game extends React.Component {
           <Board
             active={board_active}
             squares={state.squares}
+            last_two_moves={state.moves.slice(-2)}
             onClick={(i,j) => this.handle_click(i, j, first_move)}
           />
         </div>