From 45c53304cf5ed7ac7893b95f2db676b6f0f0c3ad Mon Sep 17 00:00:00 2001
From: Divyansh Seth <divyanshseth08@gmail.com>
Date: Sun, 2 Jun 2024 00:57:51 +0530
Subject: [PATCH] engine: improved card drawing logic. this commit handles the
 drawing logic from an empty cardDeck. - It reshuffles the thrown cards into
 the card deck when the card deck is empty and a player needs to draw a card.
 - It returns success message if the card is drawn successfully else returns
 message error. - Also added relevant unit test, in engine.test.ts, to verify
 this function (drawCardFromDeck) works correctly.

---
 backend/tests/engine.test.ts      | 21 ++++++++++++++++++
 backend/uno-game-engine/engine.ts | 36 +++++++++++++++++++++++++------
 2 files changed, 51 insertions(+), 6 deletions(-)
 create mode 100644 backend/tests/engine.test.ts

diff --git a/backend/tests/engine.test.ts b/backend/tests/engine.test.ts
new file mode 100644
index 0000000..1fd7312
--- /dev/null
+++ b/backend/tests/engine.test.ts
@@ -0,0 +1,21 @@
+import { GameEngine } from '../uno-game-engine/engine';
+
+describe('testing drawCardFromDeck()', () => {
+    test('draws a card when deck is empty but thrownCards is not', () => {
+        const game = new GameEngine();
+        game.addPlayer({ id: '1', cards: [] });
+        game.cardDeck = [];
+        game.thrownCards = [
+            {
+                type: 'number',
+                color: 'yellow',
+                value: '1',
+                id: 'card-number-yellow-1-1',
+            },
+        ];
+        const player = game.players[0];
+        const status: EventResult = game.drawCardFromDeck(player);
+        expect(player.cards.length).toBe(1);
+        expect(status.type).toBe('SUCCESS');
+    });
+});
diff --git a/backend/uno-game-engine/engine.ts b/backend/uno-game-engine/engine.ts
index 17bf2fe..0c97d04 100644
--- a/backend/uno-game-engine/engine.ts
+++ b/backend/uno-game-engine/engine.ts
@@ -1,4 +1,4 @@
-import { getShuffledCardDeck } from './deck';
+import { getShuffledCardDeck, shuffle } from './deck';
 import { handleEvent } from './gameEvents';
 
 const NUM_CARDS_PER_PLAYER = 7;
@@ -47,11 +47,35 @@ export class GameEngine {
         this.currentPlayerIndex =
             (this.currentPlayerIndex + this.direction) % this.players.length;
     }
-    drawCardFromDeck(player: Player) {
-        //todo: Handle the case when the deck is empty and we have to move the thrown cards back to the deck
-        this.players
-            .find((p: Player) => p.id === player.id)
-            .cards.push(this.cardDeck.pop());
+    drawCardFromDeck(player: Player): EventResult {
+        try {
+            if (this.cardDeck.length === 0) {
+                this.cardDeck = [...this.thrownCards];
+                this.thrownCards = [];
+                shuffle(this.cardDeck);
+            }
+            const currentPlayer = this.players.find(
+                (p: Player) => p.id === player.id
+            );
+            if (currentPlayer && this.cardDeck) {
+                const card = this.cardDeck.pop();
+                if (card) {
+                    currentPlayer.cards.push(card);
+                    return {
+                        type: 'SUCCESS',
+                        message: 'Card drawn successfully',
+                    };
+                } else
+                    return { type: 'ERROR', message: 'Unable to draw a card' };
+            } else {
+                return {
+                    type: 'ERROR',
+                    message: 'Player not found or cardDeck is empty',
+                };
+            }
+        } catch (error) {
+            return { type: 'ERROR', message: (error as Error).message };
+        }
     }
     dispatchEvent(event: GameEvent) {
         // handle different types of events based on event.type