Created
February 27, 2014 07:47
-
-
Save bridgpal/9246036 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict" | |
@ticTacToe = angular.module 'TicTacToe', [] | |
ticTacToe.constant 'WIN_PATTERNS', | |
[ | |
[0,1,2] | |
[3,4,5] | |
[6,7,8] | |
[0,3,6] | |
[1,4,7] | |
[2,5,8] | |
[0,4,8] | |
[2,4,6] | |
] | |
class BoardCtrl | |
constructor: (@$scope, @WIN_PATTERNS) -> | |
@resetBoard() | |
@$scope.mark = @mark | |
getPatterns: => | |
@patternsToTest = @WIN_PATTERNS.filter -> true | |
getRow: (pattern) => | |
c = @cells | |
c0 = c[pattern[0]] || pattern[0] | |
c1 = c[pattern[1]] || pattern[1] | |
c2 = c[pattern[2]] || pattern[2] | |
"#{c0}#{c1}#{c2}" | |
someoneWon: (row) -> | |
'xxx' == row || 'ooo' == row | |
resetBoard: => | |
@cells = @$scope.cells = {} | |
@getPatterns() | |
numberOfMoves: => | |
Object.keys(@cells).length | |
movesRemaining: (player) => | |
totalMoves = 9 - @numberOfMoves() | |
if player == 'x' | |
Math.ceil(totalMoves / 2) | |
else if player == 'o' | |
Math.floor(totalMoves / 2) | |
else | |
totalMoves | |
player: (options) => | |
options ||= whoMovedLast: false | |
moves = @numberOfMoves() - (if options.whoMovedLast then 1 else 0) | |
if moves % 2 == 0 then 'x' else 'o' | |
isMixedRow: (row) -> | |
!!row.match(/ox\d|o\dx|\dox|xo\d|x\do|\dxo/i) | |
hasOneX: (row) -> | |
!!row.match(/x\d\d|\dx\d|\d\dx/i) | |
hasTwoXs: (row) -> | |
!!row.match(/xx\d|x\dx|\dxx/i) | |
hasOneO: (row) -> | |
!!row.match(/o\d\d|\do\d|\d\do/i) | |
hasTwoOs: (row) -> | |
!!row.match(/oo\d|o\do|\doo/i) | |
isEmptyRow: (row) -> | |
!!row.match(/\d\d\d/i) | |
gameUnwinnable: => | |
@patternsToTest.length < 1 | |
announceWinner: => | |
winner = @player(whoMovedLast: true) | |
alert "#{winner} wins!" | |
@resetBoard() | |
announceTie: => | |
alert "It's a tie!" | |
@resetBoard() | |
rowStillWinnable: (row) => | |
not (@isMixedRow(row) or | |
(@hasOneX(row) and @movesRemaining('x') < 2) or | |
(@hasTwoXs(row) and @movesRemaining('x') < 1) or | |
(@hasOneO(row) and @movesRemaining('o') < 2) or | |
(@hasTwoOs(row) and @movesRemaining('o') < 1) or | |
(@isEmptyRow(row) and @movesRemaining() < 5)) | |
parseBoard: => | |
won = false | |
@patternsToTest = @patternsToTest.filter (pattern) => | |
row = @getRow(pattern) | |
won ||= @someoneWon(row) | |
@rowStillWinnable(row) | |
if won | |
@announceWinner() | |
else if @gameUnwinnable() | |
@announceTie() | |
mark: (@$event) => | |
cell = @$event.target.dataset.index | |
@cells[cell] = @player() | |
@parseBoard() | |
BoardCtrl.$inject = ["$scope", "WIN_PATTERNS"] | |
ticTacToe.controller "BoardCtrl", BoardCtrl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en" data-ng-app="TicTacToe"> | |
<head> | |
<meta charset="utf-8"> | |
<title>TicTacToe</title> | |
<link rel="stylesheet" href="/css/application.css" media="all"> | |
</head> | |
<body> | |
<header role="banner"> | |
<h1> | |
<span class="tic">Tic</span><span class="tac">Tac</span><span class="toe">Toe</span> | |
</h1> | |
</header> | |
<main role="main" data-ng-controller="BoardCtrl"> | |
<section id="gameboard" class="board"> | |
<div id="row-0" class="board-row"> | |
<div id="cell-0" data-index="0" data-ng-click="mark($event)" class="board-cell top left {{cells.0}}">{{cells.0}}</div> | |
<div id="cell-1" data-index="1" data-ng-click="mark($event)" class="board-cell top center {{cells.1}}">{{cells.1}}</div> | |
<div id="cell-2" data-index="2" data-ng-click="mark($event)" class="board-cell top right {{cells.2}}">{{cells.2}}</div> | |
</div> | |
<div id="row-1" class="board-row"> | |
<div id="cell-3" data-index="3" data-ng-click="mark($event)" class="board-cell middle left {{cells.3}}">{{cells.3}}</div> | |
<div id="cell-4" data-index="4" data-ng-click="mark($event)" class="board-cell middle center {{cells.4}}">{{cells.4}}</div> | |
<div id="cell-5" data-index="5" data-ng-click="mark($event)" class="board-cell middle right {{cells.5}}">{{cells.5}}</div> | |
</div> | |
<div id="row-2" class="board-row"> | |
<div id="cell-6" data-index="6" data-ng-click="mark($event)" class="board-cell bottom left {{cells.6}}">{{cells.6}}</div> | |
<div id="cell-7" data-index="7" data-ng-click="mark($event)" class="board-cell bottom center {{cells.7}}">{{cells.7}}</div> | |
<div id="cell-8" data-index="8" data-ng-click="mark($event)" class="board-cell bottom right {{cells.8}}">{{cells.8}}</div> | |
</div> | |
</section> | |
</main> | |
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script> | |
<script src="/js/application.js"></script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment