Skip to content

Instantly share code, notes, and snippets.

@bridgpal
Created February 27, 2014 07:47
Show Gist options
  • Save bridgpal/9246036 to your computer and use it in GitHub Desktop.
Save bridgpal/9246036 to your computer and use it in GitHub Desktop.
"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
<!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