Tic-Tac-Toe

Developer
Size
5,278 Kb
Views
4,048

How do I make an tic-tac-toe?

Tic-Tac-Toe game built for freeCodeCamp Zipline. Uses OOP for game logic, Underscore.js for utility, jQuery, and Bootstrap.. What is a tic-tac-toe? How do you make a tic-tac-toe? This script and codes were developed by Zac Clemans on 14 January 2023, Saturday.

Tic-Tac-Toe Previews

Tic-Tac-Toe - Script Codes HTML Codes

<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Tic-Tac-Toe</title> <link href='https://fonts.googleapis.com/css?family=Play' rel='stylesheet' type='text/css'>
<meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> <link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css'>
<link rel='stylesheet prefetch' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'> <link rel="stylesheet" href="css/style.css">
</head>
<body> <h1 class="title">Tic-Tac-Toe</h1>
<div class="board-container"> <div class="board-row"> <div id="cell-0" class="column"></div> <div id="cell-1" class="column"></div> <div id="cell-2" class="column"></div> </div> <div class="board-row"> <div id="cell-3" class="column"></div> <div id="cell-4" class="column"></div> <div id="cell-5" class="column"></div> </div> <div class="board-row"> <div id="cell-6" class="column"></div> <div id="cell-7" class="column"></div> <div id="cell-8" class="column"></div> </div>
</div>
<div class="modal fade" id="player-info-modal" tab-index="-1" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h3>Welcome to Tic-Tac-Toe!</h3> </div> <div class="modal-body"> <form class="player-info" name="player-info" role="form"> <div class="form-group"> <label class="control-label" for="token-radio">Choose a token:</label> <label class="radio-inline"><input id="x-radio" class="token-select" type="radio" value="x"><i id="x-token" class="fa fa-times icon-select"></i></label> <label class="radio-inline"><input id="o-radio" class="token-select" type="radio" value="o"><i id="o-token" class="fa fa-circle-o icon-select"></i></label> </div> </form> </div> <div class="modal-footer"> <input class="btn btn-success" id="submit-player-info" type="submit" value="OK" > </div> </div> </div>
</div>
<div class="modal fade" id="repeat-game-modal" tab-index="-1" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> <h3>Play Game Again?</h3> </div> <div class="modal-footer"> <input class="btn btn-success" id="submit-again-confirm" type="submit" value="Yes"> <input class="btn btn-danger" id="submit-again-deny" type="submit" value="No"> </div> </div> </div>
</div> <script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore-min.js'></script>
<script src='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js'></script> <script src="js/index.js"></script>
</body>
</html>

Tic-Tac-Toe - Script Codes CSS Codes

body { font-family: "Play";
}
h3 { font-weight: bold;
}
.title { text-align: center; margin-top: 50px;
}
.board-container { width: 420px; margin: 100px auto;
}
.board-row { display: flex; justify-content: space-between; align-items: center; height: 130px;
}
.column { display: flex; align-items: center; justify-content: center; width: 140px; height: 130px;
}
#cell-0, #cell-1, #cell-2, #cell-3, #cell-4, #cell-5 { border-bottom: 2px solid black;
}
#cell-0, #cell-1, #cell-3, #cell-4, #cell-6, #cell-7 { border-right: 2px solid black;
}
.icon, .icon-select { font-size: 90px;
}
.icon-select { text-align: center; width: 100px;
}
.control-label { font-size: 24px;
}
input[type="radio"] { display: none;
}
div#player-info-modal, div#repeat-game-modal { margin-top: 100px;
}

Tic-Tac-Toe - Script Codes JS Codes

$("div#player-info-modal").modal();
$("input#submit-player-info").click(function(){ console.log(humanToken); var humanToken = $("input[type=radio]:checked").val(); $("div#player-info-modal").modal('hide'); var board = new Board(); var players = []; players.push(new Player(humanToken, "human")); if (humanToken == 'x'){ players.push(new Player("o", "computer")); } else{ players.push(new Player("x", "computer")); } var game = new Game(board, players); game.playGame();
});
function Game(board, players){ this.board = board; this.players = players; this.humanPlayer = players[0]; this.computerPlayer = players[1];
}
Game.prototype = { constructor: Game, playGame: function(){ console.log("game started") if (this.humanPlayer.getToken() == 'x'){ this.playerMove(); } else{ this.computerMove(); } }, isGameOver: function(){ return (this.board.isWinner() || this.board.isBoardFull()); }, playerMove: function(){ console.log("player move called"); // This refers to the selector in jQuery functions. // If aliased to 'self' beforehand, 'self' can be used to reference this object. var self = this; // Selector for all valid moves left in the game var positions = "#" + this.board.getValidMoves().join(",#") $(positions).on('click', function(){ var move = $(this).attr('id'); // Once a cell has been selected, turn it off $(positions).off('click'); self.board.setPlayerMove(move, self.humanPlayer.getToken()); if (!self.isGameOver()){ self.computerMove(); } else{ $("div#repeat-game-modal").modal(); self.playAgain(); } }); }, computerMove: function(){ var move = this.computerPlayer.getComputerMove(this.board); this.board.setPlayerMove(move, this.computerPlayer.getToken()); // Once a cell has been selected, turn it off $("#" + move).off('click'); if (!this.isGameOver()){ this.playerMove(); } else{ $("div#repeat-game-modal").modal(); this.playAgain(); } }, playAgain: function(){ var self = this; $("input#submit-again-confirm").click(function(){ $("div#repeat-game-modal").modal('hide'); $(".column").empty(); $("div#player-info-modal").modal(); }); $("input#submit-again-deny").click(function(){ $("div#repeat-game-modal").modal('hide'); }); }
}
function Board(){ this.POSITIONS = [ "#cell-0", "#cell-1", "#cell-2", "#cell-3", "#cell-4", "#cell-5", "#cell-6", "#cell-7", "#cell-8" ]; this.currentBoard = [ "", "", "", "", "", "", "", "", "" ]; this.validMoves = [ "cell-0", "cell-1", "cell-2", "cell-3", "cell-4", "cell-5", "cell-6", "cell-7", "cell-8" ]; this.WINNING_MOVES = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ];
}
Board.prototype = { constructor: Board, getPositions: function(){ return this.POSITIONS; }, getCurrentBoard: function(){ return this.currentBoard; }, getValidMoves: function(){ return this.validMoves; }, getWinningMoves: function(){ return this.WINNING_MOVES; }, isValidMove: function(move){ if (this.validMoves.indexOf(move) != -1){ return true; } else{ return false; } }, setPlayerMove: function(move, token){ this.currentBoard[this.POSITIONS.indexOf("#" + move)] = token; if (token == "x"){ $("#" + move).append("<i class='icon fa fa-times'></i>") } else { $("#" + move).append("<i class='icon fa fa-circle-o'></i>") } // Remove the move just made from the validMoves list. if (this.validMoves.indexOf(move) != -1){ this.validMoves = this.validMoves.slice(0, this.validMoves.indexOf(move)).concat( this.validMoves.slice(this.validMoves.indexOf(move) + 1)); } }, isBoardFull: function(){ return this.currentBoard.every(function(cell){ return (cell == "x" || cell == "o"); }); }, isWinner: function(){ var winner = false; var b = this.currentBoard; this.WINNING_MOVES.forEach(function(moveSet){ if (b[moveSet[0]] == b[moveSet[1]] && b[moveSet[1]] == b[moveSet[2]]){ if (b[moveSet[0]] != ""){ var winningPositions = []; for (var i = 0; i < moveSet.length; i++){ winningPositions.push("#cell-" + moveSet[i] + " > i"); } winningPositions = winningPositions.join(","); $(winningPositions).css('color', 'red'); $(winningPositions).fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200).fadeOut(200).fadeIn(200); winner = true; // return true would only end the forEach function, not the isWinner function } } }); return winner; }, resetBoard: function(){ this.currentBoard = [ "", "", "", "", "", "", "", "", "" ]; this.validMoves = [ "cell-0", "cell-1", "cell-2", "cell-3", "cell-4", "cell-5", "cell-6", "cell-7", "cell-8" ]; }
}
function Player(token, playerType){ this.token = token; this.playerType = playerType;
}
Player.prototype = { constructor: Player, getToken: function(){ return this.token; }, getPlayerType: function(){ return this.playerType; }, getComputerMove: function(board){ // Placeholder until AI is implemented var self = this; if (returnWinOrBlockMove(board)){ return returnWinOrBlockMove(board); } else if (returnMakeForkMove(board)){ return returnMakeForkMove(board); } else if (returnBlockForkMove(board)){ return returnBlockForkMove(board); } else if (returnCenterMove(board)){ return returnCenterMove(board); } else if (returnOppositeCornerMove(board)){ return returnOppositeCornerMove(board); } else if (returnEmptyCornerMove(board)){ return returnEmptyCornerMove(board); } else if (returnEmptySideMove(board)){ return returnEmptySideMove(board); } else{ var move = board.getValidMoves()[Math.floor(Math.random()*board.getValidMoves().length)]; return move; } function returnWinOrBlockMove(board){ var winOrBlock = ''; for (var i = 0; i < board.getWinningMoves().length; i++){ var moveSet = board.getWinningMoves()[i]; //board.WINNING_MOVES.forEach(function(moveSet){ var winState = _.countBy(moveSet, function(position){ if (board.getCurrentBoard()[position] == self.token){ return 'compToken'; } else if (board.getCurrentBoard()[position] == ''){ return 'empty'; } else{ return 'humanToken'; } }); if (winState.compToken == 2 && winState.empty == 1){ for (var j = 0; j < moveSet.length; j++){ var position = moveSet[j]; if (board.getCurrentBoard()[position] == ''){ winOrBlock = "cell-" + position; return winOrBlock; } } } else if (winState.humanToken == 2 && winState.empty == 1){ for (var j = 0; j < moveSet.length; j++){ var position = moveSet[j]; if (board.getCurrentBoard()[position] == ''){ winOrBlock = "cell-" + position; } } } } return winOrBlock; } function returnMakeForkMove(board){ var move = ''; var boardCopy = $.extend(true, {}, board); for (var potentialMove = 0; potentialMove < boardCopy.getCurrentBoard().length; potentialMove++){ if (boardCopy.getCurrentBoard()[potentialMove] == ''){ boardCopy.getCurrentBoard()[potentialMove] = self.token; } else{ continue; } if (countWins(boardCopy) >= 2){ move = "cell-" + potentialMove; } boardCopy.getCurrentBoard()[potentialMove] = ''; } return move; } function returnBlockForkMove(board){ var move = ''; var boardCopy = $.extend(true, {}, board); var badMoves = []; for (var potentialMove = 0; potentialMove < boardCopy.getCurrentBoard().length; potentialMove++){ if (boardCopy.getCurrentBoard()[potentialMove] == ''){ if (self.token == 'x'){ boardCopy.getCurrentBoard()[potentialMove] = 'o'; } else{ boardCopy.getCurrentBoard()[potentialMove] = 'x'; } } else{ continue; } if (countLosses(boardCopy) >= 2){ boardCopy.getCurrentBoard()[potentialMove] = self.token; if (returnBlockForkMove(boardCopy)){ badMoves.push(potentialMove); } else{ move = "cell-" + potentialMove; return move; } } boardCopy.currentBoard[potentialMove] = ''; } for (var potentialMove = 0; potentialMove < boardCopy.getCurrentBoard().length; potentialMove++){ if (boardCopy.getCurrentBoard()[potentialMove] == '' && badMoves.indexOf(potentialMove) == -1){ boardCopy.getCurrentBoard()[potentialMove] = self.token; } else{ continue; } if (countWins(boardCopy) >= 1){ move = "cell-" + potentialMove; return move; } boardCopy.getCurrentBoard()[potentialMove] = ''; } return move; } function returnCenterMove(board){ if(board.getCurrentBoard()[4] == ''){ return "cell-4"; } else{ return ''; } } function returnOppositeCornerMove(board){ var corners = [[0,8], [2, 6]]; var move = ''; corners.forEach(function(corner){ if ((board.getCurrentBoard()[corner[0]] != self.token) && (board.getCurrentBoard()[corner[0]] != '')){ move = board.getCurrentBoard()[corner[1]] == '' ? ("cell-" + corner[1]) : ''; } else if ((board.getCurrentBoard()[corner[1]] != self.token) && (board.getCurrentBoard()[corner[1]] != '')){ move = board.getCurrentBoard()[corner[0]] == '' ? ("cell-" + corner[0]) : ''; } }); return move; } function returnEmptyCornerMove(board){ var move = ''; var corners = [0, 2, 6, 8]; var emptyCorners = []; for (var i = 0; i < corners.length; i++){ if (board.getCurrentBoard()[corners[i]] == ''){ emptyCorners.push(corners[i]); } } if (emptyCorners.length > 0){ move = "cell-" + _.sample(emptyCorners); } return move; } function returnEmptySideMove(board){ var move = ''; var sides = [1, 3, 5, 7]; var emptySides = []; for (var i = 0; i < sides.length; i++){ if (board.getCurrentBoard()[sides[i]] == ''){ emptySides.push(sides[i]); } } if (emptySides.length > 0){ move = "cell-" + _.sample(emptySides); } return move; } function countWins(board){ var winsAvailable = 0; for (var i = 0; i < board.getWinningMoves().length; i++){ var moveSet = board.getWinningMoves()[i]; //board.WINNING_MOVES.forEach(function(moveSet){ var winState = _.countBy(moveSet, function(position){ if (board.getCurrentBoard()[position] == self.token){ return 'compToken'; } else if (board.getCurrentBoard()[position] == ''){ return 'empty'; } else{ return 'humanToken'; } }); if (winState.compToken == 2 && winState.empty == 1){ winsAvailable++; } } return winsAvailable; } function countLosses(board){ var lossesAvailable = 0; for (var i = 0; i < board.getWinningMoves().length; i++){ var moveSet = board.getWinningMoves()[i]; var winState = _.countBy(moveSet, function(position){ if (board.getCurrentBoard()[position] == self.token){ return 'compToken'; } else if (board.getCurrentBoard()[position] == ''){ return 'empty'; } else{ return 'humanToken'; } }); if (winState.humanToken == 2 && winState.empty == 1){ lossesAvailable++; } } return lossesAvailable; } }
}
$("input[type=radio]").click(function(){ if ($(this).attr('id') == 'x-radio'){ $("i#o-token").css({'border': 'none'}); $("i#x-token").css({'border': '3px solid red', 'border-radius': '50%'}); $("input#o-radio").prop('checked', false); } else{ $("i#x-token").css({'border': 'none'}); $("i#o-token").css({'border': '3px solid red', 'border-radius': '50%'}); $("input#x-radio").prop('checked', false); }
});
window.onload = main;
Tic-Tac-Toe - Script Codes
Tic-Tac-Toe - Script Codes
Home Page Home
Developer Zac Clemans
Username thalpha
Uploaded January 14, 2023
Rating 3
Size 5,278 Kb
Views 4,048
Do you need developer help for Tic-Tac-Toe?

Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!

Zac Clemans (thalpha) Script Codes
Create amazing captions with AI!

Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!