Jump to content

JavaScript/Exercises/TicTacToe

From Wikibooks, open books for an open world




TicTacToe

TicTacToe is a game for two players. They choose fields out of a 3 x 3 chessboard.

First, we need an HTML file plus CSS to realize the user interface. It shall contain:

  • A caption
  • A container with nine buttons arranged in a 3 x 3 chessboard
  • Two button Start X and a button Start O to decide which user starts
  • A Reset button
  • A textfield to give the users feedbacks about the status of the game

The HTML might look like this:

Click to see solution
<!DOCTYPE html><html><head><title>TicTacToe</title><script>// ...</script><style>.container{display:grid;grid-template-columns:32%32%32%;grid-template-rows:6em6em6em;gap:1%;background-color:aliceblue;margin:2em;padding:2em;}.cell{display:flex;align-items:center;justify-content:center;}.button{height:2.4em;width:2.4em;font-size:2em;background-color:aqua;}.containerCmd{display:flex;justify-content:flex-end;}.buttonCmd{padding:0.6em2em0.6em2em;font-size:1em;margin-right:2em;}.feedback{padding:0.8em1em0.8em1em;margin:1em;font-size:1.4em;background-color:green;}</style></head><body><h1style="text-align: center;">TicTacToe</h1><!-- The container with the nine clickable buttons --><divclass="container"><divclass="cell"><buttonid="b1"class="button"disabled/></div><divclass="cell"><buttonid="b2"class="button"disabled/></div><divclass="cell"><buttonid="b3"class="button"disabled/></div><divclass="cell"><buttonid="b4"class="button"disabled/></div><divclass="cell"><buttonid="b5"class="button"disabled/></div><divclass="cell"><buttonid="b6"class="button"disabled/></div><divclass="cell"><buttonid="b7"class="button"disabled/></div><divclass="cell"><buttonid="b8"class="button"disabled/></div><divclass="cell"><buttonid="b9"class="button"disabled/></div></div><!-- buttons for start and reset the game --><divclass="containerCmd"><buttonclass="buttonCmd"id="startX">Start: X</button><buttonclass="buttonCmd"id="startO">Start: O</button><pstyle="padding-right:3em"></p><!-- a small spacer --><buttonclass="buttonCmd">Reset</button></div><!-- feedback from the script to the players --><pid="feedback"class="feedback">Click to one of the 'Start' buttons</p></body></html>


Next, you develop the app's logic by adding events to buttons and functions within the script element.

  • When the game starts or will be reset, the nine X/O buttons and the feedback area must be cleared.
  • It is helpful when the nine X/O buttons call the same event handler. event.target.id delivers the ID of the button and via document.getElementById(event.target.id) this button is reachable.
  • Whenever one of the nine X/O buttons is clicked, this button must be protected against further clicks elem.disabled = true.
  • We need a function that decides whether a line, a row, or a diagonal (8 possibilities) contains 3 'X's respectively 3 'O's.
  • Consider the case that no one wins.

All in all, the app might look like this:

Click to see solution
<!DOCTYPE html><html><head><title>TicTacToe</title><script>"use strict";// global variable for X/Oletuser="";// -------- start: decide which user has the first click ----------------functionstartXO(userXO){if(userXO==="X"){user="X";}else{user="O";}// disable / enable certain buttonsdocument.getElementById("startX").disabled=true;document.getElementById("startO").disabled=true;["b1","b2","b3","b4","b5","b6","b7","b8","b9"].forEach((button)=>{document.getElementById(button).disabled=false;});document.getElementById("feedback").innerHTML="";}// -------- regular action ----------------------------------------------functionbuttonClicked(event){constelem=document.getElementById(event.target.id);elem.innerHTML=user;elem.disabled=true;// check for end of gameswitch(isFinished()){case"tie":document.getElementById("feedback").innerHTML="No winner. Tie.";["b1","b2","b3","b4","b5","b6","b7","b8","b9"].forEach((button)=>{document.getElementById(button).disabled=true;});break;casetrue:document.getElementById("feedback").innerHTML="The winner is: "+user;["b1","b2","b3","b4","b5","b6","b7","b8","b9"].forEach((button)=>{document.getElementById(button).disabled=true;});break;default:// toggle user and go onif(user==="X"){user="O";}else{user="X";}}}// -------- check for end of game ----------------------functionisFinished(){constxo_b1=document.getElementById("b1").innerHTML;constxo_b2=document.getElementById("b2").innerHTML;constxo_b3=document.getElementById("b3").innerHTML;constxo_b4=document.getElementById("b4").innerHTML;constxo_b5=document.getElementById("b5").innerHTML;constxo_b6=document.getElementById("b6").innerHTML;constxo_b7=document.getElementById("b7").innerHTML;constxo_b8=document.getElementById("b8").innerHTML;constxo_b9=document.getElementById("b9").innerHTML;// check for 'tie' in a loop over all buttonslettmp=0;[xo_b1,xo_b2,xo_b3,xo_b4,xo_b5,xo_b6,xo_b7,xo_b8,xo_b9].forEach((elem)=>{if(elem!=="")tmp++});if(tmp===9){return"tie";}// check for winnerif(// horizontal(xo_b1===user&&xo_b2===user&&xo_b3===user)||(xo_b4===user&&xo_b5===user&&xo_b6===user)||(xo_b7===user&&xo_b8===user&&xo_b9===user)||// vertical(xo_b1===user&&xo_b4===user&&xo_b7===user)||(xo_b2===user&&xo_b5===user&&xo_b8===user)||(xo_b3===user&&xo_b6===user&&xo_b9===user)||// diagonal(xo_b1===user&&xo_b5===user&&xo_b9===user)||(xo_b3===user&&xo_b5===user&&xo_b7===user)){returntrue;}else{returnfalse;}}// -------- reset game -------------------------------------functionreset(){// disable / enable certain buttons["b1","b2","b3","b4","b5","b6","b7","b8","b9"].forEach((button)=>{document.getElementById(button).innerHTML="";document.getElementById(button).disabled=true;});document.getElementById("feedback").innerHTML="Click to 'Start'";document.getElementById("startX").disabled=false;document.getElementById("startO").disabled=false;}</script><style>.container{display:grid;grid-template-columns:32%32%32%;grid-template-rows:6em6em6em;gap:1%;background-color:aliceblue;margin:2em;padding:2em;}.cell{display:flex;align-items:center;justify-content:center;}.button{height:2.4em;width:2.4em;font-size:2em;background-color:aqua;}.containerCmd{display:flex;justify-content:flex-end;}.buttonCmd{padding:0.6em2em0.6em2em;font-size:1em;margin-right:2em;}.feedback{padding:0.8em1em0.8em1em;margin:1em;font-size:1.4em;background-color:green;}</style></head><body><h1style="text-align: center;">TicTacToe</h1><!-- The container with the nine clickable buttons --><divclass="container"><divclass="cell"><buttonid="b1"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b2"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b3"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b4"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b5"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b6"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b7"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b8"class="button"onclick="buttonClicked(event)"disabled/></div><divclass="cell"><buttonid="b9"class="button"onclick="buttonClicked(event)"disabled/></div></div><!-- buttons for start and reset the game --><divclass="containerCmd"><buttonclass="buttonCmd"id="startX"onClick="startXO('X')">Start: X</button><buttonclass="buttonCmd"id="startO"onClick="startXO('O')">Start: O</button><pstyle="padding-right:3em"></p><!-- a small spacer --><buttonclass="buttonCmd"onClick="reset()">Reset</button></div><!-- feedback from the script to the players --><pid="feedback"class="feedback">Click to one of the 'Start' buttons</p></body></html>
close