From 572bd90d97fa0556c7f7418d281b429824aa08c9 Mon Sep 17 00:00:00 2001 From: Hamcha Date: Mon, 16 Sep 2019 15:45:45 +0200 Subject: [PATCH] Add I8PCube --- src/mlpccg/draft/cube.ts | 4 +- src/mlpccg/draft/i8pcube.ts | 81 ++++++++++++++++++++++++++++++++++++ src/mlpccg/draft/session.ts | 5 ++- src/mlpccg/draft/types.ts | 17 ++++++++ src/tests/unit/draft.spec.ts | 36 +++++++++++++++- 5 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/mlpccg/draft/i8pcube.ts diff --git a/src/mlpccg/draft/cube.ts b/src/mlpccg/draft/cube.ts index fc6d4c1..1e437e7 100644 --- a/src/mlpccg/draft/cube.ts +++ b/src/mlpccg/draft/cube.ts @@ -40,7 +40,9 @@ export class Cube { } static async fromURL(url: string) { - const res = await axios(url); + const res = await axios(url, { + responseType: "text" + }); return await this.fromList(res.data); } } diff --git a/src/mlpccg/draft/i8pcube.ts b/src/mlpccg/draft/i8pcube.ts new file mode 100644 index 0000000..1b46687 --- /dev/null +++ b/src/mlpccg/draft/i8pcube.ts @@ -0,0 +1,81 @@ +import { Card, cardFromIDs } from "@/mlpccg"; +import { + PackSchema, + I8PCubeSchema, + I8PPackSchema, + I8PFileSchema, + DraftSchema +} from "./types"; +import axios from "axios"; +import { PackBuilder } from "./booster"; + +export class I8PCube { + private pools: Record; + private packschema: I8PPackSchema[]; + private problemCount: number; + + constructor(cubefile: I8PCubeSchema) { + this.pools = cubefile.Cards; + this.packschema = cubefile.Schema; + this.problemCount = cubefile.ProblemPackSize; + } + + schema(): DraftSchema { + return { + boosters: { + main: 4, + problem: 1 + }, + factories: { + main: new PackBuilder({ + slots: this.packschema.map(s => ({ + amount: s.Amount, + provider: this.provider(s.Type), + alternate: [] + })) + }), + problem: new PackBuilder({ + slots: [ + { + amount: this.problemCount, + provider: this.provider("problem"), + alternate: [] + } + ] + }) + } + }; + } + + *provider(name: string | "all") { + let poolname = name; + while (true) { + if (name == "all") { + const pools = Object.keys(this.pools); + const idx = Math.floor(Math.random() * pools.length); + poolname = pools[idx]; + } + const pool = this.pools[poolname]; + if (pool.length <= 0) { + return; + } + const idx = Math.floor(Math.random() * pool.length); + const card = pool.splice(idx, 1); + yield card[0]; + } + } + + static async fromURL(url: string) { + const res = await axios(url); + const cubefile = res.data as I8PFileSchema; + let cards: Record = {}; + for (const pool in cubefile.Cards) { + cards[pool] = await cardFromIDs(cubefile.Cards[pool]); + } + return new this({ + Cards: cards, + ProblemPackSize: cubefile.ProblemPackSize, + Schema: cubefile.Schema + }); + } +} diff --git a/src/mlpccg/draft/session.ts b/src/mlpccg/draft/session.ts index 56b6653..c3e9d02 100644 --- a/src/mlpccg/draft/session.ts +++ b/src/mlpccg/draft/session.ts @@ -4,6 +4,7 @@ import { Card } from "@/mlpccg"; import { Pack, Direction } from "./types"; import { DraftProvider } from "./provider"; import { DraftBot } from "./bot"; +import { I8PCube } from "./i8pcube"; export class Session extends EventEmitter { private options: DraftOptions; @@ -179,7 +180,9 @@ export class Session extends EventEmitter { return new Session(options, provider); } case "i8pcube": - throw new Error("not implemented"); + const cube = await I8PCube.fromURL(options.url); + const provider = new DraftProvider(cube.schema()); + return new Session(options, provider); default: throw new Error("Unknown draft source"); } diff --git a/src/mlpccg/draft/types.ts b/src/mlpccg/draft/types.ts index 8d09467..7b2931a 100644 --- a/src/mlpccg/draft/types.ts +++ b/src/mlpccg/draft/types.ts @@ -71,3 +71,20 @@ export interface DraftSchema { } export type Direction = "cw" | "ccw"; + +export interface I8PCubeSchema { + Schema: I8PPackSchema[]; + ProblemPackSize: number; + Cards: Record; +} + +export interface I8PFileSchema { + Schema: I8PPackSchema[]; + ProblemPackSize: number; + Cards: Record; +} + +export interface I8PPackSchema { + Amount: number; + Type: string; +} diff --git a/src/tests/unit/draft.spec.ts b/src/tests/unit/draft.spec.ts index 5f3bbb7..1db04e2 100644 --- a/src/tests/unit/draft.spec.ts +++ b/src/tests/unit/draft.spec.ts @@ -1,5 +1,5 @@ import { setupIDBShim, EventHook } from "@/testing"; -import { initDB, loadSets, Database } from "@/mlpccg"; +import { initDB, loadSets, Database, Card } from "@/mlpccg"; import { PackBuilder, spanByRarity, @@ -94,4 +94,38 @@ describe("mlpccg/draft", () => { } await hook.expect("session-done"); }); + + test("Sessions can load and draft I8PCube files", async () => { + expect(Database).toBeTruthy(); + const session = await Session.create({ + type: "booster-draft", + source: "i8pcube", + url: "https://mcg.zyg.ovh/cubes/hamchacube.json", + packs: 4, + players: 4, + spacing: "evenly" + }); + const hook = new EventHook(); + hook.hookEmitter(session, "start", "session-start"); + session.assign(["test1"], (_, player) => { + hook.hookEmitter(player, "available-picks", "got-cards"); + }); + session.start(); + await hook.expect("session-start"); + await hook.expect("got-cards", 1000, (cards: Card[]) => { + expect(cards).toHaveLength(12); + // Check for 2 or more multicolor cards + const multicolor = cards.filter( + c => + c.Element.length > 1 || + (c.Requirement && Object.keys(c.Requirement).length > 1) + ); + expect(multicolor.length).toBeGreaterThanOrEqual(2); + // Check for 2 or more entry cards + const entry = cards.filter( + c => !c.Requirement || c.Requirement.length < 1 + ); + expect(entry.length).toBeGreaterThanOrEqual(2); + }); + }); });