Basic draft library #19
5 changed files with 140 additions and 3 deletions
|
@ -40,7 +40,9 @@ export class Cube {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async fromURL(url: string) {
|
static async fromURL(url: string) {
|
||||||
const res = await axios(url);
|
const res = await axios(url, {
|
||||||
|
responseType: "text"
|
||||||
|
});
|
||||||
return await this.fromList(res.data);
|
return await this.fromList(res.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
src/mlpccg/draft/i8pcube.ts
Normal file
81
src/mlpccg/draft/i8pcube.ts
Normal file
|
@ -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<string, Card[]>;
|
||||||
|
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<string, Card[]> = {};
|
||||||
|
for (const pool in cubefile.Cards) {
|
||||||
|
cards[pool] = await cardFromIDs(cubefile.Cards[pool]);
|
||||||
|
}
|
||||||
|
return new this({
|
||||||
|
Cards: cards,
|
||||||
|
ProblemPackSize: cubefile.ProblemPackSize,
|
||||||
|
Schema: cubefile.Schema
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import { Card } from "@/mlpccg";
|
||||||
import { Pack, Direction } from "./types";
|
import { Pack, Direction } from "./types";
|
||||||
import { DraftProvider } from "./provider";
|
import { DraftProvider } from "./provider";
|
||||||
import { DraftBot } from "./bot";
|
import { DraftBot } from "./bot";
|
||||||
|
import { I8PCube } from "./i8pcube";
|
||||||
|
|
||||||
export class Session extends EventEmitter {
|
export class Session extends EventEmitter {
|
||||||
private options: DraftOptions;
|
private options: DraftOptions;
|
||||||
|
@ -179,7 +180,9 @@ export class Session extends EventEmitter {
|
||||||
return new Session(options, provider);
|
return new Session(options, provider);
|
||||||
}
|
}
|
||||||
case "i8pcube":
|
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:
|
default:
|
||||||
throw new Error("Unknown draft source");
|
throw new Error("Unknown draft source");
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,3 +71,20 @@ export interface DraftSchema {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Direction = "cw" | "ccw";
|
export type Direction = "cw" | "ccw";
|
||||||
|
|
||||||
|
export interface I8PCubeSchema {
|
||||||
|
Schema: I8PPackSchema[];
|
||||||
|
ProblemPackSize: number;
|
||||||
|
Cards: Record<string, Card[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface I8PFileSchema {
|
||||||
|
Schema: I8PPackSchema[];
|
||||||
|
ProblemPackSize: number;
|
||||||
|
Cards: Record<string, string[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface I8PPackSchema {
|
||||||
|
Amount: number;
|
||||||
|
Type: string;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { setupIDBShim, EventHook } from "@/testing";
|
import { setupIDBShim, EventHook } from "@/testing";
|
||||||
import { initDB, loadSets, Database } from "@/mlpccg";
|
import { initDB, loadSets, Database, Card } from "@/mlpccg";
|
||||||
import {
|
import {
|
||||||
PackBuilder,
|
PackBuilder,
|
||||||
spanByRarity,
|
spanByRarity,
|
||||||
|
@ -94,4 +94,38 @@ describe("mlpccg/draft", () => {
|
||||||
}
|
}
|
||||||
await hook.expect("session-done");
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue