TicTacToe

In this example below you will see how to do a TicTacToe with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by erawk26, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright erawk26 ©
  • HTML
  • CSS
  • JavaScript
    .container.col-xs-12.center
	.header
		h1#title Tic Tac Toe
		#message.msg.animated
		.sw-container
			label.center
				span.cir-label
				input#x-switch.switch(type='checkbox' checked='')
				div
					div
				span.exx-label
	#gameBox.gameBox
		.col1.col-xs-4
			#sq1.square.row1.unchecked.center(role='button')
			#sq4.square.row2.unchecked.center(role='button')
			#sq7.square.row3.unchecked.center(role='button')
		.col2.col-xs-4
			#sq2.square.row1.unchecked.center(role='button')
			#sq5.square.row2.unchecked.center(role='button')
			#sq8.square.row3.unchecked.center(role='button')
		.col3.col-xs-4
			#sq3.square.row1.unchecked.center(role='button')
			#sq6.square.row2.unchecked.center(role='button')
			#sq9.square.row3.unchecked.center(role='button')


/*Downloaded from https://www.codeseek.co/erawk26/tictactoe-YqWWaQ */
    $fontBody: $fontAdvent;
$fontHead: $fontAdvent;
$primary: #b64926;
$secondary: #b67926;
$tertiary: #b62633;
$quadrary: #2693b6;
$quinary: tint($secondary, 90%);
$darkQuad: shade($quadrary, 76%);
$switch1: $quadrary;
$switch2: $primary;
$switch3: #e8e8e8;
div {
	transition: background 0.35s ease-out;
}
body {
	@extend .center;
	overflow: hidden;
	font-family: $fontBody;
	text-align: center;
	color: $darkQuad;
	flex-direction: column;
}
h1,
h2,
h3,
h4,
h5 {
	font-family: $fontHead;
}
h3,
h4 {
}
.container {
	@extend .argyle;
	background-color: $tertiary;
	@include flex($direction:column);
	height: 100vh;
	margin: 0;
	padding: 0;
}
.gameBox {
	background: $darkQuad;
	overflow: hidden;
	//@extend .border-bl;
	@include border-radius(10%);
	@include single-box-shadow(5px,5px, 18px, 0, #000);
	min-width: 125px;
	min-height: 125px;
	width: 85vw;
	height: 85vw;
	max-height: 70vh;
	max-width: 70vh;
}
.header {
	//@extend .border-bl;
	max-width: 320px;
	width: 100%;
	height: auto;
	padding-bottom: 20px;
	color: $quinary;
	.msg {
		margin-left: auto;
		margin-right: auto;
		@include border-radius(25px);
		width: 90%;
		font-size: 1.5em;
		background: shade($tertiary, 20);
		color: $quinary;
		flex-wrap: wrap;
		padding: 4px 12px;
	}
}

.col-xs-4 {
	height: 100%;
	padding: 0;
	margin: 0;
}
.square {
	@include single-text-shadow(3px, 3px, 4px, 1px, #000);
	color: $quinary;
	background: $darkQuad;
	width: 100%;
	height: 33.3334%;
	&:hover {
		background: shade($darkQuad, 50);
	}
	&:active {
		background: tint($darkQuad, 50);
	}
}
.score {
	color: $quinary;
	padding: 0 3px;
}
.cir,
.exx {
	&:before{font-family: FontAwesome;}
	font-size: 14px;
}
.cir:before {
	color: $quadrary;
	content: "\f10c";
	font-size: calc(1em + 15vw);
	@media (min-width: 600px) {
		font-size: calc(1em + 11vw);
	}
}
.exx:before {
	color: $primary;
	content: "\f00d";
	font-size: calc(1em + 18vw);
	@media (min-width: 600px) {
		font-size: calc(1em + 13vw);
	}
}
.sw-container {
	@include single-text-shadow(1px, 1px, 1.25px, 0.33px, #000);
	width: 100%;
	@extend .center;
	.cir-label:before {
		@extend .cir:before;
		font-size: 20px;
	}
	.exx-label:before {
		@extend .exx:before;
		font-size: 20px;
	}
	input[type="checkbox"] {
		position: absolute;
		opacity: 0;
	}
}
.row1,
.row2 {
	border-bottom: 5px solid $quinary;
}
.col1,
.col2 {
	border-right: 5px solid $quinary;
}
//Argyle Pattern//
.argyle {
	background-image: repeating-linear-gradient(
			120deg,
			rgba(255, 255, 255, 0.1),
			rgba(255, 255, 255, 0.1) 1px,
			transparent 1px,
			transparent 60px
		),
		repeating-linear-gradient(
			60deg,
			rgba(255, 255, 255, 0.1),
			rgba(255, 255, 255, 0.1) 1px,
			transparent 1px,
			transparent 60px
		),
		linear-gradient(
			60deg,
			rgba(0, 0, 0, 0.1) 25%,
			transparent 25%,
			transparent 75%,
			rgba(0, 0, 0, 0.1) 75%,
			rgba(0, 0, 0, 0.1)
		),
		linear-gradient(
			120deg,
			rgba(0, 0, 0, 0.1) 25%,
			transparent 25%,
			transparent 75%,
			rgba(0, 0, 0, 0.1) 75%,
			rgba(0, 0, 0, 0.1)
		);
	background-size: 70px 120px;
}
///////////////////Toggle Switch/////////
/* Normal Track */
input[type="checkbox"].switch + div {
	@include single-box-shadow(1px, 1px, 1.25px, 0.33px, #000);
	vertical-align: middle;
	width: 40px;
	height: 20px;
	border: 1px solid shade($switch1, 20);
	border-radius: 999px;
	background-color: $switch1;
	-webkit-transition-duration: 0.4s;
	-webkit-transition-property: background-color, box-shadow;
	box-shadow: inset 0 0 0 0px rgba(0, 0, 0, 0.4);
	margin: 8px 4px 8px 6px;
}

/* Checked Track */
input[type="checkbox"].switch:checked + div {
	@include single-box-shadow(1px, 1px, 1.25px, 0.33px, #000);
	width: 40px;
	background-position: 0 0;
	background-color: $switch2;
	border: 1px solid shade($switch2, 40);
	box-shadow: inset 0 0 0 10px tint($switch2, 10);
}

/* Normal Knob */
input[type="checkbox"].switch + div > div {
	float: left;
	width: 16px;
	height: 16px;
	border-radius: inherit;
	background: $switch3;
	-webkit-transition-timing-function: cubic-bezier(0.54, 1.85, 0.5, 1);
	-webkit-transition-duration: 0.4s;
	-webkit-transition-property: transform, background-color, box-shadow;
	-moz-transition-timing-function: cubic-bezier(0.54, 1.85, 0.5, 1);
	-moz-transition-duration: 0.4s;
	-moz-transition-property: transform, background-color;
	box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3), 0px 0px 0 1px rgba(0, 0, 0, 0.4);
	pointer-events: none;
	margin: 1px;
}

/* Checked Knob */
input[type="checkbox"].switch:checked + div > div {
	-webkit-transform: translate3d(20px, 0, 0);
	-moz-transform: translate3d(20px, 0, 0);
	background-color: $switch3;
	box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3), 0px 0px 0 1px shade($switch2, 20);
}
.switch:disabled {
	background-color: #333;
}



/*Downloaded from https://www.codeseek.co/erawk26/tictactoe-YqWWaQ */
    var usr = 'exx',
	cpu = 'cir',
	fadeIn = 'bounceInDown',
	fadeOut = 'fadeOutDownBig',
	available,
	usrArr,
	cpuArr,
	record = [0, 0, 0],
	winKey = [
		[1, 4, 7],
		[2, 5, 8],
		[3, 6, 9],
		[1, 2, 3],
		[4, 5, 6],
		[7, 8, 9],
		[1, 5, 9],
		[3, 5, 7]
	];
$(document).ready(function() {
	$('#gameBox,#message').addClass("animated " + fadeIn);
	$('#message').html("Wins:<span class='score'>0</span>&nbsp;Losses:<span class='score'>0</span>&nbsp;Ties:<span class='score'>0</span>");
	squares();
});
$('#x-switch').click(function() {
	ai();
});
$('.square').click(function() { // actions to take when user clicks a square
	if ($(this).hasClass('unchecked') && !turn()) { //make sure the square hasnt already been marked
		$(this).removeClass('unchecked').addClass(usr); // add the users mark to the current square
		squares(); //  read the board
		winner(); //   check for winners
	}
	if(available.length > 0){
		//    tell computer to go
		ai();
	}
	
});
//////// reads the board and updates arrays
function squares() {
	if ($('.sw-container input[type="checkbox"]#x-switch:checked').length < 1) {
		usr = 'cir';
		cpu = 'exx';
	} else {
		usr = 'exx';
		cpu = 'cir';
	}
	available = read('unchecked');
	usrArr = read(usr);
	cpuArr = read(cpu);
	
	function read (x){
		return [].map.call(document.getElementsByClassName(x), (num)=>Number(num.getAttribute("id").replace(/[\D]/g,'')));
	}
}
//////// check for a winner
function terminal(usrX, cpuY) {
	var winTest = (arr1, arr2)=>arr1.filter((val)=>arr2.indexOf(val) !== -1).length === 3,//function to find matches out of array
		score = false;
	winKey.map(function(arr) {
		if (winTest(arr, usrX)) {
			score = -10;
		} //CPU LOOSES
		if (winTest(arr, cpuY)) {
			score = 10;
		} //CPU WINS
	});
	if (available.length < 1 && !score) {
		score = 0
	} //DRAW
	return score;
}
//////// what to do when the game has finished
function winner() {
	var clearIt = function() {
		$('.gameBox,#message').removeClass(fadeIn + " " + fadeOut).addClass(fadeOut);
	$('.sw-container').slideDown("slow","swing");
		setTimeout(function() {
			$('.gameBox,#message').removeClass(fadeIn + " " + fadeOut).addClass(fadeIn);
			$('.square').removeClass(usr + " " + cpu).addClass('unchecked');
			$('#title').text('Tic Tac Toe');
			$('#message').html("Wins:<span class='score'><strong>" + record[0] + "</strong></span>&nbsp;Losses:<span class='score'><strong>" + record[1] + "</strong></span>&nbsp;Ties:<span class='score'><strong>" + record[2] + "</strong></span>");
		}, 1000);
		squares();
		setTimeout(ai, 4000);
	};
	switch (terminal(usrArr, cpuArr)) {
		case -10:
			$('#title').html('You Win!!!!!!!');
			record[0]++;
			setTimeout(clearIt, 1000);
			break;
		case +10:
			$('#title').html('You Lost!!');
			record[1]++;
			setTimeout(clearIt, 1000);
			break;
		case 0:
			$('#title').html('DRAW');
			record[2]++;
			setTimeout(clearIt, 1000);
			break;
	}
	//console.log(terminal());
}
//////// check to see if its the computers turn
function turn() {
	var checked = $('.sw-container input[type="checkbox"]#x-switch:checked').length > 0;//if the switch is set to X
	squares();
	//its the CPU's turn when theres an even number of remaining squares
	//or if switch is set to O, CPU's turn on Odd nums instead
	return checked ? available.length % 2 === 0 : available.length % 2 === 1;
}
/////// AI for computer knowing what to do
function ai(lvl) {
	squares();
	var num = available[Math.floor(Math.random() * available.length)],
		//this function checks the next move
		tryMove = function (move, computer) {
	squares();
	var max = cpuArr,
		min = usrArr;
	if (!computer) {
		min.push(move);
	} else {
		max.push(move);
	}
	return terminal(min, max);
};
	//check to see if game is still going & if its cpu's turn
	if (!terminal(usrArr, cpuArr) && turn()) {
		if (available.indexOf(1) !== -1) {
				num = 1
			}
		if (available.indexOf(9) !== -1) {
				num = 9
			}
		if (available.indexOf(3) !== -1) {
				num = 3
			}
		if (available.indexOf(7) !== -1&&usrArr.indexOf(6)===-1) {
				num = 7
			}
		if (available.indexOf(5) !== -1 ) {
				num = 5
			}
		if ((usrArr.indexOf(1) !== -1&&usrArr.indexOf(9) !== -1)||(usrArr.indexOf(3) !== -1&&usrArr.indexOf(7) !== -1)){
		if (available.indexOf(2) !== -1 ) {
				num = 2
			}
		if (available.indexOf(4) !== -1 ) {
				num = 4
			}
		if (available.indexOf(6) !== -1 ) {
				num = 6
			}
		if (available.indexOf(8) !== -1 ) {
				num = 8
			}			
		}
		available.forEach(function(val) { //look for winning squares
			if (tryMove(val, false) === -10) {
					num = val
				} //look to defend
			});
		available.forEach(function(val){
			if (tryMove(val, true) === 10) {
					num = val
				} //look to WIN
			});
		$('#sq' + num).removeClass('unchecked').addClass(cpu); //add cpu mark to current square
		
	$('.sw-container').slideUp("slow","swing");
	squares();
	winner();
	}
}



Comments