Skip to content

Instantly share code, notes, and snippets.

@DanCouper
Created April 5, 2017 09:20
Show Gist options
  • Save DanCouper/a8de79c3ed6f9120fd7867aee94b12d2 to your computer and use it in GitHub Desktop.
Save DanCouper/a8de79c3ed6f9120fd7867aee94b12d2 to your computer and use it in GitHub Desktop.
yMrzEB
<!--FCC Tic Tac Toe-->
<header></header>
<main>
<button onclick='gameData.reset()'>New Game</button>
<section id='gameOverall'>
<div id='gameCentral' class='gameCentralDefault'></div>
</section>
</main>
<footer></footer>
//FCC TIC TAC TOE GAME
//********************************************************
//********************************************************
//OBJECT TO HOLD STATE OF GAME
var gameData = {
//data
p1: {
being: 'Human',
shape: 'nought',
hasWon: false
},
p2: {
being: 'Human',
shape: 'cross',
hasWon: false
},
whoseTurn: 'p1',
turn: 0,
board: [
{name: 'topLeft', shape: 'empty', row: 0, col: 0},
{name: 'topMiddle', shape: 'empty', row: 0, col: 1},
{name: 'topRight', shape: 'empty', row: 0, col: 2},
{name: 'centerLeft', shape: 'empty', row: 1, col: 0},
{name: 'centerMiddle', shape: 'empty' , row: 1, col: 1},
{name: 'centerRight', shape: 'empty', row: 1, col: 2},
{name: 'bottomLeft', shape: 'empty', row: 2, col: 0},
{name: 'bottomMiddle', shape: 'empty', row: 2, col: 1},
{name: 'bottomRight', shape: 'empty', row: 2, col: 2}
],
stages: [
'choosePlayers',
'chooseShape',
'playing',
'endGame'
],
currentStage: 0,
//methods
//expects a str ('p1' or 'p2'). Toggles being of that player.
changeBeing: function(player) {
if (this[player].being === 'Human') {
this[player].being = 'AI';
}
else {
this[player].being = 'Human';
}
},
//expects a str ('p1' or 'p2'). Toggles shape of that player.
changeShape: function() {
if (this.p1.shape === 'nought') {
this.p1.shape = 'cross';
this.p2.shape = 'nought';
}
else if (this.p1.shape === 'cross') {
this.p1.shape = 'nought';
this.p2.shape = 'cross';
}
},
//expects a str ('p1' or 'p2'). Sets hasWon to true for that player.
winner: function(player) {
this[player].hasWon = true;
},
//toggles which players turn it is.
changeTurn: function() {
if (this.whoseTurn === 'p1') {
this.whoseTurn = 'p2';
}
else {
this.whoseTurn = 'p1';
}
},
//expects a str ('p1' or 'p2' & square (eg topLeft), places a shape onto the board.
placeShape: function(square) {
this.board.forEach(function(element) {
if( element.name === square && element.shape === 'empty' ) {
element.shape = this[this.whoseTurn].shape;
}
}, this);
},
//resets gameData *** USE THIS SOMEWHERE!!!!
reset: function() {
this.p1.being = 'Human';
this.p1.shape = 'nought';
this.p1.hasWon = false;
this.p2.being = 'Human';
this.p2.shape = 'cross';
this.p2.hasWon = false;
this.whoseTurn = 'p1';
this.board.forEach(function(element) {
element.shape = 'empty';
});
this.currentStage = 0;
doTurn();
},
//progresses game stage
nextStage: function() {
this.currentStage++;
if (this.currentStage > this.stages.length - 1) {
this.currentStage = 0;
}
}
}//END OF gameData
//********************************************************
//********************************************************
//FUNCTION TO RENDER BOARD
function renderGame() {
var gameCentral = document.getElementById('gameCentral');
wipe();
switch(gameData.currentStage) {
case 0:
choosePlayers();
break;
case 1:
chooseShape();
break;
case 2:
playing();
break;
case 3:
endGame();
break;
default:
console.log('Unexpected stage in switch statement of renderGame()');
}
//Put the game board back to all empty squares
function wipe() {
while (gameCentral.firstChild) {
gameCentral.removeChild(gameCentral.firstChild);
}
gameCentral.className = '';
gameCentral.classList.add('gameCentralDefault');
}//End of wipe()
//Choose if players are any combination of AI or Human
function choosePlayers() {
//Create the message dialog node
var msg = document.createElement('p');
var msgContent = document.createTextNode('How do you want to play?');
//Create the next stage button node
var nextButton = document.createElement('div');
var nextButtonContent = document.createTextNode('NEXT');
//Create the player one option node
var p1Being = document.createElement('div');
var p1BeingMsg = 'P1: ' + gameData.p1.being;
var p1BeingMsgContent = document.createTextNode(p1BeingMsg);
//Create the player two option node
var p2Being = document.createElement('div');
var p2BeingMsg = 'P2: ' + gameData.p2.being;
var p2BeingMsgContent = document.createTextNode(p2BeingMsg);
//Append message to DOM
msg.appendChild(msgContent);
gameCentral.appendChild(msg);
//Append nextButton to DOM
nextButton.appendChild(nextButtonContent);
gameCentral.appendChild(nextButton);
nextButton.onclick = function() {
gameData.nextStage();
doTurn();
};
//Append p1 option node to DOM
p1Being.appendChild(p1BeingMsgContent);
gameCentral.appendChild(p1Being);
p1Being.onclick = function() {
gameData.changeBeing('p1');
doTurn();
};
//Append p2 option node to DOM
p2Being.appendChild(p2BeingMsgContent);
gameCentral.appendChild(p2Being);
p2Being.onclick = function() {
gameData.changeBeing('p2');
doTurn();
}
//Add style classes for newly created nodes
gameCentral.classList.add('gameCentralOptions');
msg.classList.add('optionsMsg');
nextButton.classList.add('nextButton');
p1Being.classList.add('chooseOptions');
p2Being.classList.add('chooseOptions');
}//End of choosePlayers()
function chooseShape() {
//Create message dialog node
var msg = document.createElement('p');
var msgContent = document.createTextNode('Should player one be noughts or crosses?');
//Create the next stage button node
var nextButton = document.createElement('div');
var nextButtonContent = document.createTextNode('NEXT');
//Create the shape option node
var chosenShape = document.createElement('div');
var chosenShapeMsg = gameData.p1.shape;
var chosenShapeContent = document.createTextNode(chosenShapeMsg);
//Append msg to DOM
msg.appendChild(msgContent);
gameCentral.appendChild(msg);
//Append nextButton to DOM
nextButton.appendChild(nextButtonContent);
gameCentral.appendChild(nextButton);
nextButton.onclick = function() {
gameData.nextStage();
doTurn();
};
//Append chosenShape to DOM
chosenShape.appendChild(chosenShapeContent);
gameCentral.appendChild(chosenShape);
chosenShape.onclick = function() {
gameData.changeShape();
doTurn();
};
//Style newly created nodes
gameCentral.classList.add('gameCentralOptions');
msg.classList.add('optionsMsg');
nextButton.classList.add('nextButton');
chosenShape.classList.add('chooseOptions');
}//End of chooseShape()
function playing() {
var boardSquare;
var boardSquareShape;
var boardSquareContent;
//smells having state changed by the rendering function but too stupid to think of alternative
gameData.turn++;
//Create 9 squares on board
gameData.board.forEach(function(element) {
if (element.shape === 'nought') {
boardSquareShape = 'O';
} else if (element.shape === 'cross') {
boardSquareShape = 'X';
} else if (element.shape === 'empty') {
boardSquareShape = '---';
}
boardSquare = document.createElement('div');
boardSquareContent = document.createTextNode(boardSquareShape);
boardSquare.appendChild(boardSquareContent);
gameCentral.appendChild(boardSquare);
boardSquare.id = element.name;
//get this logic out of the render function
boardSquare.onclick = function() {
if (gameData[gameData.whoseTurn].being === 'Human') {
gameData.placeShape(element.name);
doTurn();
}
};
gameCentral.classList.add('gameCentralPlaying');
boardSquare.classList.add('boardSquare');
});
//Populate squares with shape from gameData board
}//End of playing()
//Not finished ***
function endGame() {
var player;
if (gameData.p1.hasWon === true) {
player = 'ONE';
} else if (gameData.p2.hasWon === true) {
player = 'TWO';
}
console.log('GAME OVER: ' + player + ' WON');
}//End of endGame()
}//END OF renderGame()
//********************************************************
//********************************************************
//FUNCTION TO CALC IF GAME FINISHED
function checkForComplete() {
//Avoid lines 57km long
var lowRight = gameData.board[8].shape;
var midMid = gameData.board[4].shape;
var upLeft = gameData.board[0].shape;
var lowLeft = gameData.board[6].shape;
var upRight = gameData.board[2].shape;
//Evaluate to true if all 3 squares of a diagonal containt teh same shape
var diagA = (lowRight === midMid ) && (upLeft === midMid);
var diagB = (lowLeft === midMid ) && (upRight === midMid)
//If an element reaches 3 or -3 then a player has won
var victoryConditions = [
0,//top
0,//middle row
0,//bottom row
0,//left col
0,//midle col
0,//right col
0//diag, either
]
//Check for a win (minus diagonal victory conditions)
gameData.board.forEach(function(element) {
if (element.shape === gameData.p1.shape) {
victoryConditions[element.row]++;
victoryConditions[element.col + 3]++;
} else if (element.shape === gameData.p2.shape) {
victoryConditions[element.row]--;
victoryConditions[element.col + 3]--;
}
});
//Check diagonal victories
if ( diagA || diagB ) {
console.log('diagonal found');
if (gameData.board[4].shape === gameData.p1.shape) {
victoryConditions[6] = 3;
} else if (gameData.board[4].shape === gameData.p2.shape) {
victoryConditions[6] = -3;
}
}
//Check if either player has won
victoryConditions.forEach(function(element) {
if (element === 3) {
gameData.winner('p1');
} else if (element === -3) {
gameData.winner('p2');
}
});
//check if draw
//game ended, move to next stage
if (gameData.p1.hasWon === true || gameData.p2.hasWon === true) {
gameData.nextStage();
}
}//END OF checkForComplete()
//********************************************************
//********************************************************
//FUNCTION TO MOVE AI
//jesus christ how do i do this!
function AIMove(ai) {
console.log('moving ' + ai);
}
//********************************************************
//********************************************************
//FUNCTION TO DO TURN
function doTurn() {
if (gameData.turn > 0) {
gameData.changeTurn();
}
if (gameData.p1.being === 'AI') {
AIMove('p1');
}
if (gameData.p2.being === 'AI') {
AIMove('p2');
}
checkForComplete();
renderGame();
}
//********************************************************
//********************************************************
//FUNCTION
function newGame(){
gameData.reset();
}
:root {
--main-bg-color: #999999;
--gameOverall-bg-color: #222222;
--gameCentral-bg-color: #356634;
--shape-color: #ffffff;
}
* {
box-sizing: border-box;
border: 2px solid red;/*for dev only*/
}
html, body {
height: 100%;
margin: 0px;
}
/*LAYOUT ON SCREEN*/
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
main {
display: flex;
flex-direction: row;
justify-content: center;
flex-grow: 0;
flex-shrink: 0;
width: 100%;
background-color: var(--main-bg-color);
}
header, footer {
flex-grow: 1;
flex-shrink: 1;
width: 100%;
background-color: var(--main-bg-color);
}
/*GAME BOARD STYLING*/
#gameOverall {
width: 400px;
height: 400px;
background-color: var(--gameOverall-bg-color);
}
/*GAME BOARD - DEFAULT STYLING*/
.gameCentralDefault {
width: 90%;
height: 90%;
margin: 5%;
background-color: var(--gameCentral-bg-color);
}
/*GAME BOARD - STAGE=CHOOSING PLAYERS STYLING*/
.gameCentralOptions {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: space-around;
}
.optionsMsg {
flex-grow: 0;
flex-shrink: 0;
width: 80%;
height: 25%;
font-size: 30px;
text-align: center;
margin-top: 5%;
}
.nextButton {
flex-grow: 0;
flex-shrink: 0;
width: 80%;
height: 25%;
font-size: 66px;
text-align: center;
margin-top: -5%;
margin-bottom: 5%;
}
.chooseOptions {
flex-grow: 0;
flex-shrink: 0;
width: 40%;
height: 25%;
font-size: 36px;
text-align: center;
}
.boardSquare {
width: 33.3%;
height: 33.3%;
font-size: 36px;
color: var(--shape-color);
display: flex;
justify-content: center;
align-items: center;
}
.gameCentralPlaying {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-start;
justify-content: flex-start;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment