Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tic tac karin #18

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c76445b
inital setup of src and spec files
Ynakashima Dec 13, 2016
cf6dd78
initial test for Game is passing
Ynakashima Dec 13, 2016
8793346
game constructor tests creation of players and board
wordkarin Dec 13, 2016
9cf42a2
added constructor tests for Board
wordkarin Dec 13, 2016
a1e56c7
positive and negative tests for Player play function are passing
Ynakashima Dec 13, 2016
909147d
positive test for validPlay function in Game is passing
Ynakashima Dec 13, 2016
2d87021
added markPlay and validPlay to Board, negative validPlay test in pro…
Ynakashima Dec 13, 2016
7bef251
updated markPlay
Ynakashima Dec 13, 2016
d3707b7
added negative test case for validPlay and added error handling for m…
Ynakashima Dec 14, 2016
e815d32
built toggleTurn in Game and wrote passing positive test
Ynakashima Dec 14, 2016
0ee580e
moved all validation into board, added gameOver function, tests pass
wordkarin Dec 14, 2016
fac54c3
added winHorizontal, negative and positive tests pass
wordkarin Dec 14, 2016
295efbd
added winVertical and tests are passing
Ynakashima Dec 14, 2016
75c58a7
tests and function written for winDiagonal
wordkarin Dec 14, 2016
c7cf633
gameWin function and tests passing
wordkarin Dec 14, 2016
02b5a9f
modified win functions to set the player that won, tests passing
Ynakashima Dec 14, 2016
f17ddf7
wrote takeTurn, tests pass. wave 1 complete
Ynakashima Dec 14, 2016
c2c12d0
cleaned up and removed console.logs
Ynakashima Dec 14, 2016
816e0e4
set up Backbone model and view files, did html
Ynakashima Dec 16, 2016
b884520
added document.ready to run html, tried to get tests working
wordkarin Dec 16, 2016
f22eaae
moved models back into src'
wordkarin Dec 16, 2016
e519dcd
using foundation cdn stylesheet
wordkarin Dec 16, 2016
586f688
added html/css to board to see click events
Ynakashima Dec 19, 2016
991cd8a
added imports for views and models into app.js and put app.js in righ…
Ynakashima Dec 19, 2016
298e416
added click handler for board squares, passing square id also
wordkarin Dec 19, 2016
2464cbf
resolved stack overflow on gameview, click event on play again working
Ynakashima Dec 19, 2016
0833d3b
added html and CSS to get board to center and display winner/play aga…
Ynakashima Dec 19, 2016
8e6bdd1
changed board from table to listso we can iterate through board array
Ynakashima Dec 19, 2016
a23be33
styled ul to represent board; click handlers still work
Ynakashima Dec 19, 2016
db278bf
moved html for board into boardview render
wordkarin Dec 19, 2016
9cf1544
experimenting with markPosition
wordkarin Dec 19, 2016
88b23bf
moved js classes into backbone models
wordkarin Dec 19, 2016
0072d49
restartGame now makes a new Game
wordkarin Dec 20, 2016
50fad5e
trying to get play again button to work, getting multiple copies of b…
wordkarin Dec 20, 2016
f6224a2
updated player to be an attribute of game, tests pass
wordkarin Dec 20, 2016
094da80
turnPlay in gameview calling takeTurn on model
wordkarin Dec 20, 2016
dd096c7
cannot keep playing if someone has won
wordkarin Dec 20, 2016
49938b7
added game attribute and listener for gameisOver, tests still pass
wordkarin Dec 20, 2016
1c257d5
hiding the gameover banner on game play, displays winner at end of game
wordkarin Dec 20, 2016
d7469af
made the board look nicer
wordkarin Dec 21, 2016
f07cb65
play again still busted, moving on to API
wordkarin Dec 21, 2016
147e96d
added functionality for displaying if it is a draw
wordkarin Dec 21, 2016
7e04825
successfully posting games to API using toJSON
wordkarin Dec 22, 2016
5f3bdf1
fixed bug with banner display when game ends in a draw
wordkarin Dec 22, 2016
9655f27
fixed failing tests with references to .winner
wordkarin Dec 22, 2016
dded5d0
play again refreshes page
wordkarin Dec 22, 2016
276b973
fetching the collection from the api on document.ready
wordkarin Dec 22, 2016
a7ba808
adding html for displaying games list
wordkarin Dec 22, 2016
1d43afd
show games button now displays all the games
wordkarin Dec 22, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions build/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#game, #game-list {
max-width: 600px;
}

h1 {
text-align: center;
}

#board-display {
width: 50%;
list-style: none;
}

.board-square {
height: 100px;
width: 100px;
background-color: pink;
padding: 5px;
border: 1px solid white;
line-height: 100px;
text-align: center;
font-size: 4em;
color: white;
}

.end-of-game {
display: none;
}
45 changes: 45 additions & 0 deletions build/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,53 @@
<head>
<title>Tic-Tac-Toe</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/foundation/6.2.4/foundation.min.css">
<link rel="stylesheet" href="css/app.css">
</head>

<body>
<script src="/app.bundle.js" charset="utf-8"></script>
<article id="game">

<header>
<h1>Tic Tac Toe with Backbone</h1>
</header>

<section class="end-of-game" class="row small-centered">
<div class="small-8 columns">
<p id="win-banner"></p>
</div>
<div class="small-4 columns">
<button class="button" type="button" id="play-again" onClick="window.location.reload()">Play Again</button>
</div>
</section>

<section class="board">
<ul class="row small-up-3 small-centered" id="board-display">
<li class="column board-square" id="0"></li>
<li class="column board-square" id="1"></li>
<li class="column board-square" id="2"></li>
<li class="column board-square" id="3"></li>
<li class="column board-square" id="4"></li>
<li class="column board-square" id="5"></li>
<li class="column board-square" id="6"></li>
<li class="column board-square" id="7"></li>
<li class="column board-square" id="8"></li>
</ul>
</section>

</article>
<article id="game-list">
<section class="row">
<div class="small-3 small-centered columns">
<button class="button" type="button" id="show-all-games">Show games</button></div>
</section>
<section class="row">
<div class="small-10 small-centered columns">
<table id="prev-games">
</table>
</div>
</section>
</article>
</body>
</html>
58 changes: 58 additions & 0 deletions spec/board.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import Board from 'app/models/board';

describe('Board', function(){
describe('constructor', function(){
it('should make a positions array of length 9', function(){
var board1 = new Board();
expect(board1.positions instanceof Array).toBeTruthy();

expect(board1.positions[0]).toEqual(" ");

expect(board1.positions.length).toEqual(9);
});
});

describe('validPlay', function(){
var board2 = new Board();
it('should return true if position is available', function() {
expect(board2.validPlay(1)).toBeTruthy();

expect(board2.validPlay(0)).toBeTruthy();

expect(board2.validPlay(8)).toBeTruthy();
});

it('should return false if position is unavailable', function(){
expect(board2.validPlay(2)).toBeTruthy();

board2.markPlay('X', 2);

expect(board2.validPlay(2)).toBeFalsy();
});

it('should throw an error if position is not an integer', function(){
expect(function() {
board2.validPlay("cat");
}).toThrow(new Error('Input must be an integer between 0 and 8'));
});

it('will return false if position is not in the positions array', function(){
expect(board2.validPlay(9)).toBeFalsy();
});
});

describe('markPlay', function() {
var board2 = new Board();
it('should mark the board with the play for that player', function(){
expect(board2.markPlay('X', 1)).toEqual(1);

expect(board2.positions[1]).toEqual('X');
});

it('should throw an error if 2 arguments are not passed to it', function(){
expect(function() {
board2.markPlay(2);
}).toThrow(new Error('Wrong number of arguments'));
});
});
});
179 changes: 179 additions & 0 deletions spec/game.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import Game from 'app/models/game';
import Board from 'app/models/board';

describe('Game', function(){
describe('constructor', function() {
it('should make a new game', function(){
var game1 = new Game();
expect(game1 instanceof Game).toBeTruthy();

expect(game1.get("player1")).toEqual("X");

expect(game1.get("player2")).toEqual("O");

expect(game1.board instanceof Board).toBeTruthy();

expect(game1.turn).toEqual(game1.get("player1"));
});
});

describe('toggleTurn', function() {
var game2 = new Game();
it('should switch to player2 after player1', function() {
expect(game2.toggleTurn()).toEqual(game2.get("player2"));
});
});

describe('gameOver', function(){
var game3 = new Game();
game3.board.positions = ["O","X","X","X","X","O","O","O","X"];
it('should return true if all positions are filled', function(){
expect(game3.board.positions.length).toEqual(9);

expect(game3.gameOver()).toBeTruthy();
});

it('should return false if any positions are empty string', function(){
game3.board.positions[1] = " ";

expect(game3.gameOver()).toBeFalsy();
});
});

describe('winHorizontal', function(){
var game4 = new Game();
it('should return false if matches are empty strings', function(){
expect(game4.winHorizontal()).toBeFalsy();
});

it('should return true if there is a horizontal win in the first row', function(){
game4.board.positions = ["X","X","X","O"," ","O","O","O","X"];
expect(game4.winHorizontal()).toBeTruthy();
expect(game4.get('winner')).toEqual(game4.get("player1"));
});

it('should return true if there is a horizontal win in the second row', function(){
game4.board.positions = ["X","X"," ","O","O","O","X"," ","X"];
game4.turn = game4.get("player2");
expect(game4.winHorizontal()).toBeTruthy();
expect(game4.get('winner')).toEqual(game4.get("player2"));
});

it('should return true if there is a horizontal win in the third row', function(){
game4.board.positions = ["X","X","O","O"," ","O","X","X","X"];
game4.turn = game4.get("player1");
expect(game4.winHorizontal()).toBeTruthy();
expect(game4.get('winner')).toEqual(game4.get("player1"));
});

it('should return false if there is no horizontal win yet', function (){
game4.board.positions = ["X"," "," ","O"," "," "," "," "," "];
expect(game4.winHorizontal()).toBeFalsy();
});
});

describe('winVertical', function() {
var game5 = new Game();
it('should return false if matches are empty strings', function(){
expect(game5.winVertical()).toBeFalsy();
});

it('should return true if there is a vertical win in the first column', function(){
game5.board.positions = ["X"," ","X","X"," ","O","X","O","X"];
game5.turn = game5.get("player1");
expect(game5.winVertical()).toBeTruthy();
expect(game5.get('winner')).toEqual(game5.get("player1"));
});

it('should return true if there is a vertical win in the second column', function(){
game5.board.positions = [" ","X"," ","O","X","O","O","X"," "];
game5.turn = game5.get("player1");
expect(game5.winVertical()).toBeTruthy();
expect(game5.get('winner')).toEqual(game5.get("player1"));
});

it('should return true if there is a vertical win in the third column', function(){
game5.board.positions = [" "," ","X","O"," ","X","O","O","X"];
game5.turn = game5.get("player1");
expect(game5.winVertical()).toBeTruthy();
expect(game5.get('winner')).toEqual(game5.get("player1"));
});

it('should return false if there is no vertical win yet', function (){
game5.board.positions = ["X"," "," ","O"," "," "," "," "," "];
expect(game5.winVertical()).toBeFalsy();
});
});

describe('winDiagonal', function(){
var game5 = new Game();
it('should return false if matches are empty strings', function(){
expect(game5.winDiagonal()).toBeFalsy();
});

it('should return true if there is a diagonal win left to right', function(){
game5.board.positions = ["X"," ","O","X","X","O","X","O","X"];
game5.turn = game5.get("player1");
expect(game5.winDiagonal()).toBeTruthy();
expect(game5.get('winner')).toEqual(game5.get("player1"));
});

it('should return true if there is a diagonal win right to left', function(){
game5.board.positions = [" ","X","O","O","O","X","O","X"," "];
game5.turn = game5.get("player2");
expect(game5.winDiagonal()).toBeTruthy();
expect(game5.get('winner')).toEqual(game5.get("player2"));
});

it('should return false if there is no diagonal win yet', function (){
game5.board.positions = ["X"," "," ","O"," "," "," "," "," "];
expect(game5.winDiagonal()).toBeFalsy();
});
});

describe('gameWin', function(){
var game6 = new Game();
it('should return false at game start', function(){
expect(game6.gameWin()).toBeFalsy();
});

it('should return true if a win in any direction', function(){
game6.board.positions = ["X","X","O","O"," ","O","X","X","X"];
expect(game6.gameWin()).toBeTruthy();

game6.board.positions = [" "," ","X","O"," ","X","O","O","X"];
expect(game6.gameWin()).toBeTruthy();

game6.board.positions = [" ","X","O","O","O","X","O","X"," "];
expect(game6.gameWin()).toBeTruthy();
});
});

describe('takeTurn', function(){
var game = new Game();

it('should throw an error if the position is not valid', function(){
game.board.positions[0] = "X";
expect(function(){
game.takeTurn(0);}).toThrow(new Error('that position is already taken'));
});

it('should return the winner if someone won', function(){
game.board.positions = [" "," "," ","O"," ","X","O","O","X"];
expect(game.takeTurn(2)).toEqual(game.get("player1"));
});

it('should return gameOver if no one wins', function(){
game.board.positions = ["O","X","X","X","X","O","O","O"," "];
expect(game.takeTurn(8)).toEqual("gameOver");
});

it('should toggle the turn if nobody won and game is not over', function(){
game.board.positions = ["X"," "," ","O"," "," "," "," "," "];
expect(game.turn).toEqual(game.get("player1"));
game.takeTurn(2);
expect(game.board.positions).toEqual(["X"," ","X","O"," "," "," "," "," "]);
expect(game.turn).toEqual(game.get("player2"));
});
});
});
23 changes: 23 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import $ from 'jquery';
import _ from 'underscore';
import Backbone from 'backbone';

import Game from 'app/models/game';
import Games from 'app/collections/games';
import GamesView from 'app/views/games_view';
// import Board from 'app/models/board';
// import BoardView from 'app/views/board_view';
import GameView from 'app/views/game_view';

$(document).ready(function(){

var games = new Games();
var gameListView = new GamesView({
el: $('body'), //this will be something else later.
model: games
});

games.fetch();
console.log(games);

});
14 changes: 14 additions & 0 deletions src/app/collections/games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//this is the collection of games, specifically for interacting with the API
import Backbone from 'backbone';
import Game from 'app/models/game';

var Games = Backbone.Collection.extend({
model: Game,
url: 'http://localhost:3000/api/v1/games',
parse: function(data) {
return data;
}

});

export default Games;
34 changes: 34 additions & 0 deletions src/app/models/board.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Backbone from 'backbone';

const Board = Backbone.Model.extend({
initialize: function(){
this.positions = [];
for(var i = 0; i < 9; i++){
this.positions.push(" ");
}
},

validPlay: function (position) {
if (!(Number.isInteger(position))) {
throw new Error('Input must be an integer between 0 and 8');
} else if (this.positions[position] == " ") {
return true;
} else {
return false;
}
},

markPlay: function (mark, position) {
if(position === undefined) {
throw new Error('Wrong number of arguments');
} else if(this.validPlay(position)) {
this.positions[position] = mark;
return position;
} else {
throw new Error('that position is already taken');
}
}

});

export default Board;
Loading