At work I am switching from AS3 to HTML5 for mobile game development, I have always hated JavaScript and developing for web but I have denied this transition for far too long and now I have to make the switch.
I would like for some of you to give me a little feedback on my simple Tic Tac Toe game. I only spent my lunch time writing this so ignore the rubbish AI or the fact that this should not all be on one HTML page (I know how to include a JavaScript file and CSS, but just wanted everything done quickly and ploughed in).
Not using classes or declaring variable types is so strange to me that the code just looks incomplete. I'm not sure if it has just been too long since I last coded a lot of JavaScript or I am to use to type casting but when I look at this code I feel like I am missing something obvious a junior would notice. Is the code fine or are there specific areas I should look into to improve?
<html>
<style>
#body {
display: block;
}
.grid {
position: absolute;
width: 300px;
height: 300px;
margin: auto;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
}
.squareButton {
width: 95px;
height: 95px;
border-radius: 20px;
background-color: #DDDDDD;
font-size: 40px;
color: #3333AA;
}
</style>
<script>
var gridArray = [0, 0, 0, 0, 0, 0, 0, 0, 0];
var aiSequence = [4, 0, 2, 6, 8, 1, 3, 5, 7];
var aiPlaying = true;
var aiPlayerId = 2;
var playerIdentifiers = ["-", "O", "X"];
var playersTurn = 1;
function onLoad() {
clearGrid();
}
function squareClicked(buttonId) {
if (gridArray[buttonId] == 0) {
setSquareToCurrentPlayer(buttonId);
} else {
alert("that square has been taken, please choose a different one :)");
}
}
function setSquareToCurrentPlayer(squareId) {
gridArray[squareId] = playersTurn;
endTurn();
}
function endTurn() {
updateGridDisplay();
if (endGame() == true) {
if (winCheck() == true) {
alert("GAME OVER!!! player " + playersTurn + " WINS!!! - hope you had fun :)");
} else {
alert("GAME OVER!!! No more spaces left :( Hope you had fun ;)");
}
} else {
playersTurn == 1 ? playersTurn = 2 : playersTurn = 1;
if (aiPlaying == true) {
if (playersTurn == aiPlayerId) {
runAi();
}
}
}
}
function runAi() {
var aiCanWin = false;
var playerCanWin = false;
for (var i = 0; i < 9; i++) {
if (gridArray[i] == 0) {
gridArray[i] = playersTurn;
if (winCheck()) {
aiCanWin = true;
break;
} else {
gridArray[i] = 0;
}
}
}
if (aiCanWin == false) {
for (i = 0; i < 9; i++) {
if (gridArray[i] == 0) {
gridArray[i] = playersTurn == 1 ? 2 : 1;
if (winCheck()) {
playerCanWin = true;
gridArray[i] = playersTurn;
break;
} else {
gridArray[i] = 0;
}
}
}
if (playerCanWin == false) {
for (i = 0; i < aiSequence.length; i++) {
if (gridArray[aiSequence[i]] == 0) {
gridArray[aiSequence[i]] = playersTurn;
break;
}
}
}
}
endTurn();
}
function endGame() {
if (winCheck() == true) {
return true;
} else {
if (allSquaresTaken() == true) {
return true;
} else {
return false;
}
}
}
function allSquaresTaken() {
var allSquaresHaveBeenTaken = true;
for (var i = 0; i < 9; i++) {
if (gridArray[i] == 0) {
allSquaresHaveBeenTaken = false;
break;
}
}
return allSquaresHaveBeenTaken;
}
function winCheck() {
if (
gridArray[0] == gridArray[1] && gridArray[1] == gridArray[2] && gridArray[0] > 0 ||
gridArray[3] == gridArray[4] && gridArray[4] == gridArray[5] && gridArray[3] > 0 ||
gridArray[6] == gridArray[7] && gridArray[7] == gridArray[8] && gridArray[6] > 0 ||
gridArray[0] == gridArray[3] && gridArray[3] == gridArray[6] && gridArray[0] > 0 ||
gridArray[1] == gridArray[4] && gridArray[4] == gridArray[7] && gridArray[1] > 0 ||
gridArray[2] == gridArray[5] && gridArray[5] == gridArray[8] && gridArray[2] > 0 ||
gridArray[0] == gridArray[4] && gridArray[4] == gridArray[8] && gridArray[0] > 0 ||
gridArray[2] == gridArray[4] && gridArray[4] == gridArray[6] && gridArray[2] > 0
) {
return true;
} else {
return false;
}
}
function clearGrid() {
for (var i = 0; i < 9; i++) {
gridArray[i] = 0;
}
updateGridDisplay();
}
function updateGridDisplay() {
for (var i = 0; i < 9; i++) {
document.getElementById("" + i).innerHTML = playerIdentifiers[gridArray[i]];
}
}
</script>
<body onload="onLoad()">
<div class="grid" id="gridContainer">
<button class="squareButton" onclick="squareClicked(this.id)" id="0">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="1">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="2">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="3">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="4">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="5">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="6">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="7">-</button>
<button class="squareButton" onclick="squareClicked(this.id)" id="8">-</button>
</div>
</body>
</html>
TypeScript
- it's like JavaScript (and gets compiled to JavaScript) but offery type saftey \$\endgroup\$if (endGame() == true)
(1) You don't need to compare with true. (2) If you do, use===
instead (also compares the types). Same forfalse
,1
,0
. In fact, it's best practice to always use===
instead of conventional==
\$\endgroup\$gridArray[2][2]
means versusgridArray[8]
. \$\endgroup\$