Last active
October 11, 2017 11:10
-
-
Save Atibaashraf/c02d0a9650bc0dae5eb01b59657b0f95 to your computer and use it in GitHub Desktop.
Adding tic tac toe game and basic tests
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
import {Component} from '@angular/core'; | |
@Component({ | |
selector: 'ttt-app', | |
template: ` | |
<ttt-game></ttt-game> | |
`, | |
}) | |
export class AppComponent { | |
} |
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
import {NgModule} from '@angular/core'; | |
import {AppComponent} from './app-component'; | |
import {BrowserModule} from '@angular/platform-browser'; | |
import {FormsModule} from '@angular/forms'; | |
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; | |
import {Board} from './tictactoe'; | |
import {GameComponent} from './game'; | |
@NgModule({ | |
declarations: [AppComponent, Board, GameComponent], | |
imports: [BrowserModule, FormsModule], | |
bootstrap: [AppComponent], | |
}) | |
export class MyAppModule{} | |
platformBrowserDynamic().bootstrapModule(MyAppModule); |
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
import { | |
async, | |
ComponentFixture, | |
TestBed | |
} from '@angular/core/testing'; | |
import {NO_ERRORS_SCHEMA} from '@angular/core'; | |
import {FormsModule} from '@angular/forms'; | |
import { | |
By | |
} from '@angular/platform-browser'; | |
import { GameComponent } from './game'; | |
describe('Game UI', () => { | |
beforeEach(() => { | |
TestBed.configureTestingModule({ | |
imports: [FormsModule], | |
declarations: [GameComponent], | |
schemas: [NO_ERRORS_SCHEMA] | |
}); | |
}); | |
beforeEach(async(() => { | |
TestBed.compileComponents(); | |
})); | |
it('should render', () => { | |
let fixture = TestBed.createComponent(GameComponent); | |
expect(fixture.nativeElement.textContent).toContain('Player X'); | |
}); | |
it('should listen to events', () => { | |
let fixture = TestBed.createComponent(GameComponent); | |
fixture.debugElement.query(By.css('ttt-board')).triggerEventHandler('endgame', '_'); | |
fixture.detectChanges(); | |
expect(fixture.nativeElement.textContent).toContain('Tie!'); | |
}); | |
it('should listen to events', () => { | |
let fixture = TestBed.createComponent(GameComponent); | |
fixture.debugElement.query(By.css('ttt-board')).triggerEventHandler('turnswap', 'o'); | |
fixture.detectChanges(); | |
expect(fixture.nativeElement.textContent).toContain('Elizabeth\'s turn'); | |
}); | |
it('should bind to player name', () => { | |
let fixture = TestBed.createComponent(GameComponent); | |
fixture.detectChanges(); | |
expect(fixture.nativeElement.textContent).toContain('Jane\'s turn'); | |
fixture.componentInstance.playerX = 'Eddie'; | |
fixture.detectChanges(); | |
expect(fixture.nativeElement.textContent).toContain('Eddie\'s turn'); | |
}); | |
}); |
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
describe('universal truths', () => { | |
it('should do math', () => { | |
expect(1 + 1).toEqual(2); | |
expect(5).toBeGreaterThan(4); | |
}); | |
xit('should skip this', () => { | |
expect(4).toEqual(40); | |
}); | |
}); |
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
button { | |
display: inline-block; | |
margin: 0px; | |
padding: 0px; | |
font-size: 54px; | |
box-shadow: none; | |
border-radius: 0; | |
height: 75px; | |
width: 75px; | |
background: white; | |
border: 1px solid grey; | |
font-family: sans-serif; | |
line-height: 0; | |
} | |
.ttt-row.selected button{ | |
background-color: cornflowerblue; | |
} |
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
<div *ngFor="let row of rows; let i=index" class="ttt-row" [class.selected]="selectedRow == i + 1"> | |
<button *ngFor = "let col of columns" class="ttt-box" (click)="handleCheck(row, col)"> | |
{{getOwner(row, col)}} | |
</button> | |
</div> |
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
import { | |
async, | |
ComponentFixture, | |
TestBed | |
} from '@angular/core/testing'; | |
import { | |
By | |
} from '@angular/platform-browser'; | |
import { Board } from './tictactoe'; | |
describe('winning Tic-Tac-Toe', () => { | |
let board: Board; | |
beforeEach(() => { | |
board = new Board(); | |
}); | |
it('should have no winner', () => { | |
let winner = board.checkForEndgame([ | |
['x', '_', '_',], | |
['x', '_', '_',], | |
['o', '_', '_',] | |
]); | |
expect(winner).toEqual(null); | |
winner = board.checkForEndgame([ | |
['o', '_', '_',], | |
['x', 'x', '_',], | |
['o', '_', 'x',] | |
]); | |
expect(winner).toEqual(null); | |
}); | |
it('should have a winner', () => { | |
let winner = board.checkForEndgame([ | |
['x', 'o', 'o',], | |
['x', 'x', '_',], | |
['o', 'o', 'x',] | |
]); | |
expect(winner).toEqual('x'); | |
winner = board.checkForEndgame([ | |
['o', '_', '_',], | |
['o', 'x', '_',], | |
['o', '_', 'x',] | |
]); | |
expect(winner).toEqual('o'); | |
winner = board.checkForEndgame([ | |
['x', '_', 'x',], | |
['o', 'o', 'o',], | |
['o', '_', 'x',] | |
]); | |
expect(winner).toEqual('o'); | |
}); | |
it('should be a draw', () => { | |
let winner = board.checkForEndgame([ | |
['x', 'o', 'x',], | |
['o', 'x', 'o',], | |
['o', 'x', 'o',] | |
]); | |
expect(winner).toEqual('_'); | |
}); | |
}); | |
describe('Tic-Tac-Toe board', () => { | |
beforeEach(() => { | |
TestBed.configureTestingModule({ | |
declarations: [Board] | |
}); | |
}); | |
beforeEach(async(() => { | |
TestBed.compileComponents(); | |
})); | |
it('should respond to click events', () => { | |
let fixture = TestBed.createComponent(Board); | |
fixture.detectChanges(); | |
let board = fixture.nativeElement; | |
let box = board.querySelectorAll('.ttt-box')[0]; | |
expect(box.textContent).toContain('_'); | |
box.click(); | |
fixture.detectChanges(); | |
expect(box.textContent).toContain('x'); | |
}); | |
it('should respond to keyboard events', () => { | |
let fixture = TestBed.createComponent(Board); | |
fixture.detectChanges(); | |
var event1 = new KeyboardEvent('keydown', { | |
key: '1' | |
}); | |
var event3 = new KeyboardEvent('keydown', { | |
key: '3' | |
}); | |
window.dispatchEvent(event1); | |
window.dispatchEvent(event3); | |
fixture.detectChanges(); | |
let board = fixture.nativeElement; | |
let box = board.querySelectorAll('.ttt-box')[2]; | |
expect(box.textContent).toContain('x'); | |
}); | |
}); |
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
import {Component, Output, EventEmitter, HostListener} from '@angular/core'; | |
@Component({ | |
selector: 'ttt-board', | |
templateUrl: 'dist/app/tictactoe.html', | |
styleUrls: ['dist/app/tictactoe.css'] | |
}) | |
export class Board { | |
@Output() endgame = new EventEmitter<string>(); | |
@Output() turnswap = new EventEmitter<string>(); | |
public rows: number[]; | |
public columns: number[]; | |
public selectedRow: number = null; | |
private grid: string[][]; | |
private player = 'x'; | |
constructor() { | |
this.rows = [1, 2, 3]; | |
this.columns = [1, 2, 3]; | |
this.reset(); | |
} | |
reset() { | |
this.grid = []; | |
for (let i = 0; i < this.rows.length; i++) { | |
this.grid.push([]); | |
for (let j = 0; j < this.columns.length; j++) { | |
this.grid[i].push('_'); | |
} | |
} | |
} | |
getOwner(row: number, col: number): string { | |
return this.grid[row - 1][col - 1]; | |
} | |
handleCheck(row: number, col: number) { | |
if (this.grid[row - 1][col - 1] == '_') { | |
this.grid[row - 1][col - 1] = this.player; | |
this.player = this.player == 'x' ? 'o' : 'x'; | |
this.turnswap.emit(this.player); | |
} | |
this.checkForEndgame(this.grid); | |
} | |
@HostListener('window:keydown', ['$event']) | |
handleKeydown(event) { | |
let numberKey; | |
if (event.keyCode) { | |
numberKey = event.keyCode - 48; | |
} else { | |
numberKey = +event.key; | |
} | |
if (numberKey > 0 && numberKey <= this.rows.length) { | |
if (this.selectedRow == null) { | |
this.selectedRow = numberKey; | |
} else { | |
this.handleCheck(this.selectedRow, numberKey); | |
this.selectedRow = null; | |
} | |
} else { | |
this.selectedRow = null; | |
} | |
} | |
checkForEndgame(grid) { | |
// Assumes a square grid. | |
// Rows. | |
for (let i = 0; i < grid.length; i++) { | |
let owner = grid[i][0]; | |
let winner = owner != '_'; | |
for (let j = 0; j < grid[i].length; j++) { | |
let newOwner = grid[i][j]; | |
if (owner != newOwner) { | |
winner = false; | |
} | |
} | |
if (winner) { | |
return this.emitWinner(owner); | |
} | |
} | |
// Cols. | |
for (let j = 0; j < grid[0].length; j++) { | |
let owner = grid[0][j]; | |
let winner = owner != '_'; | |
for (let i = 0; i < grid.length; i++) { | |
let newOwner = grid[i][j]; | |
if (owner != newOwner) { | |
winner = false; | |
} | |
} | |
if (winner) { | |
return this.emitWinner(owner); | |
} | |
} | |
// Diagonals. | |
let owner = grid[0][0]; | |
let winner = owner != '_'; | |
for (let k = 0; k < grid.length; k++) { | |
let newOwner = grid[k][k]; | |
if (owner != newOwner) { | |
winner = false; | |
} | |
} | |
if (winner) { | |
return this.emitWinner(owner); | |
} | |
owner = grid[grid.length - 1][0]; | |
winner = owner != '_'; | |
for (let k = 0; k < grid.length; k++) { | |
let newOwner = grid[grid.length - k - 1][k]; | |
if (owner != newOwner) { | |
winner = false; | |
} | |
} | |
if (winner) { | |
return this.emitWinner(owner); | |
} | |
// All full. | |
let full = true; | |
for (let i = 0; i < grid.length; i++) { | |
for (let j = 0; j < grid.length; j++) { | |
if (grid[i][j] == '_') { | |
full = false; | |
} | |
} | |
} | |
if (full) { | |
return this.emitWinner('_'); | |
} | |
return null; | |
} | |
emitWinner(winner) { | |
this.endgame.emit(winner); | |
return winner; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment