Alright, so I made a pretty simple Tic-Tac-Toe game in Python at one point, and it was pretty fun, so I thought I'd spice it up and do it in HTML/JS/CSS to make it a little bit more pretty. It was going pretty good, however I hit a little bump in the road when making the easy "AI" for the game. The easy AI for the game is supposed to just be completely random, and it is, but sometimes it takes over a square that is already occupied, and sometimes it doesn't move at all, so I know it is probably something pretty simple, I just don't know what. I think it's probably somewhere in this block of code, but I don't know:
function computerEasyModeMove(){
if(player == 'x'){
computer = 'o';
}
if(player == 'o'){
computer = 'x';
}
var computerMove = Math.floor(Math.random() * 9) + 1;
while(computerMove == 1 && (topLeftBox.innerHTML == 'o' || topLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 2 && (topMiddleBox.innerHTML == 'o' || topMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 3 && (topRightBox.innerHTML == 'o' || topRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 4 && (middleLeftBox.innerHTML == 'o' || middleLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 5 && (middleMiddleBox.innerHTML == 'o' || middleMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 6 && (middleRightBox.innerHTML == 'o' || middleRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 7 && (bottomLeftBox.innerHTML == 'o' || bottomLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 8 && (bottomMiddleBox.innerHTML == 'o' || bottomMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 9 && (bottomRightBox.innerHTML == 'o' || bottomRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
if(computerMove == 1){
topLeftBox.innerHTML = computer;
topLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 2){
topMiddleBox.innerHTML = computer;
topMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 3){
topRightBox.innerHTML = computer;
topRightBox.style.pointerEvents = 'none';
}
if(computerMove == 4){
middleLeftBox.innerHTML = computer;
middleLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 5){
middleMiddleBox.innerHTML = computer;
middleMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 6){
middleRightBox.innerHTML = computer;
middleRightBox.style.pointerEvents = 'none';
}
if(computerMove == 7){
bottomLeftBox.innerHTML = computer;
bottomLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 8){
bottomMiddleBox.innerHTML = computer;
bottomMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 9){
bottomRightBox.innerHTML = computer;
bottomRightBox.style.pointerEvents = 'none';
}
}
That is the code that I use for the easy AI basically, with the full code below. I think my game is looking pretty good. If you want to try it, I have been making it on repl.it, (https://repl.it/@AnthonyRobinso2/Tic-Tac-Toe-HTMLJS) if that makes it easier to help me. I'm still working on the game, and the harder ai modes, so I still need to get those done, but I want to have a playable game, even if it is really easy. Thanks again!
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<center>
<div id='setup'>
Hey! Welcome to my Tic-Tac-Toe game! Please choose some settings below!
<br>
<div class='xOrO'>
<h3>Player:</h3>
Do you want to be X's?<input type='checkbox' id='Xs' value='X' onchange='player = "x"'>
Or do you want to be O's?<input type='checkbox' id='Os' value='O' onchange='player = "o"'>
<h3>Opponent AI Level:</h3>
Easy<input type='checkbox' id='easy' value='easyMode'>
Medium (Coming Soon)<input type='checkbox' id='medium' value='mediumMode'>
Hard (Coming Soon)<input type='checkbox' id='hard' value='hardMode'>
<br>
<h4>Do you want to go first, or have the computer go first?</h4>
First<input type='checkbox' id='goFirst' value='first' onchange='playerFirst = true'>
  Second<input type='checkbox' id='goSecond' value='second' onchange='playerFirst = false'>
<br>
<br>
<br>
<button id='confirm' onclick='getGameUp()'>Confirm</button>
</div>
<div id='ticTacBoard'>
<div id='topLeft' onclick='move("topLeft")'> </div>
<div id='topMiddle' onclick='move("topMiddle")'> </div>
<div id='topRight' onclick='move("topRight")'> </div>
<br>
<div id='middleLeft' onclick='move("middleLeft")'> </div>
<div id='middleMiddle' onclick='move("middleMiddle")'> </div>
<div id='middleRight' onclick='move("middleRight")'> </div>
<br>
<div id='bottomLeft' onclick='move("bottomLeft")'> </div>
<div id='bottomMiddle' onclick='move("bottomMiddle")'> </div>
<div id='bottomRight' onclick='move("bottomRight")'> </div>
</div>
<br>
<br>
<br>
<br>
<br>
<div id='winDiv'>
<h1 id='winHeader'>
YOU WON!!!
</h1>
</div>
<div id='lossDiv'>
<h1 id='lossHeader'>
You lost...
</h1>
</div>
<div id='tieDiv'>
<h1 id='tieHeader'>
It's a tie!
</h1>
</div>
</center>
<script src="script.js"></script>
</body>
</html>
Javascript:
var player;
var computer;
var playerFirst;
var topLeftBox = document.getElementById('topLeft');
var topMiddleBox = document.getElementById('topMiddle');
var topRightBox = document.getElementById('topRight');
var middleLeftBox = document.getElementById('middleLeft');
var middleMiddleBox = document.getElementById('middleMiddle');
var middleRightBox = document.getElementById('middleRight');
var bottomLeftBox = document.getElementById('bottomLeft');
var bottomMiddleBox = document.getElementById('bottomMiddle');
var bottomRightBox = document.getElementById('bottomRight');
var winDiv = document.getElementById('winDiv');
var lossDiv = document.getElementById('lossDiv');
var ticTacBoard = document.getElementById('ticTacBoard');
var setup = document.getElementById('setup');
function getGameUp(){
setup.style.visibility = "hidden";
ticTacBoard.style.visibility = "visible";
if(playerFirst == false){
computerEasyModeMove();
}
}
function move(x){
if(x=='topLeft'){
if(topLeftBox.innerHTML != 'o' && topLeftBox.innerHTML != 'x'){
topLeftBox.innerHTML = player;
topLeftBox.style.pointerEvents = 'none';
}
}
if(x=='topMiddle'){
if(topMiddleBox.innerHTML != 'o' && topMiddleBox.innerHTML != 'x'){
topMiddleBox.innerHTML = player;
topMiddleBox.style.pointerEvents = 'none';
}
}
if(x=='topRight'){
if(topRightBox.innerHTML != 'o' && topRightBox.innerHTML != 'x'){
topRightBox.innerHTML = player;
topRightBox.style.pointerEvents = 'none';
}
}
if(x=='middleLeft'){
if(middleLeftBox.innerHTML != 'o' && middleLeftBox.innerHTML != 'x'){
middleLeftBox.innerHTML = player;
middleLeftBox.style.pointerEvents = 'none';
}
}
if(x=='middleMiddle'){
if(middleMiddleBox.innerHTML != 'o' && middleMiddleBox.innerHTML != 'x' ){
middleMiddleBox.innerHTML = player;
middleMiddleBox.style.pointerEvents = 'none';
}
}
if(x=='middleRight'){
if(middleRightBox.innerHTML != 'o' && middleRightBox.innerHTML != 'x'){
middleRightBox.innerHTML = player;
middleRightBox.style.pointerEvents = 'none';
}
}
if(x=='bottomLeft'){
if(bottomLeftBox.innerHTML != 'o' && bottomLeftBox.innerHTML != 'x'){
bottomLeftBox.innerHTML = player;
bottomLeftBox.style.pointerEvents = 'none';
}
}
if(x=='bottomMiddle'){
if(bottomMiddleBox.innerHTML != 'o' && bottomMiddleBox.innerHTML != 'x'){
bottomMiddleBox.innerHTML = player;
bottomMiddleBox.style.pointerEvents = 'none';
}
}
if(x=='bottomRight'){
if(bottomRightBox.innerHTML != 'o' && bottomRightBox.innerHTML != 'x'){
bottomRightBox.innerHTML = player;
bottomRightBox.style.pointerEvents = 'none';
}
}
checkWinCondition();
if(winDiv.style.visibility != 'visible'){
computerEasyModeMove();
checkWinCondition();
}
}
function computerEasyModeMove(){
if(player == 'x'){
computer = 'o';
}
if(player == 'o'){
computer = 'x';
}
var computerMove = Math.floor(Math.random() * 9) + 1;
while(computerMove == 1 && (topLeftBox.innerHTML == 'o' || topLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 2 && (topMiddleBox.innerHTML == 'o' || topMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 3 && (topRightBox.innerHTML == 'o' || topRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 4 && (middleLeftBox.innerHTML == 'o' || middleLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 5 && (middleMiddleBox.innerHTML == 'o' || middleMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 6 && (middleRightBox.innerHTML == 'o' || middleRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 7 && (bottomLeftBox.innerHTML == 'o' || bottomLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 8 && (bottomMiddleBox.innerHTML == 'o' || bottomMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 9 && (bottomRightBox.innerHTML == 'o' || bottomRightBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
if(computerMove == 1){
topLeftBox.innerHTML = computer;
topLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 2){
topMiddleBox.innerHTML = computer;
topMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 3){
topRightBox.innerHTML = computer;
topRightBox.style.pointerEvents = 'none';
}
if(computerMove == 4){
middleLeftBox.innerHTML = computer;
middleLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 5){
middleMiddleBox.innerHTML = computer;
middleMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 6){
middleRightBox.innerHTML = computer;
middleRightBox.style.pointerEvents = 'none';
}
if(computerMove == 7){
bottomLeftBox.innerHTML = computer;
bottomLeftBox.style.pointerEvents = 'none';
}
if(computerMove == 8){
bottomMiddleBox.innerHTML = computer;
bottomMiddleBox.style.pointerEvents = 'none';
}
if(computerMove == 9){
bottomRightBox.innerHTML = computer;
bottomRightBox.style.pointerEvents = 'none';
}
}
function computerMediumModeMove(){
}
function computerHardModeMove(){
}
function checkWinCondition(){
//Top 3 Player
if(topLeftBox.innerHTML == player && topMiddleBox.innerHTML == player && topRightBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Top 3 Computer
if(topLeftBox.innerHTML == computer && topMiddleBox.innerHTML == computer && topRightBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Middle 3 Player
if(middleLeftBox.innerHTML == player && middleMiddleBox.innerHTML == player && middleRightBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Middle 3 Computer
if(middleLeftBox.innerHTML == computer && middleMiddleBox.innerHTML == computer && middleRightBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Bottom 3 Player
if(bottomLeftBox.innerHTML == player && bottomMiddleBox.innerHTML == player && bottomRightBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Bottom 3 Computer
if(bottomLeftBox.innerHTML == computer && bottomMiddleBox.innerHTML == computer && bottomRightBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Left 3 Player (Up and Down)
if(bottomLeftBox.innerHTML == player && topLeftBox.innerHTML == player && middleLeftBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Left 3 Computer (Up and Down)
if(bottomLeftBox.innerHTML == computer && topLeftBox.innerHTML == computer && middleLeftBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Middle 3 Player (Up and Down)
if(bottomMiddleBox.innerHTML == player && topMiddleBox.innerHTML == player && middleMiddleBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Middle 3 Computer (Up and Down)
if(bottomMiddleBox.innerHTML == computer && topMiddleBox.innerHTML == computer && middleMiddleBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Right 3 Player (Up and Down)
if(bottomRightBox.innerHTML == player && topRightBox.innerHTML == player && middleRightBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Right 3 Computer (Up and Down)
if(bottomRightBox.innerHTML == computer && topRightBox.innerHTML == computer && middleRightBox.innerHTML == computer ){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Diagonal Left to Right Player (Down Slope)
if(bottomRightBox.innerHTML == player && topLeftBox.innerHTML == player && middleMiddleBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Diagonal Left to Right Computer (Down Slope)
if(bottomRightBox.innerHTML == computer && topLeftBox.innerHTML == computer && middleMiddleBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
//Diagonal Right to Left Player (Up Slope)
if(bottomLeftBox.innerHTML == player && topRightBox.innerHTML == player && middleMiddleBox.innerHTML == player){
ticTacBoard.style.pointerEvents = 'none';
winDiv.style.visibility = 'visible';
}
//Diagonal Right to Left Computer(Up Slope)
if(bottomLeftBox.innerHTML == computer && topRightBox.innerHTML == computer && middleMiddleBox.innerHTML == computer){
ticTacBoard.style.pointerEvents = 'none';
lossDiv.style.visibility = 'visible';
}
}
CSS:
#setup{
background-color:white;
height:75vh;
width:75vw;
}
#ticTacBoard{
text-transform:capitalize;
font-size:0vw;
background-color:white;
visibility:hidden;
position:absolute;
top:2vh;
}
#winDiv{
visibility:hidden;
background-color:white;
position:relative;
border:2px solid black;
}
#lossDiv{
visibility:hidden;
background-color:white;
position:relative;
border:2px solid black;
}
#tieDiv{
visibility:hidden;
background-color:white;
position:relative;
border:2px solid black;
}
#topLeft{
display:inline-block;
padding:30px;
border-right:2px solid black;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#topLeft:hover{
background-color:lightgrey;
}
#topMiddle{
display:inline-block;
padding:30px;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#topMiddle:hover{
background-color:lightgrey;
}
#topRight{
display:inline-block;
padding:30px;
border-left:2px solid black;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#topRight:hover{
background-color:lightgrey;
}
#middleLeft{
display:inline-block;
padding:30px;
border-right:2px solid black;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#middleMiddle:hover{
background-color:lightgrey;
}
#middleMiddle{
display:inline-block;
padding:30px;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#middleLeft:hover{
background-color:lightgrey;
}
#middleRight{
display:inline-block;
padding:30px;
border-left:2px solid black;
border-bottom:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#middleRight:hover{
background-color:lightgrey;
}
#bottomLeft{
display:inline-block;
padding:30px;
border-right:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#bottomLeft:hover{
background-color:lightgrey;
}
#bottomMiddle{
display:inline-block;
padding:30px;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#bottomMiddle:hover{
background-color:lightgrey;
}
#bottomRight{
display:inline-block;
padding:30px;
border-left:2px solid black;
width:15vw;
height:15vh;
font-size:9vw;
cursor:pointer;
}
#bottomRight:hover{
background-color:lightgrey;
}
body{
background-color:grey;
}
That happened because there's a flaw in your logic. I'll take a small portion of your code (look below):
var computerMove = Math.floor(Math.random() * 9) + 1;
while(computerMove == 1 && (topLeftBox.innerHTML == 'o' || topLeftBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
while(computerMove == 2 && (topMiddleBox.innerHTML == 'o' || topMiddleBox.innerHTML == 'x')){
computerMove = Math.floor(Math.random() * 9) + 1;
}
Consider this scenario: the first line of your code produces computerMove = 1
and the topLeftBox
is already filled with either 'x' or 'o' (doesn't matter). Then, we go to the second line (the first while
loop). Because it detects that the topLeftBox
is already filled, it will randomize a number. Say that the randomization gives computerMove = 2
. Then, as computerMove
is not 1
anymore, the first while
loop exits, proceeding to the second while
loop. For the sake of this example, let's assume that the topMiddleBox
is also filled with 'x' or 'o' already. It fulfills the loop condition and as a result, it randomizes a number. Say that it randomizes computerMove = 1
. The second loop's condition, which requires computerMove
to be of value 2
, is not fulfilled, thus exiting the loop. Problem: it produced a computerMove
of 1
and topLeftBox
is already filled. That's when your code failed.
I've also noticed that you gave all the div
s unique IDs. However, in this particular scenario, you can simplify the code by just giving all the div
s a class that you can iterate over. See the following code that solves your problem and removes the need for a specific ID for each div
in your particular case:
JS
let actionBox = document.querySelectorAll('div.action-box')
function computerEasyModeMove() {
let randomizeMove = () => Math.floor(Math.random() * 9)
let computerMove = randomizeMove()
computer = player == 'x' ? 'o' : 'x'
while (actionBox[computerMove].innerHTML.trim() != ' ') {
computerMove = randomizeMove()
}
actionBox[computerMove].innerHTML = computer
actionBox[computerMove].style.pointerEvents = 'none'
}
HTML (inside div#ticTacBoard
)
<div id='topLeft' class='action-box' onclick='move("topLeft")'> </div>
<div id='topMiddle' class='action-box' onclick='move("topMiddle")'> </div>
<div id='topRight' class='action-box' onclick='move("topRight")'> </div>
<br>
<div id='middleLeft' class='action-box' onclick='move("middleLeft")'> </div>
<div id='middleMiddle' class='action-box' onclick='move("middleMiddle")'> </div>
<div id='middleRight' class='action-box' onclick='move("middleRight")'> </div>
<br>
<div id='bottomLeft' class='action-box' onclick='move("bottomLeft")'> </div>
<div id='bottomMiddle' class='action-box' onclick='move("bottomMiddle")'> </div>
<div id='bottomRight' class='action-box' onclick='move("bottomRight")'> </div>
The forked code: here
I have not tested, But I think if you change it to following it should work (replace 9 while loops to 1 while loop). Idea is to make sure get the next random cell if already occupied.
var computerMove = Math.floor(Math.random() * 9) + 1;
while (computerMove == 1 && (topLeftBox.innerHTML == 'o' || topLeftBox.innerHTML == 'x')
|| (computerMove == 2 && (topMiddleBox.innerHTML == 'o' || topMiddleBox.innerHTML == 'x'))
|| (computerMove == 3 && (topRightBox.innerHTML == 'o' || topRightBox.innerHTML == 'x'))
|| (computerMove == 4 && (middleLeftBox.innerHTML == 'o' || middleLeftBox.innerHTML == 'x'))
|| (computerMove == 5 && (middleMiddleBox.innerHTML == 'o' || middleMiddleBox.innerHTML == 'x'))
|| (computerMove == 6 && (middleRightBox.innerHTML == 'o' || middleRightBox.innerHTML == 'x'))
|| (computerMove == 7 && (bottomLeftBox.innerHTML == 'o' || bottomLeftBox.innerHTML == 'x'))
|| (computerMove == 8 && (bottomMiddleBox.innerHTML == 'o' || bottomMiddleBox.innerHTML == 'x'))
|| (computerMove == 9 && (bottomRightBox.innerHTML == 'o' || bottomRightBox.innerHTML == 'x'))) {
computerMove = Math.floor(Math.random() * 9) + 1;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With