Skip to content

Instantly share code, notes, and snippets.

@Atibaashraf
Last active October 11, 2017 11:10
Show Gist options
  • Save Atibaashraf/c02d0a9650bc0dae5eb01b59657b0f95 to your computer and use it in GitHub Desktop.
Save Atibaashraf/c02d0a9650bc0dae5eb01b59657b0f95 to your computer and use it in GitHub Desktop.
Adding tic tac toe game and basic tests
import {Component} from '@angular/core';
@Component({
selector: 'ttt-app',
template: `
<ttt-game></ttt-game>
`,
})
export class AppComponent {
}
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);
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');
});
});
describe('universal truths', () => {
it('should do math', () => {
expect(1 + 1).toEqual(2);
expect(5).toBeGreaterThan(4);
});
xit('should skip this', () => {
expect(4).toEqual(40);
});
});
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;
}
<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>
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');
});
});
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