Javascript Turorial App - Viết ứng dụng chơi game cờ caro bằng JS
File index.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:600,700" rel="stylesheet">
<title>Caro App</title>
<style>
@import url('https://fonts.googleapis.com/css?family=Bubbler+One|Lato:400,900');
/* BASIC RESET AND SETUP */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #E0DDBC;
}
/* ============= */
/* TITLE STYLING */
.title-box {
margin: 10px auto;
width: 300px;
border-bottom: 2px solid black;
}
.title-box h1 {
text-align: center;
font: 60px 'Bubbler One', sans-serif;
}
/* ============= */
/* BOARD STYLING */
.container {
padding: 20px;
width: 360px;
margin: 10px auto;
border-radius: 23px;
}
.game-panel {
/* clear float */
overflow: hidden;
height: auto;
width: 300px;
margin: auto;
}
/* board colour */
.container,
.game-panel span {
background-color: #3581B8;
}
.game-panel span {
float: left;
width: 100px;
height: 100px;
cursor: pointer;
font: 400 80px 'Lato', sans-serif;
line-height: 90px;
text-align: center;
color: #92D5DD;
}
#box-0, #box-3, #box-6 {
border-right: 4px solid #92D5DD;
}
#box-2, #box-5, #box-8 {
border-left: 4px solid #92D5DD;
}
#box-3, #box-4, #box-5 {
border-top: 4px solid #92D5DD;
border-bottom: 4px solid #92D5DD;
}
/* ===================== */
/* CONTROL PANEL STYLING */
.control-panel,
.reset-area,
.control-panel h3 {
background-color: #3581B8;
}
.control-panel {
width: 360px;
padding: 15px;
margin-left: auto;
margin-right: auto;
margin-top: 15px;
border-radius: 23px;
color: #92D5DD;
}
.control-panel h3 {
text-align: center;
margin-top: -5px;
margin-bottom: 10px;
font: 900 25px 'Lato', sans-serif;
}
/* general buttons styling */
button {
border: 0;
border-radius: 10px;
position: relative;
background-color: #F9A03F;
box-shadow: 0px 6px #B7752D;
cursor: pointer;
}
button:active {
top: 4px;
background-color: #E28A2B;
box-shadow: 0px 2px #B7752D;
}
button:focus {
outline: 0;
}
/* X - O buttons styling */
#choose-x, #choose-o {
height: 60px;
width: 110px;
margin-bottom: 20px;
font: 400 24px 'Lato', sans-serif;
color: black;
}
#choose-x {
margin-left: 15px;
}
#choose-o {
margin-left: 75px;
}
.active {
top: 4px;
background-color: #E28A2B;
box-shadow: 0px 2px #B7752D;
cursor: default;
}
/* Start/Reset buttons styling */
#reset {
height: 60px;
width: 200px;
margin-left: 60px;
font: 400 18px 'Lato', sans-serif;
}
/* ===================== */
/* SIGNATURE STYLING */
p {
margin-top: 30px;
margin-bottom: 10px;
padding-top: 5px;
text-align: center;
font: 16px 'Bubbler One', sans-serif;
border-top: 1px solid black;
}
/* ===================== */
/* WINNING (or LOSING or DRAWING) MESSAGE */
.overlay {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
transition: 0.8s ease;
background-color: #3581B8;
cursor: pointer;
}
.message {
color: #FB3640;
position: absolute;
top: 40%;
left: 50%;
font: 400 40px 'Lato', sans-serif;
background-color: #3581B8;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div id="container">
<div class="title-box">
<h1>TIC-TAC-TOE</h1>
</div>
<div class="container">
<div class="game-panel">
<span id="box-0"></span>
<span id="box-1"></span>
<span id="box-2"></span>
<span id="box-3"></span>
<span id="box-4"></span>
<span id="box-5"></span>
<span id="box-6"></span>
<span id="box-7"></span>
<span id="box-8"></span>
</div>
</div>
<div class="control-panel">
<h3>C O N T R O L P A N E L</h3>
<button id="choose-x" class="active" disabled>X</button>
<button id="choose-o">O</button>
<div class="reset-area">
<button id="reset">START/RESET</button>
</div>
</div>
<div class="overlay">
<div class="message"></div>
</div>
<p>Designed & Coded in Brighton<br>by Arry Tapiheroe</p>
</div>
<script src="script.js"></script>
</body>
</html>
File app.js
// Javascript Tic Tac Toe App
// A project for FreeCodeCamp Front End Certification
// Designed and Coded in Brighton, Sussex, (pre-Brexit) England
// by Arry Tapiheroe
// I've lost (or, effectively utilised) many lunch times and post-dinner times in the coding of this app
// jQuery used when necessary
// initial game starts with player starting with "X"
var game = {
player: "X",
computer: "O",
turn: "player",
moves: 0,
over: false
};
// create the board as an array
// 0 | 1 | 2
// ---------
// 3 | 4 | 5
// ---------
// 6 | 7 | 8
var board = [0, 0, 0,
0, 0, 0,
0, 0, 0];
// WIN happens when the sums of either any rows, any columns or any diagonals
// are equal to "-3" for "O" or "3" for "X"
//
// ==================
// PLAYER CLICK BOARD
// ==================
// select the board panels
// add event listener for all the spans
var panels = document.querySelectorAll(".game-panel span");
for (var i = 0; i < panels.length; i++) {
panels[i].onclick = function(e) {
if (this.innerHTML == "") {
this.innerHTML = game.player;
game.turn = "player";
if (game.moves == 0) hidePanels();
game.moves++;
checkScore();
if (!game.over) computerMove();
}
};
}
// ======================
// COMPUTER MOVE FUNCTION
// ======================
function computerMove() {
game.turn = "computer";
if (game.moves == 0) hidePanels();
daMove();
game.moves++;
checkScore();
}
// initial AI is just.. well.. random
// THIS IS NOT AN AI!!
function daMove() {
var random = Math.floor(Math.random() * 9);
// recur the function if panel is already filled
if (panels[random].innerHTML != "") {
daMove();
} else {
panels[random].innerHTML = game.computer;
return;
}
}
// ====================
// CHECK SCORE FUNCTION
// ====================
function checkScore() {
// record the score in the board array
for (var j = 0; j < panels.length; j++) {
if (panels[j].innerHTML == "X") board[j] = 1;
else if (panels[j].innerHTML == "O") board[j] = -1;
}
var scoreArray = [
[board[0], board[1], board[2]],
[board[3], board[4], board[5]],
[board[6], board[7], board[8]],
[board[0], board[3], board[6]],
[board[1], board[4], board[7]],
[board[2], board[5], board[8]],
[board[0], board[4], board[8]],
[board[2], board[4], board[6]]
];
// go through scoreArray and see if there is a winner
var sumScore = [];
for (var k = 0; k < scoreArray.length; k++) {
sumScore[k] = scoreArray[k].reduce(function(a, b) {
return a + b;
}, 0);
// check if there's a winner
if (sumScore[k] == -3 || sumScore[k] == 3) {
game.over = true;
if (game.turn == "player") {
endMessage("WIN!");
} else {
endMessage("LOSE!");
}
return;
}
}
// check if it's a draw
if (game.moves == 9) {
game.over = true;
endMessage("DRAW..");
}
}
// ==============
// CONTROL PANELS
// ==============
$("#choose-x").on("click", function() {
game.player = "X";
game.computer = "O";
// disable this button (in appearance and class) & enable "O" button
$(this).prop("disabled", true)
.toggleClass("active");
$("#choose-o").prop("disabled", false)
.toggleClass("active");
});
$("#choose-o").on("click", function() {
game.player = "O";
game.computer = "X";
// disable this button (in appearance and class) & enable "X" button
$(this).prop("disabled", true)
.toggleClass("active");
$("#choose-x").prop("disabled", false)
.toggleClass("active");
});
// ====================
// START/RESET FUNCTION
// ====================
$("#reset").on("click", function() {
resetGame();
});
function resetGame() {
// if game hasn't started
// button will let computer starts
if (game.moves == 0) {
computerMove();
} else {
// otherwise
// reset the game objects
game.turn = "player";
game.moves = 0;
game.over = false;
// empty the panels
for (var j = 0; j < panels.length; j++) {
panels[j].innerHTML = "";
}
// show control panel back
$("#choose-x").slideDown("fast");
$("#choose-o").slideDown("fast");
// initialise the score board back
board = [0, 0, 0,
0, 0, 0,
0, 0, 0];
}
}
// ===============
// OTHER FUNCTIONS
// ===============
function hidePanels() {
$("#choose-x").slideUp("fast");
$("#choose-o").slideUp("fast");
}
function endMessage(message) {
$(".message").text(message);
$(".overlay").fadeTo("fast", 0.9);
}
$(".overlay").click(function() {
$(this).fadeOut("fast");
resetGame();
});