Skip to content

Commit ed9f265

Browse files
author
R. Kaleta
authored
Merge pull request #6 from ref-humbold/troll
Troll mode
2 parents 61f008a + f11dbb5 commit ed9f265

File tree

8 files changed

+221
-91
lines changed

8 files changed

+221
-91
lines changed

src/app/components/game-board/game-board.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<div id="board" class="d-flex flex-column h-100 w-100">
22
<div id="panel" class="row">
33
<div class="counter text col-4">{{flagsLeft}}</div>
4-
<div class="face col-2 offset-1" (click)="startNewGame()">
4+
<div class="face col-2 offset-1" (click)="onLeftClickFace()"
5+
(contextmenu)="onRightClickFace($event)">
56
<img [src]="faceImage" />
67
</div>
78
<div class="counter text col-4 offset-1">{{seconds}}</div>

src/app/components/game-board/game-board.component.ts

Lines changed: 120 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { Component, ViewChildren, QueryList, AfterViewInit } from "@angular/core";
22
import { Subscription } from "rxjs";
3-
import { TickerService } from "../../services/ticker.service";
3+
import { GameMode } from "../../models/game-mode";
44
import { GameState } from "../../models/game-state";
55
import { GameResult } from "../..//models/game-result";
66
import { BoardPosition } from "../../models/board-position";
7+
import { NormalModeService } from "../../services/normal-mode.service";
8+
import { TrollModeService } from "../../services/troll-mode.service";
9+
import { TickerService } from "../../services/ticker.service";
710
import { FieldStatus, FieldComponent } from "../field/field.component";
811

912
@Component({
@@ -14,22 +17,39 @@ import { FieldStatus, FieldComponent } from "../field/field.component";
1417
export class GameBoardComponent implements AfterViewInit {
1518
@ViewChildren("field") public fieldsList: QueryList<FieldComponent>;
1619
public fieldsGrid: FieldComponent[][];
20+
private readonly modes: GameMode[];
1721
public readonly size: number = 16;
1822
public readonly bombsCount: number = 32;
1923
public flagsLeft: number = this.bombsCount;
2024
public seconds: number = 0;
2125
public faceImage: string = "../../../assets/epicface.jpg";
22-
protected secondsTicker: Subscription;
23-
protected state: GameState = GameState.New;
26+
private secondsTicker: Subscription;
27+
private state: GameState = GameState.New;
2428
private score: number = 0;
25-
26-
constructor(private readonly ticker: TickerService) {}
29+
private modeIndex: number = 0;
30+
31+
constructor(
32+
private readonly ticker: TickerService,
33+
normalMode: NormalModeService,
34+
trollMode: TrollModeService
35+
) {
36+
this.modes = [normalMode, trollMode];
37+
}
2738

2839
public ngAfterViewInit(): void {
2940
this.fieldsListToGrid();
3041
this.startNewGame();
3142
}
3243

44+
public get currentMode(): GameMode {
45+
return this.modes[this.modeIndex];
46+
}
47+
48+
public changeMode(): void {
49+
this.modeIndex = 1 - this.modeIndex;
50+
this.ngAfterViewInit();
51+
}
52+
3353
public startNewGame(): void {
3454
if (this.secondsTicker) {
3555
this.secondsTicker.unsubscribe();
@@ -38,9 +58,9 @@ export class GameBoardComponent implements AfterViewInit {
3858
this.state = GameState.New;
3959
this.flagsLeft = this.bombsCount;
4060
this.seconds = 0;
41-
this.faceImage = "../../../assets/epicface.jpg";
61+
this.faceImage = this.currentMode.playingImage;
4262
this.score = 0;
43-
this.fieldsGrid.forEach(rw => rw.forEach(fd => fd.clear()));
63+
this.fieldsGrid.forEach(row => row.forEach(field => field.clear()));
4464
this.secondsTicker = this.ticker.create(() => ++this.seconds);
4565
}
4666

@@ -49,19 +69,31 @@ export class GameBoardComponent implements AfterViewInit {
4969
this.secondsTicker.unsubscribe();
5070

5171
if (result === GameResult.Winning) {
52-
this.faceImage = "../../../assets/winface.jpg";
72+
this.faceImage = this.currentMode.winningImage;
5373
} else {
54-
this.faceImage = "../../../assets/sadface.jpg";
55-
this.fieldsGrid.forEach(rw =>
56-
rw.forEach(fld => {
57-
if (fld.hasBomb) {
58-
fld.status = FieldStatus.Visible;
74+
this.faceImage = this.currentMode.losingImage;
75+
this.fieldsGrid.forEach(row =>
76+
row.forEach(field => {
77+
if (field.hasBomb) {
78+
field.status = FieldStatus.Visible;
5979
}
6080
})
6181
);
6282
}
6383
}
6484

85+
public onLeftClickFace(): void {
86+
this.startNewGame();
87+
}
88+
89+
public onRightClickFace(event: MouseEvent): void {
90+
event.preventDefault();
91+
92+
if (this.state === GameState.Finished) {
93+
this.changeMode();
94+
}
95+
}
96+
6597
public onLeftClickField(position: BoardPosition): void {
6698
if (this.state === GameState.Finished) {
6799
return;
@@ -71,7 +103,7 @@ export class GameBoardComponent implements AfterViewInit {
71103
const bombs: BoardPosition[] = this.generateBombs(position);
72104

73105
this.countDistances(bombs);
74-
this.state = GameState.Played;
106+
this.state = GameState.Playing;
75107
}
76108

77109
const field: FieldComponent = this.fieldsGrid[position.row][position.column];
@@ -85,12 +117,12 @@ export class GameBoardComponent implements AfterViewInit {
85117
}
86118
}
87119

88-
public onRightClickField(pos: BoardPosition): void {
89-
if (this.state !== GameState.Played) {
120+
public onRightClickField(position: BoardPosition): void {
121+
if (this.state !== GameState.Playing) {
90122
return;
91123
}
92124

93-
const field: FieldComponent = this.fieldsGrid[pos.row][pos.column];
125+
const field: FieldComponent = this.fieldsGrid[position.row][position.column];
94126

95127
if (field.status === FieldStatus.Hidden && this.flagsLeft > 0) {
96128
--this.flagsLeft;
@@ -113,10 +145,6 @@ export class GameBoardComponent implements AfterViewInit {
113145
}
114146
}
115147

116-
private initialBombs(posClicked: BoardPosition): BoardPosition[] {
117-
return [];
118-
}
119-
120148
private fieldsListToGrid(): void {
121149
this.fieldsGrid = new Array<FieldComponent[]>(this.size).fill(null);
122150

@@ -127,8 +155,8 @@ export class GameBoardComponent implements AfterViewInit {
127155
this.fieldsList.forEach(fd => (this.fieldsGrid[fd.position.row][fd.position.column] = fd));
128156
}
129157

130-
private generateBombs(posClicked: BoardPosition): BoardPosition[] {
131-
const bombs: BoardPosition[] = this.initialBombs(posClicked);
158+
private generateBombs(positionClicked: BoardPosition): BoardPosition[] {
159+
const bombs: BoardPosition[] = this.currentMode.initialBombs(positionClicked);
132160

133161
while (bombs.length < this.bombsCount) {
134162
let bombPosition: BoardPosition;
@@ -140,7 +168,7 @@ export class GameBoardComponent implements AfterViewInit {
140168
);
141169
} while (
142170
bombs.findIndex(p => p.equals(bombPosition)) >= 0 ||
143-
posClicked.isNeighbour(bombPosition)
171+
positionClicked.isNeighbour(bombPosition)
144172
);
145173

146174
bombs.push(bombPosition);
@@ -149,42 +177,42 @@ export class GameBoardComponent implements AfterViewInit {
149177
return bombs;
150178
}
151179

152-
private countDistances(bombs: BoardPosition[]): void {
153-
for (const pos of bombs) {
154-
this.fieldsGrid[pos.row][pos.column].createBomb();
180+
private countDistances(bombPositions: BoardPosition[]): void {
181+
for (const position of bombPositions) {
182+
this.fieldsGrid[position.row][position.column].createBomb();
155183
}
156184

157-
for (const pos of bombs) {
158-
if (pos.row > 0 && pos.column > 0) {
159-
this.fieldsGrid[pos.row - 1][pos.column - 1].addNeighbouringBomb();
185+
for (const position of bombPositions) {
186+
if (position.row > 0 && position.column > 0) {
187+
this.fieldsGrid[position.row - 1][position.column - 1].addNeighbouringBomb();
160188
}
161189

162-
if (pos.row > 0) {
163-
this.fieldsGrid[pos.row - 1][pos.column].addNeighbouringBomb();
190+
if (position.row > 0) {
191+
this.fieldsGrid[position.row - 1][position.column].addNeighbouringBomb();
164192
}
165193

166-
if (pos.row > 0 && pos.column < this.size - 1) {
167-
this.fieldsGrid[pos.row - 1][pos.column + 1].addNeighbouringBomb();
194+
if (position.row > 0 && position.column < this.size - 1) {
195+
this.fieldsGrid[position.row - 1][position.column + 1].addNeighbouringBomb();
168196
}
169197

170-
if (pos.column > 0) {
171-
this.fieldsGrid[pos.row][pos.column - 1].addNeighbouringBomb();
198+
if (position.column > 0) {
199+
this.fieldsGrid[position.row][position.column - 1].addNeighbouringBomb();
172200
}
173201

174-
if (pos.column < this.size - 1) {
175-
this.fieldsGrid[pos.row][pos.column + 1].addNeighbouringBomb();
202+
if (position.column < this.size - 1) {
203+
this.fieldsGrid[position.row][position.column + 1].addNeighbouringBomb();
176204
}
177205

178-
if (pos.row < this.size - 1 && pos.column > 0) {
179-
this.fieldsGrid[pos.row + 1][pos.column - 1].addNeighbouringBomb();
206+
if (position.row < this.size - 1 && position.column > 0) {
207+
this.fieldsGrid[position.row + 1][position.column - 1].addNeighbouringBomb();
180208
}
181209

182-
if (pos.row < this.size - 1) {
183-
this.fieldsGrid[pos.row + 1][pos.column].addNeighbouringBomb();
210+
if (position.row < this.size - 1) {
211+
this.fieldsGrid[position.row + 1][position.column].addNeighbouringBomb();
184212
}
185213

186-
if (pos.row < this.size - 1 && pos.column < this.size - 1) {
187-
this.fieldsGrid[pos.row + 1][pos.column + 1].addNeighbouringBomb();
214+
if (position.row < this.size - 1 && position.column < this.size - 1) {
215+
this.fieldsGrid[position.row + 1][position.column + 1].addNeighbouringBomb();
188216
}
189217
}
190218
}
@@ -195,95 +223,98 @@ export class GameBoardComponent implements AfterViewInit {
195223
this.fieldsGrid[startPos.row][startPos.column].status = FieldStatus.Visible;
196224

197225
while (queue.length > 0) {
198-
const pos: BoardPosition = queue.shift();
226+
const position: BoardPosition = queue.shift();
199227

200-
if (this.fieldsGrid[pos.row][pos.column].isEmpty) {
228+
if (this.fieldsGrid[position.row][position.column].isEmpty) {
201229
if (
202-
pos.row > 0 &&
203-
pos.column > 0 &&
204-
this.fieldsGrid[pos.row - 1][pos.column - 1].status === FieldStatus.Hidden
230+
position.row > 0 &&
231+
position.column > 0 &&
232+
this.fieldsGrid[position.row - 1][position.column - 1].status === FieldStatus.Hidden
205233
) {
206-
this.fieldsGrid[pos.row - 1][pos.column - 1].status = FieldStatus.Visible;
234+
this.fieldsGrid[position.row - 1][position.column - 1].status = FieldStatus.Visible;
207235

208-
if (!this.fieldsGrid[pos.row - 1][pos.column - 1].hasBomb) {
209-
queue.push(new BoardPosition(pos.row - 1, pos.column - 1));
236+
if (!this.fieldsGrid[position.row - 1][position.column - 1].hasBomb) {
237+
queue.push(new BoardPosition(position.row - 1, position.column - 1));
210238
}
211239
}
212240

213-
if (pos.row > 0 && this.fieldsGrid[pos.row - 1][pos.column].status === FieldStatus.Hidden) {
214-
this.fieldsGrid[pos.row - 1][pos.column].status = FieldStatus.Visible;
241+
if (
242+
position.row > 0 &&
243+
this.fieldsGrid[position.row - 1][position.column].status === FieldStatus.Hidden
244+
) {
245+
this.fieldsGrid[position.row - 1][position.column].status = FieldStatus.Visible;
215246

216-
if (!this.fieldsGrid[pos.row - 1][pos.column].hasBomb) {
217-
queue.push(new BoardPosition(pos.row - 1, pos.column));
247+
if (!this.fieldsGrid[position.row - 1][position.column].hasBomb) {
248+
queue.push(new BoardPosition(position.row - 1, position.column));
218249
}
219250
}
220251

221252
if (
222-
pos.row > 0 &&
223-
pos.column < this.size - 1 &&
224-
this.fieldsGrid[pos.row - 1][pos.column + 1].status === FieldStatus.Hidden
253+
position.row > 0 &&
254+
position.column < this.size - 1 &&
255+
this.fieldsGrid[position.row - 1][position.column + 1].status === FieldStatus.Hidden
225256
) {
226-
this.fieldsGrid[pos.row - 1][pos.column + 1].status = FieldStatus.Visible;
257+
this.fieldsGrid[position.row - 1][position.column + 1].status = FieldStatus.Visible;
227258

228-
if (!this.fieldsGrid[pos.row - 1][pos.column + 1].hasBomb) {
229-
queue.push(new BoardPosition(pos.row - 1, pos.column + 1));
259+
if (!this.fieldsGrid[position.row - 1][position.column + 1].hasBomb) {
260+
queue.push(new BoardPosition(position.row - 1, position.column + 1));
230261
}
231262
}
232263

233264
if (
234-
pos.column > 0 &&
235-
this.fieldsGrid[pos.row][pos.column - 1].status === FieldStatus.Hidden
265+
position.column > 0 &&
266+
this.fieldsGrid[position.row][position.column - 1].status === FieldStatus.Hidden
236267
) {
237-
this.fieldsGrid[pos.row][pos.column - 1].status = FieldStatus.Visible;
268+
this.fieldsGrid[position.row][position.column - 1].status = FieldStatus.Visible;
238269

239-
if (!this.fieldsGrid[pos.row][pos.column - 1].hasBomb) {
240-
queue.push(new BoardPosition(pos.row, pos.column - 1));
270+
if (!this.fieldsGrid[position.row][position.column - 1].hasBomb) {
271+
queue.push(new BoardPosition(position.row, position.column - 1));
241272
}
242273
}
243274

244275
if (
245-
pos.column < this.size - 1 &&
246-
this.fieldsGrid[pos.row][pos.column + 1].status === FieldStatus.Hidden
276+
position.column < this.size - 1 &&
277+
this.fieldsGrid[position.row][position.column + 1].status === FieldStatus.Hidden
247278
) {
248-
this.fieldsGrid[pos.row][pos.column + 1].status = FieldStatus.Visible;
279+
this.fieldsGrid[position.row][position.column + 1].status = FieldStatus.Visible;
249280

250-
if (!this.fieldsGrid[pos.row][pos.column + 1].hasBomb) {
251-
queue.push(new BoardPosition(pos.row, pos.column + 1));
281+
if (!this.fieldsGrid[position.row][position.column + 1].hasBomb) {
282+
queue.push(new BoardPosition(position.row, position.column + 1));
252283
}
253284
}
254285

255286
if (
256-
pos.row < this.size - 1 &&
257-
pos.column > 0 &&
258-
this.fieldsGrid[pos.row + 1][pos.column - 1].status === FieldStatus.Hidden
287+
position.row < this.size - 1 &&
288+
position.column > 0 &&
289+
this.fieldsGrid[position.row + 1][position.column - 1].status === FieldStatus.Hidden
259290
) {
260-
this.fieldsGrid[pos.row + 1][pos.column - 1].status = FieldStatus.Visible;
291+
this.fieldsGrid[position.row + 1][position.column - 1].status = FieldStatus.Visible;
261292

262-
if (!this.fieldsGrid[pos.row + 1][pos.column - 1].hasBomb) {
263-
queue.push(new BoardPosition(pos.row + 1, pos.column - 1));
293+
if (!this.fieldsGrid[position.row + 1][position.column - 1].hasBomb) {
294+
queue.push(new BoardPosition(position.row + 1, position.column - 1));
264295
}
265296
}
266297

267298
if (
268-
pos.row < this.size - 1 &&
269-
this.fieldsGrid[pos.row + 1][pos.column].status === FieldStatus.Hidden
299+
position.row < this.size - 1 &&
300+
this.fieldsGrid[position.row + 1][position.column].status === FieldStatus.Hidden
270301
) {
271-
this.fieldsGrid[pos.row + 1][pos.column].status = FieldStatus.Visible;
302+
this.fieldsGrid[position.row + 1][position.column].status = FieldStatus.Visible;
272303

273-
if (!this.fieldsGrid[pos.row + 1][pos.column].hasBomb) {
274-
queue.push(new BoardPosition(pos.row + 1, pos.column));
304+
if (!this.fieldsGrid[position.row + 1][position.column].hasBomb) {
305+
queue.push(new BoardPosition(position.row + 1, position.column));
275306
}
276307
}
277308

278309
if (
279-
pos.row < this.size - 1 &&
280-
pos.column < this.size - 1 &&
281-
this.fieldsGrid[pos.row + 1][pos.column + 1].status === FieldStatus.Hidden
310+
position.row < this.size - 1 &&
311+
position.column < this.size - 1 &&
312+
this.fieldsGrid[position.row + 1][position.column + 1].status === FieldStatus.Hidden
282313
) {
283-
this.fieldsGrid[pos.row + 1][pos.column + 1].status = FieldStatus.Visible;
314+
this.fieldsGrid[position.row + 1][position.column + 1].status = FieldStatus.Visible;
284315

285-
if (!this.fieldsGrid[pos.row + 1][pos.column + 1].hasBomb) {
286-
queue.push(new BoardPosition(pos.row + 1, pos.column + 1));
316+
if (!this.fieldsGrid[position.row + 1][position.column + 1].hasBomb) {
317+
queue.push(new BoardPosition(position.row + 1, position.column + 1));
287318
}
288319
}
289320
}

src/app/models/game-mode.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { BoardPosition } from "./board-position";
2+
3+
export interface GameMode {
4+
get modeName(): string;
5+
get playingImage(): string;
6+
get winningImage(): string;
7+
get losingImage(): string;
8+
9+
initialBombs(posClicked: BoardPosition): BoardPosition[];
10+
}

src/app/models/game-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export enum GameState {
22
New,
3-
Played,
3+
Playing,
44
Finished
55
}

0 commit comments

Comments
 (0)