tictactoe: Don't let the user send an illegal move
authorCarl Worth <cworth@cworth.org>
Thu, 4 Jun 2020 00:37:59 +0000 (17:37 -0700)
committerCarl Worth <cworth@cworth.org>
Thu, 4 Jun 2020 00:37:59 +0000 (17:37 -0700)
The client already knows which squares are occupied, and when the game
is won, so it's pointless to ever send a move we know is going to be
rejected. And in fact, we shouldn't even give the user a hover
indication as if they could move there.

That's all implemented in this commit. The hover highlight and the
pointer cursor are both disabled for squares that are already
occupied, and for all squares once the game is over.

tictactoe/tictactoe.css
tictactoe/tictactoe.jsx

index 52a8e87b0d81895374560a61a11ad29087d79fe6..a9879334d710a2e96926f83140f88e8492b8063e 100644 (file)
@@ -29,7 +29,15 @@ ol, ul {
   border-radius: 4px;
 }
 
-.square:hover {
+.square.open {
+    cursor: pointer;
+}
+
+.square.occupied {
+    cursor: default;
+}
+
+.square.open:hover {
     background-color: var(--accent-color-bright);
 }
 
index 61a828eb751d6662e63681aa6e313cb6ed95dd20..d92b698fe57b913e8d8625643b18376bf0262947 100644 (file)
@@ -36,18 +36,31 @@ events.addEventListener("game-state", event => {
 });
 
 function Square(props) {
+  let className = "square";
+
+  if (props.value) {
+    className += " occupied";
+  } else if (props.active) {
+    className += " open";
+  }
+
+  const onClick = props.active ? props.onClick : null;
+
   return (
-    <button className="square" onClick={props.onClick}>
+    <div className={className}
+         onClick={onClick}>
       {props.value}
-    </button>
+    </div>
   );
 }
 
 class Board extends React.Component {
   renderSquare(i) {
+    const value = this.props.squares[i];
     return (
       <Square
-        value={this.props.squares[i]}
+        value={value}
+        active={! this.props.gameOver && ! value}
         onClick={() => this.props.onClick(i)}
       />
     );
@@ -173,6 +186,7 @@ class Game extends React.Component {
         </div>
         <div className="game-board">
           <Board
+            gameOver={winner}
             squares={current.squares}
             onClick={i => this.handleClick(i)}
           />