Add reward reveal, pick, and skip functions to run module

This commit is contained in:
Jared Miller 2026-02-24 22:36:18 -05:00
parent 11e12ee906
commit 46bd6e6d2b
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 82 additions and 1 deletions

View file

@ -13,6 +13,27 @@ export function createRunState(character) {
};
}
export function revealRewards(run) {
const count = Math.min(3, run.cardRewardsDeck.length);
const revealed = run.cardRewardsDeck.slice(0, count);
const cardRewardsDeck = run.cardRewardsDeck.slice(count);
return { revealed, run: { ...run, cardRewardsDeck } };
}
export function pickReward(run, revealed, index) {
return {
...run,
deck: [...run.deck, revealed[index]],
};
}
export function skipRewards(run, revealed) {
return {
...run,
cardRewardsDeck: shuffle([...run.cardRewardsDeck, ...revealed]),
};
}
function buildRewardsDeck(character) {
const ids = [];
for (const card of getAllCards()) {

View file

@ -1,7 +1,12 @@
import { beforeAll, describe, expect, test } from "bun:test";
import { getAllCards, initCards } from "./cards.js";
import { initEnemies } from "./enemies.js";
import { createRunState } from "./run.js";
import {
createRunState,
pickReward,
revealRewards,
skipRewards,
} from "./run.js";
beforeAll(async () => {
await Promise.all([initCards(), initEnemies()]);
@ -49,3 +54,58 @@ describe("createRunState", () => {
expect(allSorted).toBe(false);
});
});
describe("rewards", () => {
test("revealRewards removes 3 from rewards deck and returns them", () => {
const run = createRunState("ironclad");
const originalLen = run.cardRewardsDeck.length;
const { revealed, run: updated } = revealRewards(run);
expect(revealed).toHaveLength(3);
expect(updated.cardRewardsDeck).toHaveLength(originalLen - 3);
});
test("revealRewards handles deck with fewer than 3 cards", () => {
const run = createRunState("ironclad");
const modified = { ...run, cardRewardsDeck: ["card_a", "card_b"] };
const { revealed, run: updated } = revealRewards(modified);
expect(revealed).toHaveLength(2);
expect(updated.cardRewardsDeck).toHaveLength(0);
});
test("revealRewards with empty deck returns empty revealed", () => {
const run = { ...createRunState("ironclad"), cardRewardsDeck: [] };
const { revealed, run: updated } = revealRewards(run);
expect(revealed).toHaveLength(0);
expect(updated.cardRewardsDeck).toHaveLength(0);
});
test("pickReward adds picked card to deck", () => {
const run = createRunState("ironclad");
const originalDeckLen = run.deck.length;
const { revealed, run: afterReveal } = revealRewards(run);
const updated = pickReward(afterReveal, revealed, 0);
expect(updated.deck).toHaveLength(originalDeckLen + 1);
expect(updated.deck).toContain(revealed[0]);
});
test("pickReward discards unpicked cards", () => {
const run = createRunState("ironclad");
const { revealed, run: afterReveal } = revealRewards(run);
const rewardsDeckLen = afterReveal.cardRewardsDeck.length;
const updated = pickReward(afterReveal, revealed, 1);
// unpicked cards are gone, not returned to rewards deck
expect(updated.cardRewardsDeck).toHaveLength(rewardsDeckLen);
expect(updated.deck).not.toContain(revealed[0]);
expect(updated.deck).toContain(revealed[1]);
expect(updated.deck).not.toContain(revealed[2]);
});
test("skipRewards reshuffles all 3 back into rewards deck", () => {
const run = createRunState("ironclad");
const { revealed, run: afterReveal } = revealRewards(run);
const rewardsDeckLen = afterReveal.cardRewardsDeck.length;
const updated = skipRewards(afterReveal, revealed);
expect(updated.cardRewardsDeck).toHaveLength(rewardsDeckLen + 3);
expect(updated.deck).toHaveLength(run.deck.length); // deck unchanged
});
});