Compare commits

..

2 commits

Author SHA1 Message Date
572bd90d97
Add I8PCube
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2019-09-16 15:45:45 +02:00
dddeca9867
Add comment about setTimeout hack 2019-09-16 12:08:02 +02:00
6 changed files with 141 additions and 3 deletions

View file

@ -5,6 +5,7 @@ export class DraftBot {
assign(player: SessionPlayer) { assign(player: SessionPlayer) {
player.on("available-picks", cards => { player.on("available-picks", cards => {
const pick = this.pick(cards); const pick = this.pick(cards);
// setTimeout hack to avoid handlers being called before the rest of the code
setTimeout(() => player.pick(pick.ID), 0); setTimeout(() => player.pick(pick.ID), 0);
}); });
} }

View file

@ -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);
} }
} }

View 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
});
}
}

View file

@ -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");
} }

View file

@ -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;
}

View file

@ -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);
});
});
}); });