Skip to content

Commit

Permalink
Merge pull request #6 from ref-humbold/troll
Browse files Browse the repository at this point in the history
Troll mode
  • Loading branch information
R. Kaleta authored Sep 21, 2021
2 parents 61f008a + f11dbb5 commit ed9f265
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 91 deletions.
3 changes: 2 additions & 1 deletion src/app/components/game-board/game-board.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<div id="board" class="d-flex flex-column h-100 w-100">
<div id="panel" class="row">
<div class="counter text col-4">{{flagsLeft}}</div>
<div class="face col-2 offset-1" (click)="startNewGame()">
<div class="face col-2 offset-1" (click)="onLeftClickFace()"
(contextmenu)="onRightClickFace($event)">
<img [src]="faceImage" />
</div>
<div class="counter text col-4 offset-1">{{seconds}}</div>
Expand Down
209 changes: 120 additions & 89 deletions src/app/components/game-board/game-board.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Component, ViewChildren, QueryList, AfterViewInit } from "@angular/core";
import { Subscription } from "rxjs";
import { TickerService } from "../../services/ticker.service";
import { GameMode } from "../../models/game-mode";
import { GameState } from "../../models/game-state";
import { GameResult } from "../..//models/game-result";
import { BoardPosition } from "../../models/board-position";
import { NormalModeService } from "../../services/normal-mode.service";
import { TrollModeService } from "../../services/troll-mode.service";
import { TickerService } from "../../services/ticker.service";
import { FieldStatus, FieldComponent } from "../field/field.component";

@Component({
Expand All @@ -14,22 +17,39 @@ import { FieldStatus, FieldComponent } from "../field/field.component";
export class GameBoardComponent implements AfterViewInit {
@ViewChildren("field") public fieldsList: QueryList<FieldComponent>;
public fieldsGrid: FieldComponent[][];
private readonly modes: GameMode[];
public readonly size: number = 16;
public readonly bombsCount: number = 32;
public flagsLeft: number = this.bombsCount;
public seconds: number = 0;
public faceImage: string = "../../../assets/epicface.jpg";
protected secondsTicker: Subscription;
protected state: GameState = GameState.New;
private secondsTicker: Subscription;
private state: GameState = GameState.New;
private score: number = 0;

constructor(private readonly ticker: TickerService) {}
private modeIndex: number = 0;

constructor(
private readonly ticker: TickerService,
normalMode: NormalModeService,
trollMode: TrollModeService
) {
this.modes = [normalMode, trollMode];
}

public ngAfterViewInit(): void {
this.fieldsListToGrid();
this.startNewGame();
}

public get currentMode(): GameMode {
return this.modes[this.modeIndex];
}

public changeMode(): void {
this.modeIndex = 1 - this.modeIndex;
this.ngAfterViewInit();
}

public startNewGame(): void {
if (this.secondsTicker) {
this.secondsTicker.unsubscribe();
Expand All @@ -38,9 +58,9 @@ export class GameBoardComponent implements AfterViewInit {
this.state = GameState.New;
this.flagsLeft = this.bombsCount;
this.seconds = 0;
this.faceImage = "../../../assets/epicface.jpg";
this.faceImage = this.currentMode.playingImage;
this.score = 0;
this.fieldsGrid.forEach(rw => rw.forEach(fd => fd.clear()));
this.fieldsGrid.forEach(row => row.forEach(field => field.clear()));
this.secondsTicker = this.ticker.create(() => ++this.seconds);
}

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

if (result === GameResult.Winning) {
this.faceImage = "../../../assets/winface.jpg";
this.faceImage = this.currentMode.winningImage;
} else {
this.faceImage = "../../../assets/sadface.jpg";
this.fieldsGrid.forEach(rw =>
rw.forEach(fld => {
if (fld.hasBomb) {
fld.status = FieldStatus.Visible;
this.faceImage = this.currentMode.losingImage;
this.fieldsGrid.forEach(row =>
row.forEach(field => {
if (field.hasBomb) {
field.status = FieldStatus.Visible;
}
})
);
}
}

public onLeftClickFace(): void {
this.startNewGame();
}

public onRightClickFace(event: MouseEvent): void {
event.preventDefault();

if (this.state === GameState.Finished) {
this.changeMode();
}
}

public onLeftClickField(position: BoardPosition): void {
if (this.state === GameState.Finished) {
return;
Expand All @@ -71,7 +103,7 @@ export class GameBoardComponent implements AfterViewInit {
const bombs: BoardPosition[] = this.generateBombs(position);

this.countDistances(bombs);
this.state = GameState.Played;
this.state = GameState.Playing;
}

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

public onRightClickField(pos: BoardPosition): void {
if (this.state !== GameState.Played) {
public onRightClickField(position: BoardPosition): void {
if (this.state !== GameState.Playing) {
return;
}

const field: FieldComponent = this.fieldsGrid[pos.row][pos.column];
const field: FieldComponent = this.fieldsGrid[position.row][position.column];

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

private initialBombs(posClicked: BoardPosition): BoardPosition[] {
return [];
}

private fieldsListToGrid(): void {
this.fieldsGrid = new Array<FieldComponent[]>(this.size).fill(null);

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

private generateBombs(posClicked: BoardPosition): BoardPosition[] {
const bombs: BoardPosition[] = this.initialBombs(posClicked);
private generateBombs(positionClicked: BoardPosition): BoardPosition[] {
const bombs: BoardPosition[] = this.currentMode.initialBombs(positionClicked);

while (bombs.length < this.bombsCount) {
let bombPosition: BoardPosition;
Expand All @@ -140,7 +168,7 @@ export class GameBoardComponent implements AfterViewInit {
);
} while (
bombs.findIndex(p => p.equals(bombPosition)) >= 0 ||
posClicked.isNeighbour(bombPosition)
positionClicked.isNeighbour(bombPosition)
);

bombs.push(bombPosition);
Expand All @@ -149,42 +177,42 @@ export class GameBoardComponent implements AfterViewInit {
return bombs;
}

private countDistances(bombs: BoardPosition[]): void {
for (const pos of bombs) {
this.fieldsGrid[pos.row][pos.column].createBomb();
private countDistances(bombPositions: BoardPosition[]): void {
for (const position of bombPositions) {
this.fieldsGrid[position.row][position.column].createBomb();
}

for (const pos of bombs) {
if (pos.row > 0 && pos.column > 0) {
this.fieldsGrid[pos.row - 1][pos.column - 1].addNeighbouringBomb();
for (const position of bombPositions) {
if (position.row > 0 && position.column > 0) {
this.fieldsGrid[position.row - 1][position.column - 1].addNeighbouringBomb();
}

if (pos.row > 0) {
this.fieldsGrid[pos.row - 1][pos.column].addNeighbouringBomb();
if (position.row > 0) {
this.fieldsGrid[position.row - 1][position.column].addNeighbouringBomb();
}

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

if (pos.column > 0) {
this.fieldsGrid[pos.row][pos.column - 1].addNeighbouringBomb();
if (position.column > 0) {
this.fieldsGrid[position.row][position.column - 1].addNeighbouringBomb();
}

if (pos.column < this.size - 1) {
this.fieldsGrid[pos.row][pos.column + 1].addNeighbouringBomb();
if (position.column < this.size - 1) {
this.fieldsGrid[position.row][position.column + 1].addNeighbouringBomb();
}

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

if (pos.row < this.size - 1) {
this.fieldsGrid[pos.row + 1][pos.column].addNeighbouringBomb();
if (position.row < this.size - 1) {
this.fieldsGrid[position.row + 1][position.column].addNeighbouringBomb();
}

if (pos.row < this.size - 1 && pos.column < this.size - 1) {
this.fieldsGrid[pos.row + 1][pos.column + 1].addNeighbouringBomb();
if (position.row < this.size - 1 && position.column < this.size - 1) {
this.fieldsGrid[position.row + 1][position.column + 1].addNeighbouringBomb();
}
}
}
Expand All @@ -195,95 +223,98 @@ export class GameBoardComponent implements AfterViewInit {
this.fieldsGrid[startPos.row][startPos.column].status = FieldStatus.Visible;

while (queue.length > 0) {
const pos: BoardPosition = queue.shift();
const position: BoardPosition = queue.shift();

if (this.fieldsGrid[pos.row][pos.column].isEmpty) {
if (this.fieldsGrid[position.row][position.column].isEmpty) {
if (
pos.row > 0 &&
pos.column > 0 &&
this.fieldsGrid[pos.row - 1][pos.column - 1].status === FieldStatus.Hidden
position.row > 0 &&
position.column > 0 &&
this.fieldsGrid[position.row - 1][position.column - 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row - 1][pos.column - 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row - 1][position.column - 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row - 1][pos.column - 1].hasBomb) {
queue.push(new BoardPosition(pos.row - 1, pos.column - 1));
if (!this.fieldsGrid[position.row - 1][position.column - 1].hasBomb) {
queue.push(new BoardPosition(position.row - 1, position.column - 1));
}
}

if (pos.row > 0 && this.fieldsGrid[pos.row - 1][pos.column].status === FieldStatus.Hidden) {
this.fieldsGrid[pos.row - 1][pos.column].status = FieldStatus.Visible;
if (
position.row > 0 &&
this.fieldsGrid[position.row - 1][position.column].status === FieldStatus.Hidden
) {
this.fieldsGrid[position.row - 1][position.column].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row - 1][pos.column].hasBomb) {
queue.push(new BoardPosition(pos.row - 1, pos.column));
if (!this.fieldsGrid[position.row - 1][position.column].hasBomb) {
queue.push(new BoardPosition(position.row - 1, position.column));
}
}

if (
pos.row > 0 &&
pos.column < this.size - 1 &&
this.fieldsGrid[pos.row - 1][pos.column + 1].status === FieldStatus.Hidden
position.row > 0 &&
position.column < this.size - 1 &&
this.fieldsGrid[position.row - 1][position.column + 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row - 1][pos.column + 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row - 1][position.column + 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row - 1][pos.column + 1].hasBomb) {
queue.push(new BoardPosition(pos.row - 1, pos.column + 1));
if (!this.fieldsGrid[position.row - 1][position.column + 1].hasBomb) {
queue.push(new BoardPosition(position.row - 1, position.column + 1));
}
}

if (
pos.column > 0 &&
this.fieldsGrid[pos.row][pos.column - 1].status === FieldStatus.Hidden
position.column > 0 &&
this.fieldsGrid[position.row][position.column - 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row][pos.column - 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row][position.column - 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row][pos.column - 1].hasBomb) {
queue.push(new BoardPosition(pos.row, pos.column - 1));
if (!this.fieldsGrid[position.row][position.column - 1].hasBomb) {
queue.push(new BoardPosition(position.row, position.column - 1));
}
}

if (
pos.column < this.size - 1 &&
this.fieldsGrid[pos.row][pos.column + 1].status === FieldStatus.Hidden
position.column < this.size - 1 &&
this.fieldsGrid[position.row][position.column + 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row][pos.column + 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row][position.column + 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row][pos.column + 1].hasBomb) {
queue.push(new BoardPosition(pos.row, pos.column + 1));
if (!this.fieldsGrid[position.row][position.column + 1].hasBomb) {
queue.push(new BoardPosition(position.row, position.column + 1));
}
}

if (
pos.row < this.size - 1 &&
pos.column > 0 &&
this.fieldsGrid[pos.row + 1][pos.column - 1].status === FieldStatus.Hidden
position.row < this.size - 1 &&
position.column > 0 &&
this.fieldsGrid[position.row + 1][position.column - 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row + 1][pos.column - 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row + 1][position.column - 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row + 1][pos.column - 1].hasBomb) {
queue.push(new BoardPosition(pos.row + 1, pos.column - 1));
if (!this.fieldsGrid[position.row + 1][position.column - 1].hasBomb) {
queue.push(new BoardPosition(position.row + 1, position.column - 1));
}
}

if (
pos.row < this.size - 1 &&
this.fieldsGrid[pos.row + 1][pos.column].status === FieldStatus.Hidden
position.row < this.size - 1 &&
this.fieldsGrid[position.row + 1][position.column].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row + 1][pos.column].status = FieldStatus.Visible;
this.fieldsGrid[position.row + 1][position.column].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row + 1][pos.column].hasBomb) {
queue.push(new BoardPosition(pos.row + 1, pos.column));
if (!this.fieldsGrid[position.row + 1][position.column].hasBomb) {
queue.push(new BoardPosition(position.row + 1, position.column));
}
}

if (
pos.row < this.size - 1 &&
pos.column < this.size - 1 &&
this.fieldsGrid[pos.row + 1][pos.column + 1].status === FieldStatus.Hidden
position.row < this.size - 1 &&
position.column < this.size - 1 &&
this.fieldsGrid[position.row + 1][position.column + 1].status === FieldStatus.Hidden
) {
this.fieldsGrid[pos.row + 1][pos.column + 1].status = FieldStatus.Visible;
this.fieldsGrid[position.row + 1][position.column + 1].status = FieldStatus.Visible;

if (!this.fieldsGrid[pos.row + 1][pos.column + 1].hasBomb) {
queue.push(new BoardPosition(pos.row + 1, pos.column + 1));
if (!this.fieldsGrid[position.row + 1][position.column + 1].hasBomb) {
queue.push(new BoardPosition(position.row + 1, position.column + 1));
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/app/models/game-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BoardPosition } from "./board-position";

export interface GameMode {
get modeName(): string;
get playingImage(): string;
get winningImage(): string;
get losingImage(): string;

initialBombs(posClicked: BoardPosition): BoardPosition[];
}
2 changes: 1 addition & 1 deletion src/app/models/game-state.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export enum GameState {
New,
Played,
Playing,
Finished
}
Loading

0 comments on commit ed9f265

Please sign in to comment.