Skip to content

Commit

Permalink
Adding menu to snoguess
Browse files Browse the repository at this point in the history
  • Loading branch information
alopezo committed Feb 15, 2024
1 parent 24fdc6b commit f88e80c
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 96 deletions.
Binary file added docs/assets/img/SI_CT_w_tagline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/img/snoguess-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
gtag('config', 'G-7SK998GPMX', { 'page_path': '/home' });
}
</script>
<style>*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }html,body{height:100%}body{margin:0;font-family:Roboto,Helvetica Neue,sans-serif}</style><link rel="stylesheet" href="styles.e2e86333782a342a.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.e2e86333782a342a.css"></noscript></head>
<style>*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }html,body{height:100%}body{margin:0;font-family:Roboto,Helvetica Neue,sans-serif}</style><link rel="stylesheet" href="styles.1e268e0cb8b258f2.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.1e268e0cb8b258f2.css"></noscript></head>
<body class="mat-typography">
<app-root></app-root>
<script src="runtime.c2d2548033d65b02.js" type="module"></script><script src="polyfills.75186c7b7fc1d123.js" type="module"></script><script src="scripts.a1e2309b4257c7b3.js" defer></script><script src="main.6b0327b434170248.js" type="module"></script>
<script src="runtime.c2d2548033d65b02.js" type="module"></script><script src="polyfills.75186c7b7fc1d123.js" type="module"></script><script src="scripts.a1e2309b4257c7b3.js" defer></script><script src="main.cc6fde15e71b7882.js" type="module"></script>

</body></html>

Large diffs are not rendered by default.

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions src/app/game/service/snoguess.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface Game {
hitPoints: number; // Number of attempts left
hints: string[]; // Hints that have been revealed
hintsAvailable: boolean; // Whether hints are available
state: 'playing' | 'gameOver' | 'loading' | 'won'; // Game state,
state: 'playing' | 'gameOver' | 'loading' | 'won' | 'menu'; // Game state,
score: number; // Score of the game
}

Expand Down Expand Up @@ -49,13 +49,17 @@ export class SnoguessService {
randomLimit: number = 4000;

@Output() guessResult: EventEmitter<any> = new EventEmitter();
@Output() termResult: EventEmitter<boolean> = new EventEmitter();
@Output() termResult: EventEmitter<string> = new EventEmitter();

constructor(private terminologyService: TerminologyService) {
// Initialize the game with default values
this.game = new BehaviorSubject<Game>(this.resetGame());
}

loadGame() {
this.game.next({ ...this.game.value, state: 'menu' });
}

async getRandomConcept(reset?: boolean) {
// Do nothing if game state is not playing
this.game.next({ ...this.game.value, state: 'loading', score: reset ? 0 : this.game.value.score, hitPoints: reset ? this.maxHitPoints : this.game.value.hitPoints });
Expand Down Expand Up @@ -251,7 +255,7 @@ export class SnoguessService {
// Check if the term was guessed by verifying if there are no more '_' characters before the semantic tag
const isTermGessed = newState.displayTerm.slice(0, semanticTagIndex).indexOf('_') === -1;
if (isTermGessed && newState.state === 'playing') {
this.termResult.emit(true); // Emit true for correct term guesses
this.termResult.emit(newState.term); // Emit true for correct term guesses
newState.hitPoints = newState.hitPoints + this.hitpointsAwardedForGuessingfullTerm; // Add a hit points for winning
if (newState.hitPoints > this.maxHitPoints) {
newState.hitPoints = this.maxHitPoints;
Expand All @@ -270,7 +274,7 @@ export class SnoguessService {
// Guess the full term
guessTerm(guess: string): boolean {
if (guess.toLowerCase() === this.game.value.term.toLowerCase()) {
this.termResult.emit(true); // Emit true for correct term guesses
this.termResult.emit(guess); // Emit true for correct term guesses
this.game.next({ ...this.game.value, displayTerm: this.game.value.term.split('') });
return true;
} else {
Expand Down
1 change: 1 addition & 0 deletions src/app/game/snoguess-main/snoguess-main.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
letter-spacing: 4px; /* Adds space between letters */
word-break: break-all; /* Ensures the term wraps if it's too long for the container */
margin-bottom: 20px; /* Adds some space before the next section */
text-align: center; /* Center the term display */
}

.term-display span {
Expand Down
154 changes: 73 additions & 81 deletions src/app/game/snoguess-main/snoguess-main.component.html
Original file line number Diff line number Diff line change
@@ -1,82 +1,90 @@
<div class="snoguess-game" *ngIf="(game | async) as gameState">
<h2>Guess the SNOMED Term</h2>

<div class="term-display" *ngIf="gameState.state != 'loading'">
<span *ngFor="let char of gameState.displayTerm">{{ char }}</span>
</div>

<div *ngIf="gameState.state === 'loading'" class="loading-container">
<div class="progress-bar-message">
Choosing a random SNOMED CT concept using the FHIR API
<div *ngIf="gameState.state == 'playing' || gameState.state == 'loading'">

<div class="flex justify-center items-center">
<img src="assets/img/snoguess-logo.png" alt="Game Logo" class="w-1/4 mt-8 mb-8">
</div>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>

<div class="hit-points">
<span class="score">
Score: {{ gameState.score }} &nbsp;&nbsp;&nbsp;&nbsp; Life:
</span>
<span *ngFor="let hp of [].constructor(gameState.hitPoints); let i = index">
<mat-icon>favorite</mat-icon>
</span>
<span *ngFor="let hp of [].constructor(gameState.maxHitPoints - gameState.hitPoints); let i = index">
<mat-icon>favorite_border</mat-icon>
</span>
</div>


<div>
<!-- <div class="guess-field">
<mat-form-field appearance="fill" [@shake]="shakeState">
<mat-label>Guess a letter</mat-label>
<input matInput #letterInput maxlength="1" (input)="letterInput.value = letterInput.value.slice(0, 1)"
(keyup.enter)="letterInput.value ? guessLetter(letterInput.value) : null; letterInput.value=''"
[disabled]="gameState.state !== 'playing'">
</mat-form-field>
<button mat-flat-button color="accent"
(click)="letterInput.value ? guessLetter(letterInput.value) : null; letterInput.value=''"
[disabled]="gameState.state !== 'playing' || !letterInput.value">Guess</button>
</div> -->
<div class="term-display" *ngIf="gameState.state == 'playing'">
<span *ngFor="let char of gameState.displayTerm">{{ char }}</span>
</div>

<div *ngIf="gameState.state === 'loading'" class="loading-container">
<div class="progress-bar-message">
Choosing a random SNOMED CT concept using the FHIR API
</div>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>

<div class="hit-points">
<span class="score">
Score: {{ gameState.score }} &nbsp;&nbsp;&nbsp;&nbsp; Life:
</span>
<span *ngFor="let hp of [].constructor(gameState.hitPoints); let i = index">
<mat-icon>favorite</mat-icon>
</span>
<span *ngFor="let hp of [].constructor(gameState.maxHitPoints - gameState.hitPoints); let i = index">
<mat-icon>favorite_border</mat-icon>
</span>
</div>

<p class="guess-message">Click the keys to guess the letters of the term!</p>
<div [@shake]="shakeState">
<app-keyboard #keyboard (letterGuessed)="guessLetter($event)"></app-keyboard>
</div>

<!-- <div class="guess-field">
<mat-form-field appearance="fill">
<mat-label>Guess the full term</mat-label>
<input matInput #fullTermInput (keyup.enter)="guessTerm(fullTermInput.value); fullTermInput.value=''" [disabled]="gameState.state !== 'playing'">
</mat-form-field>
<button mat-flat-button color="accent" (click)="guessTerm(fullTermInput.value); fullTermInput.value=''" [disabled]="gameState.state !== 'playing'">Guess</button>
</div> -->

<br>
<div class="guess-field">
<button mat-flat-button color="accent" (click)="revealHint()" (keydown.enter)="$event.preventDefault()" [disabled]="gameState.state !== 'playing' || !gameState.hintsAvailable || gameState.hitPoints <= 1">Reveal Hint</button>
<button mat-flat-button color="accent" (click)="initialize()" (keydown.enter)="$event.preventDefault()" [disabled]="gameState.state !== 'playing'">Reset</button>
</div>
<div class="note">
* Hints are generated from the definition of the SNOMED CT concept, retrieved from the FHIR API as an SCG grammar expression
<div class="guess-field mt-8">
<button mat-flat-button color="accent" (click)="revealHint()" (keydown.enter)="$event.preventDefault()" [disabled]="gameState.state !== 'playing' || !gameState.hintsAvailable || gameState.hitPoints <= 1">Reveal Hint</button>
<button mat-flat-button color="accent" (click)="loadMenu()" (keydown.enter)="$event.preventDefault()" [disabled]="gameState.state !== 'playing'">Abandon game</button>
</div>
<div class="note">
* Hints are generated from the definition of the SNOMED CT concept, retrieved from the FHIR API as an SCG grammar expression
</div>

<div *ngIf="gameState.hints.length > 0" class="hints-container">
<div class="hints-callout text-center">
<h2>Hints:</h2>
<ul>
<li *ngFor="let hint of gameState.hints" [innerHTML]="hint"></li>
</ul>
</div>

<div *ngIf="gameState.hints.length > 0" class="hints-container">
<div class="hints-callout">
<h2>Hints</h2>
<ul>
<li *ngFor="let hint of gameState.hints" [innerHTML]="hint"></li>
</ul>
</div>
</div>

<div class="score-progression-panel">
<h3>Score Progression</h3>
<div class="progress-bar-container">
<mat-progress-bar mode="determinate" [value]="calculateProgress(gameState.score)"></mat-progress-bar>
<!-- Goal Indicators and Trophy icons generated dynamically -->
<ng-container *ngFor="let goal of goals">
<div class="goal-indicator" [class]="goal.name.toLowerCase()" [style.left.%]="calculateGoalPosition(goal.score)"></div>
<mat-icon *ngIf="gameState.score >= goal.score" class="star-icon left-star" [ngClass]="[goal.name.toLowerCase()]" [style.left.%]="calculateGoalPosition(goal.score-5)">grade</mat-icon>
<mat-icon class="trophy-icon" [ngClass]="[goal.name.toLowerCase(), (gameState.score >= goal.score) ? 'trophy-large' : '']" [style.left.%]="calculateGoalPosition(goal.score-3)">emoji_events</mat-icon>
<mat-icon *ngIf="gameState.score >= goal.score" class="star-icon right-star" [ngClass]="[goal.name.toLowerCase()]" [style.left.%]="calculateGoalPosition(goal.score-1)">grade</mat-icon>
<div *ngIf="gameState.score >= goal.score" class="goal-name" [style.left.%]="calculateGoalPosition(goal.score)" [ngClass]="[goal.name.toLowerCase()]">{{ goal.name }} trophy!</div>
</ng-container>
</div>

</div>
</div>


<div *ngIf="gameState.state === 'menu'" class="flex flex-col items-center gap-4">
<img src="assets/img/SI_CT_w_tagline.png" alt="SNOMED CT Logo" class="w-1/6">
<img src="assets/img/snoguess-logo.png" alt="Game Logo" class="w-1/4 mt-8">
<p class="text-center">Welcome to SnoGuess! A fun way to learn about SNOMED CT concepts and their definitions.</p>
<div (click)="startGame()"
class="bg-gradient-to-b from-blue-500 to-gray-500 hover:from-black hover:to-blue-500 border-solid border-4 border-black
rounded-3xl pl-12 pr-12 pt-4 pb-4 w-1/5 text-center cursor-pointer font-bold text-white mt-12 mb-24 text-3xl">
New game
</div>
</div>

<div *ngIf="termGuessed" class="overlay overlay-transparent">
<div class="pyro">
<div class="before"></div>
<div class="after"></div>
</div>
<div class="message won">Correct!</div>
<div class="reveal won">{{ gameState.term }}</div>
<div class="reveal won">{{ termGuessed }}</div>
</div>

<!-- Overlay for "Lost" state -->
Expand Down Expand Up @@ -148,7 +156,10 @@ <h2>Hints</h2>
<mat-icon class="" [ngClass]="[getMaxTrophyObtained(gameState.score).toLocaleLowerCase(), 'shadow']">grade</mat-icon>
</div>
<br>
<button mat-flat-button color="warn" (click)="initialize()">Try Again</button>
<div class="flex gap-4">
<button mat-flat-button color="warn" (click)="startGame()">Try Again</button>
<button mat-flat-button color="warn" (click)="loadMenu()">Back to menu</button>
</div>
</div>

<div *ngIf="gameState.state == 'won'" class="overlay overlay-dark">
Expand All @@ -165,23 +176,4 @@ <h2>Hints</h2>
<div class="reveal won">Final score: {{ gameState.score }}</div>
</div>

<!-- Existing Game Panels Here -->

<!-- Score Progression Panel -->
<div class="score-progression-panel">
<h3>Score Progression</h3>
<div class="progress-bar-container">
<mat-progress-bar mode="determinate" [value]="calculateProgress(gameState.score)"></mat-progress-bar>
<!-- Goal Indicators and Trophy icons generated dynamically -->
<ng-container *ngFor="let goal of goals">
<div class="goal-indicator" [class]="goal.name.toLowerCase()" [style.left.%]="calculateGoalPosition(goal.score)"></div>
<mat-icon *ngIf="gameState.score >= goal.score" class="star-icon left-star" [ngClass]="[goal.name.toLowerCase()]" [style.left.%]="calculateGoalPosition(goal.score-5)">grade</mat-icon>
<mat-icon class="trophy-icon" [ngClass]="[goal.name.toLowerCase(), (gameState.score >= goal.score) ? 'trophy-large' : '']" [style.left.%]="calculateGoalPosition(goal.score-3)">emoji_events</mat-icon>
<mat-icon *ngIf="gameState.score >= goal.score" class="star-icon right-star" [ngClass]="[goal.name.toLowerCase()]" [style.left.%]="calculateGoalPosition(goal.score-1)">grade</mat-icon>
<div *ngIf="gameState.score >= goal.score" class="goal-name" [style.left.%]="calculateGoalPosition(goal.score)" [ngClass]="[goal.name.toLowerCase()]">{{ goal.name }} trophy!</div>
</ng-container>
</div>

</div>

</div>
17 changes: 10 additions & 7 deletions src/app/game/snoguess-main/snoguess-main.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export class SnoguessMainComponent implements OnInit {

game!: Observable<Game>;
shakeState = 'normal';
termGuessed = false;
termGuessed = '';
goals: any[] = [];

constructor(private snoguessMainService: SnoguessService) {}

ngOnInit(): void {
this.game = this.snoguessMainService.getGameState();
this.goals = this.snoguessMainService.goals;
this.initialize();
this.loadMenu();
this.snoguessMainService.guessResult.subscribe((guess: any) => {
if (guess.result === false) {
this.keyboard.addGuessedLetter(guess.letter, false);
Expand All @@ -48,18 +48,22 @@ export class SnoguessMainComponent implements OnInit {
}
});

this.snoguessMainService.termResult.subscribe((result: boolean) => {
this.snoguessMainService.termResult.subscribe((result: string) => {
if (result) {
this.keyboard.reset();
this.termGuessed = true;
this.termGuessed = result;
setTimeout(() => {
this.termGuessed = false;
this.termGuessed = '';
}, 3000);
}
});
}

initialize(): void {
loadMenu(): void {
this.snoguessMainService.loadGame();
}

startGame(): void {
if (this.keyboard) this.keyboard.reset();
this.snoguessMainService.getRandomConcept(true);
}
Expand Down Expand Up @@ -127,7 +131,6 @@ export class SnoguessMainComponent implements OnInit {
maxTrophy = goal.name;
}
});
console.log(maxTrophy);
return maxTrophy;
}

Expand Down
Binary file added src/assets/img/SI_CT_w_tagline.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/img/snoguess-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f88e80c

Please sign in to comment.