From ea97970da148175c10f18c05af6bf15a025fff27 Mon Sep 17 00:00:00 2001 From: Wessel Tip Date: Tue, 11 Mar 2025 16:04:56 +0000 Subject: [PATCH] feat: Work on hints, drawing cards until set is available --- .../backend/Controllers/GamesController.cs | 19 ++++++++++ backend/backend/Models/Game.cs | 37 ++++++++++++++++--- frontend/src/app/card/card.component.ts | 2 +- frontend/src/app/game/game.component.html | 30 +++++++++++++++ frontend/src/app/game/game.component.ts | 9 ++++- frontend/src/service/game/game.service.ts | 16 ++++++++ 6 files changed, 106 insertions(+), 7 deletions(-) diff --git a/backend/backend/Controllers/GamesController.cs b/backend/backend/Controllers/GamesController.cs index 269c512..9219c66 100755 --- a/backend/backend/Controllers/GamesController.cs +++ b/backend/backend/Controllers/GamesController.cs @@ -130,5 +130,24 @@ namespace backend.Controllers return res; } + + [HttpGet] + [Route("[action]/{id}")] + public async Task>> SetsInHand(long id) { + var game = await _context.Games.FindAsync(id); + if (game == null) { + return NotFound(); + } + + var res = game.GetIndicesOfSet(); + + if (res == null) { + return BadRequest(); + } + + Console.WriteLine($"Found {res.Count} sets in hand"); + + return res; + } } } diff --git a/backend/backend/Models/Game.cs b/backend/backend/Models/Game.cs index 78b1b8c..bfe0b45 100755 --- a/backend/backend/Models/Game.cs +++ b/backend/backend/Models/Game.cs @@ -21,13 +21,13 @@ public class Game { Deck = Deck.OrderBy(_ => rand.Next()).ToArray(); } - public void DealHand() { + public void DealHand(int max = 12) { if (Deck == null) return; Hand ??= []; List handList = [.. Hand]; - while (handList.Count < 12 && Deck.Length > 0) { + while (handList.Count < max && Deck.Length > 0) { handList.Add(Deck[0]); Deck = [.. Deck.Skip(1)]; } @@ -64,7 +64,7 @@ public class Game { return finished; } - public SetCheckResult? IsSet(ushort[] indices) { + public SetCheckResult? IsSet(ushort[] indices, bool remove = true) { if (GameIsFinished()) { FinishedAt = DateTime.Now; @@ -89,14 +89,21 @@ public class Game { AllSameOrDifferent(cards[0].Shade, cards[1].Shade, cards[2].Shade) && AllSameOrDifferent(cards[0].Count, cards[1].Count, cards[2].Count) )) { + // todo(wessel): Split up for checking algorithm to game data Fails += 1; return new SetCheckResult { IsSet = false, NewState = this }; } // Order by Descending to make sure the correct card is removed // (From the top may cause the indices to be off by one) - foreach (var index in indices.OrderByDescending(i => i)) { - ReplaceCardInHand(index); + if (remove) { + foreach (var index in indices.OrderByDescending(i => i)) { + ReplaceCardInHand(index); + } + + while (GetIndicesOfSet().Count < 1 && Deck?.Length > 0) { + DealHand(Hand.Length + 1); + } } return new SetCheckResult { IsSet = true, NewState = this }; @@ -109,4 +116,24 @@ public class Game { return (ai == bi && bi == ci) || (ai != bi && bi != ci && ai != ci); } + + public List GetIndicesOfSet() { + if (Hand == null) return new List(); + List res = new List(); + + for (int i = 0; i < Hand.Length; i++) { + for (int j = i + 1; j < Hand.Length; j++) { + for (int k = j + 1; k < Hand.Length; k++) { + var result = IsSet([(ushort)i, (ushort)j, (ushort)k], false); + + if (result?.IsSet == true) { + Console.WriteLine($"Found set at {i}, {j}, {k}"); + res.Add([i, j, k]); + } + } + } + } + + return res; + } } diff --git a/frontend/src/app/card/card.component.ts b/frontend/src/app/card/card.component.ts index 5f64a23..e28256f 100755 --- a/frontend/src/app/card/card.component.ts +++ b/frontend/src/app/card/card.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, input, Input, OnInit } from '@angular/core'; import { Card, CardColor, CardCount, CardShade, CardShape } from '../models/card'; @Component({ diff --git a/frontend/src/app/game/game.component.html b/frontend/src/app/game/game.component.html index aeb006c..233f105 100755 --- a/frontend/src/app/game/game.component.html +++ b/frontend/src/app/game/game.component.html @@ -15,6 +15,19 @@ + +
+

Hint

+ @for(card of hint; track card.id) { + + } +
+

Deck Size {{ gameService.stats().size }} @@ -39,6 +52,23 @@ /> } +

+

Available Sets

+
+ @for(row of this.gameService.possibleSets; track row) { +
+

Set {{$index + 1}}

+ @for(card of row; track card.id) { + + } +
+ } +
diff --git a/frontend/src/app/game/game.component.ts b/frontend/src/app/game/game.component.ts index 825bc1a..f45b287 100755 --- a/frontend/src/app/game/game.component.ts +++ b/frontend/src/app/game/game.component.ts @@ -14,6 +14,7 @@ import { ActivatedRoute, UrlSegment, Router } from '@angular/router'; export class GameComponent { gameId: string = ''; + hint: Card[] = [] constructor(public gameService: GameService, private route: ActivatedRoute, private router: Router) { this.route.params.subscribe(params => { @@ -39,8 +40,14 @@ export class GameComponent { this.returnHome(); } - selectCard(card: Card) { + async selectCard(card: Card) { this.gameService.selectCard(card); card.selected = !card.selected; } + + async showHint() { + if (this.gameService.possibleSets.length < 0) return console.error('No valid sets found'); + + this.hint = [this.gameService.possibleSets[0][0], this.gameService.possibleSets[0][1]] + } } diff --git a/frontend/src/service/game/game.service.ts b/frontend/src/service/game/game.service.ts index 3e85471..a65a0f7 100755 --- a/frontend/src/service/game/game.service.ts +++ b/frontend/src/service/game/game.service.ts @@ -7,6 +7,7 @@ import axios from 'axios'; export class GameService { public deck: Card[] = []; public hand: Card[] = []; + public possibleSets: Card[][] = []; public gameId: number = 0; public fails: number = 0; @@ -39,6 +40,7 @@ export class GameService { this.startDate = new Date(req.data.startedAt); this.fails = req.data.fails; this.gameId = req.data.id; + await this.updateSets(); return req.data.id; @@ -57,6 +59,9 @@ export class GameService { this.startDate = new Date(res.data.startedAt); this.fails = res.data.fails; this.gameId = res.data.id; + + await this.updateSets(); + return res.data.id; } @@ -78,8 +83,18 @@ export class GameService { } } + public async updateSets(): Promise { + const req = await axios.get('http://localhost:5224/api/v1/Games/SetsInHand/' + this.gameId); + const cards = req.data.map((set: number[]) => set.map((card: number) => this.hand[card])); + + this.possibleSets = cards; + + return cards; + } + private isSet(cards: number[]): boolean { + console.log(this.possibleSets); // return (['shape', 'color', 'count', 'shade'] as (keyof Card)[]).every(attr => { // const values = new Set([card1[attr], card2[attr], card3[attr]]); // return values.size === 1 || values.size === 3; @@ -89,6 +104,7 @@ export class GameService { this.hand = response.data.newState.hand.map((card: number) => toCard(card)); this.deck = response.data.newState.deck.map((card: number) => toCard(card)); this.fails = response.data.newState.fails; + this.updateSets(); return response.data.isSet; });