Skip to content

Instantly share code, notes, and snippets.

@chemoish
Created October 30, 2012 04:35
Show Gist options
  • Save chemoish/3978317 to your computer and use it in GitHub Desktop.
Save chemoish/3978317 to your computer and use it in GitHub Desktop.
A CodePen by Carey Hinoki. Tic-Tac-Toe - The first interview question I give out is to make TTT in 15 minutes. The only person that has finished it in my company / all interviewees is me. One day everyone decided to one up the basic TTT problem... So thi
<canvas id="game" width="600" height="600"></canvas>
TTT = (function() {
var canvas = $('#game').get(0);
var ctx = canvas.getContext('2d');
var height = canvas.height;
var width = canvas.width;
function drawBoard() {
ctx.save();
ctx.lineWidth = 10;
ctx.lineCap = 'round';
ctx.strokeStyle = '#AD5472';
ctx.beginPath();
ctx.moveTo(200, 20);
ctx.lineTo(200, 580);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(400, 20);
ctx.lineTo(400, 580);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(20, 200);
ctx.lineTo(580, 200);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(20, 400);
ctx.lineTo(580, 400);
ctx.stroke();
ctx.restore();
}
function drawDrop(x, y) {
var segments = 30;
var fromX = x;
var fromY = y;
var toX = x + Math.floor(Math.random() * 10) + 5;
var toY = y + Math.floor(Math.random() * 20) + 5;
var slope = ((toY - fromY) / (toX - fromX)) * -1;
var slopeX = ((toX - fromX) / segments);
var slopeY = ((toY - fromY) / segments);
ctx.lineCap = 'round';
var segment_collection = [];
for (var i = 0; i <= segments; i++) {
toX = (i * slopeX) + x;
toY = (i * slopeY) + y;
segment_collection[i] = {
fromX: fromX,
fromY: fromY,
toX: toX,
toY: toY
};
fromX = toX;
fromY = toY;
}
var counter = 0;
var tail = Math.floor(Math.random() * 10) + 5;
(function animate() {
var segment = segment_collection[counter];
var segment_tail = segment_collection[counter - tail];
counter++;
if (segment_tail != undefined) {
drop(segment_tail.fromX, segment_tail.fromY, segment_tail.toX, segment_tail.toY, '#FFFFFF', 5);
}
if (segment != undefined) {
var color;
if (Math.floor(Math.random() * 100) < 15) {
color = '#A1B0FF';
} else {
color = '#CAE6E8';
}
drop(segment.fromX, segment.fromY, segment.toX, segment.toY, color, 3);
}
if (segment != undefined || segment_tail != undefined) {
setTimeout(function() {
animate();
}, 1000 / 60);
}
})();
function drop(fromX, fromY, toX, toY, color, lineWidth) {
ctx.save();
ctx.beginPath();
ctx.moveTo(fromX, fromY);
ctx.lineTo(toX, toY);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;
ctx.globalAlpha = 0.7;
ctx.stroke();
ctx.restore();
}
}
function rain(x, y) {
drawDrop(x + 15, y + 5);
drawDrop(x + 25, y + 5);
drawDrop(x + 41, y + 0);
drawDrop(x + 46, y + 5);
drawDrop(x + 60, y + 5);
drawDrop(x + 70, y + 0);
var timeout = setTimeout(function() {
rain(x, y);
}, 1000/5);
if (shower == false) {
clearTimeout(timeout);
}
};
// initialize game
var board = [
[0, 0, 200, 200],
[200, 0, 400, 200],
[400, 0, 600, 200],
[0, 200, 200, 400],
[200, 200, 400, 400],
[400, 200, 600, 400],
[0, 400, 200, 600],
[200, 400, 400, 600],
[400, 400, 600, 600]
];
var moves = [];
var turns = [
'9728', // Sun
'9729' // Cloud
];
var turn = 0;
var shower = true;
// draw board
drawBoard();
return {
getBoard: function() {
return moves;
},
getWinner: function() {
if (this.hasWon(0)) {
return 1; // update zero index offset
} else if (this.hasWon(1)) {
return 2; // update zero index offset
} else {
return false;
}
},
hasWon: function(turn) {
if (
(moves[0] == turn && moves[1] == turn && moves[2] == turn) ||
(moves[3] == turn && moves[4] == turn && moves[5] == turn) ||
(moves[6] == turn && moves[7] == turn && moves[8] == turn) ||
(moves[0] == turn && moves[3] == turn && moves[6] == turn) ||
(moves[1] == turn && moves[4] == turn && moves[7] == turn) ||
(moves[2] == turn && moves[5] == turn && moves[8] == turn) ||
(moves[0] == turn && moves[4] == turn && moves[8] == turn) ||
(moves[2] == turn && moves[4] == turn && moves[6] == turn)
) {
return true;
} else {
return false;
}
},
isCatsGame: function () {
return this.getBoard().join('').length == 9 && this.getWinner() === false;
},
isGameOver: function() {
if (this.hasWon(0) || this.hasWon(1) || this.isCatsGame()) {
return true;
}
},
move: function(x, y) {
var num_slots = board.length;
// check every slot to see if your mouse click matches a give areamap
for (var i = 0; i < num_slots; i++) {
// grab slot cordinates
var x1 = board[i][0];
var y1 = board[i][1];
var x2 = board[i][2];
var y2 = board[i][3];
// check to see if slot is a valid move
if ((x >= x1 && x <= x2 && y >= y1 && y <= y2) && moves[i] == undefined) {
// store move
moves[i] = turn;
// generate position of text based on slot
// offset is for text centering - based on font size
var slot = board[i];
var offsetX = slot[0] + 50;
var offsetY = slot[1] + 145;
ctx.save();
ctx.font = '120px Futura, Helvetica, sans-serif';
ctx.lineCap = 'square';
ctx.lineWidth = 2;
ctx.shadowBlur = 10;
ctx.shadowColor = '#6C9380';
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
// change color based on turns
if (turn == 0) {
ctx.strokeStyle = '#F07C6C';
} else {
ctx.strokeStyle = '#56626B';
}
ctx.strokeText(String.fromCharCode(turns[turn]), offsetX, offsetY);
ctx.restore();
if (turn == 1) {
// add rain to turn 1 move - offset it to the text
rain(offsetX + 10, offsetY - 8);
}
turn = (turn == 0) ? 1 : 0; // update turn
}
}
},
restart: function() {
shower = false;
setTimeout(function() {
ctx.save();
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, width, height);
ctx.restore();
drawBoard();
// reset instance variables
turn = 0;
moves = [];
shower = true;
}, 300);
}
};
}());
$(function() {
$('#game').on('click', function(event) {
var element = $(this),
eoffset = $(this).offset(),
x = event.pageX - eoffset.left,
y = event.pageY - eoffset.top;
// if game is not over - let the player move
if (!TTT.isGameOver()) {
TTT.move(x, y);
var winner = TTT.getWinner(),
is_cats_game = TTT.isCatsGame();
if (winner !== false || is_cats_game === true) {
var body = $('body'),
msg;
if (is_cats_game === true) {
msg = 'Cats Game!';
} else {
msg = 'Player ' + winner + ' has won!';
}
body.append($('<h1 class="title">' + msg + '</h1>'));
body.append($('<input type="button" class="reset" value="Reset Game">'));
$('.reset').on('click', function() {
TTT.restart();
$('h1.title').remove();
$(this).remove();
});
}
} else {
return false;
}
});
});
body
{
padding: 100px 0;
}
#game
{
cursor: pointer;
display: block;
margin: 0 auto;
position: relative;
}
h1.title
{
color: #404040;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-align: center;
}
input.reset
{
display: block;
height: 35px;
margin: 0px auto;
width: 90px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment