Skip to content

Commit 5929f59

Browse files
authored
N Picks per pack (#1296)
1 parent f3f1053 commit 5929f59

16 files changed

+1634
-249
lines changed

backend/bot.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@ const {sample, pull} = require("lodash");
22
const Player = require("./player");
33

44
module.exports = class extends Player {
5-
constructor() {
5+
constructor(picksPerPack) {
66
super({
77
isBot: true,
88
isConnected: true,
99
name: "bot",
10-
id: ""
10+
id: "",
1111
});
12+
this.picksPerPack = picksPerPack;
1213
}
1314

1415
getPack(pack) {
15-
const randomPick = sample(pack);
16-
this.picks.push(randomPick.name);
17-
pull(pack, randomPick);
16+
let randomPick;
17+
let min = Math.min(this.picksPerPack,pack.length);
18+
for (var i = 0; i < min; i++) {
19+
randomPick = sample(pack);
20+
this.picks.push(randomPick.name);
21+
pull(pack, randomPick);
22+
}
1823
this.emit("pass", pack);
1924
}
2025
};

backend/game.js

+38-34
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ const {saveDraftStats, getDataDir} = require("./data");
1313
const path = require("path");
1414

1515
module.exports = class Game extends Room {
16-
constructor({ hostId, title, seats, type, sets, cube, isPrivate, modernOnly, totalChaos, chaosPacksNumber }) {
16+
constructor({ hostId, title, seats, type, sets, cube, isPrivate, modernOnly, totalChaos, chaosPacksNumber, picksPerPack }) {
1717
super({ isPrivate });
1818
const gameID = uuid.v1();
1919
Object.assign(this, {
20-
title, seats, type, isPrivate, modernOnly, totalChaos, cube, chaosPacksNumber,
20+
title, seats, type, isPrivate, modernOnly, totalChaos, cube, chaosPacksNumber, picksPerPack,
2121
delta: -1,
2222
hostID: hostId,
2323
id: gameID,
@@ -29,7 +29,6 @@ module.exports = class Game extends Room {
2929
secret: uuid.v4(),
3030
logger: logger.child({ id: gameID })
3131
});
32-
3332
// Handle packsInfos to show various informations about the game
3433
switch(type) {
3534
case "draft":
@@ -194,45 +193,48 @@ module.exports = class Game extends Room {
194193
this.logger.debug(`${sock.name} joined the game`);
195194

196195
function regularDraftPickDelegate(index) {
197-
const pack = this.packs.shift();
198-
const card = pack.splice(index, 1)[0];
199-
200-
this.draftLog.pack.push( [`--> ${card.name}`].concat(pack.map(x => ` ${x.name}`)) );
201-
this.updateDraftStats(this.draftLog.pack[ this.draftLog.pack.length-1 ], this.pool);
202-
203-
let pickcard = card.name;
204-
if (card.foil === true)
205-
pickcard = "*" + pickcard + "*";
206-
207-
this.pool.push(card);
208-
this.picks.push(pickcard);
209-
this.send("add", card);
196+
index.sort(function(a, b){return b-a;});
197+
let cards=[];
198+
let pack = this.packs.shift();
199+
for (var i = 0; i < index.length; i++) {
200+
cards.push( pack.splice(index[i], 1)[0]);
201+
this.draftLog.pack.push( [`--> ${cards[i].name}`].concat(pack.map(x => ` ${x.name}`)) );
202+
this.pool.push(cards[i]);
203+
let pickcard = cards[i].name;
204+
if (cards[i].foil === true)
205+
pickcard = "*" + pickcard + "*";
206+
this.picks.push(pickcard);
207+
this.updateDraftStats(this.draftLog.pack[ this.draftLog.pack.length-index.length ], this.pool);
208+
this.send("add", cards[i]);
209+
}
210210

211211
let [next] = this.packs;
212212
if (!next)
213213
this.time = 0;
214214
else
215215
this.sendPack(next);
216-
217-
this.autopickIndex = -1;
216+
this.autopickIndex = [];
218217
this.emit("pass", pack);
219218
}
220219

221220
function decadentDraftPickDelegate(index) {
222-
const pack = this.packs.shift();
223-
const card = pack.splice(index, 1)[0];
224-
225-
this.draftLog.pack.push( [`--> ${card.name}`].concat(pack.map(x => ` ${x.name}`)) );
226-
this.updateDraftStats(this.draftLog.pack[ this.draftLog.pack.length-1 ], this.pool);
227-
228-
let pickcard = card.name;
229-
if (card.foil === true)
230-
pickcard = "*" + pickcard + "*";
231-
232-
this.pool.push(card);
233-
this.picks.push(pickcard);
234-
this.send("add", card);
221+
index.sort(function(a, b){return b-a;});
222+
let cards=[];
235223

224+
const pack = this.packs.shift();
225+
for (var i = 0; i < index.length; i++) {
226+
cards.push( pack.splice(index[i], 1)[0]);
227+
this.draftLog.pack.push( [`--> ${cards[i].name}`].concat(pack.map(x => ` ${x.name}`)) );
228+
this.updateDraftStats(this.draftLog.pack[ this.draftLog.pack.length-1 ], this.pool);
229+
230+
let pickcard = cards[i].name;
231+
if (cards[i].foil === true)
232+
pickcard = "*" + pickcard + "*";
233+
234+
this.pool.push(cards[i]);
235+
this.picks.push(pickcard);
236+
this.send("add", cards[i]);
237+
}
236238
let [next] = this.packs;
237239
if (!next)
238240
this.time = 0;
@@ -243,13 +245,13 @@ module.exports = class Game extends Room {
243245
// after one is chosen.
244246
pack.length = 0;
245247

246-
this.autopickIndex = -1;
248+
this.autopickIndex = [];
247249
this.emit("pass", pack);
248250
}
249251

250252
const draftPickDelegate = this.isDecadent ? decadentDraftPickDelegate : regularDraftPickDelegate;
251253

252-
const h = new Human(sock, draftPickDelegate);
254+
const h = new Human(sock, draftPickDelegate, this.picksPerPack);
253255
if (h.id === this.hostID) {
254256
h.isHost = true;
255257
sock.once("start", this.start.bind(this));
@@ -523,6 +525,7 @@ module.exports = class Game extends Room {
523525
});
524526
break;
525527
}
528+
526529
case "sealed": {
527530
this.pool = Pool.SealedNormal({
528531
playersLength: this.players.length,
@@ -586,7 +589,7 @@ module.exports = class Game extends Room {
586589

587590
if (this.shouldAddBots()) {
588591
while (this.players.length < this.seats) {
589-
this.players.push(new Bot());
592+
this.players.push(new Bot(this.picksPerPack));
590593
this.bots++;
591594
}
592595
}
@@ -630,6 +633,7 @@ module.exports = class Game extends Room {
630633
type: ${this.type}
631634
sets: ${this.sets}
632635
isPrivate: ${this.isPrivate}
636+
picksPerPack: ${this.picksPerPack}
633637
modernOnly: ${this.modernOnly}
634638
totalChaos: ${this.totalChaos}
635639
chaosPacksNumber: ${this.chaosPacksNumber}

backend/human.js

+33-15
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
const Player = require("./player");
22
const util = require("./util");
33
const hash = require("./hash");
4-
const {random} = require("lodash");
4+
const {random, pull} = require("lodash");
55
const logger = require("./logger");
66

77
module.exports = class extends Player {
8-
constructor(sock, pickDelegate) {
8+
constructor(sock, pickDelegate, picksPerPack) {
99
super({
1010
isBot: false,
1111
isConnected: true,
1212
name: sock.name,
13-
id: sock.id
13+
id: sock.id,
1414
});
15+
this.picksPerPack = picksPerPack;
1516
this.pickDelegate = pickDelegate.bind(this);
1617
this.attach(sock);
18+
this.autopickIndex = [];
1719
}
1820

1921
attach(sock) {
@@ -52,13 +54,15 @@ module.exports = class extends Player {
5254
}
5355
_autopick(index) {
5456
let [pack] = this.packs;
55-
if (pack && index < pack.length)
56-
this.autopickIndex = index;
57+
if (pack && index < pack.length){
58+
if (this.autopickIndex.length == this.picksPerPack){
59+
this.autopickIndex.shift();
60+
}
61+
this.autopickIndex.push(index);
62+
}
5763
}
58-
_pick(index) {
59-
let [pack] = this.packs;
60-
if (pack && index < pack.length)
61-
this.pick(index);
64+
_pick() {
65+
this.pick();
6266
}
6367
getPack(pack) {
6468
if (this.packs.push(pack) === 1)
@@ -111,14 +115,28 @@ module.exports = class extends Player {
111115
let namePool = pool.map(card => card.name);
112116
this.draftStats.push( { picked, notPicked, pool: namePool } );
113117
}
114-
pick(index) {
115-
this.pickDelegate(index);
118+
pick() {
119+
this.pickDelegate(this.autopickIndex);
116120
}
117121
pickOnTimeout() {
118-
let index = this.autopickIndex;
119-
if (index === -1)
120-
index = random(this.packs[0].length - 1);
121-
this.pick(index);
122+
let pack = this.packs.slice(0);
123+
let newIndex;
124+
let card;
125+
let min = Math.min(this.packs[0].length,this.picksPerPack);
126+
if(this.autopickIndex.length < min){
127+
for (var i = 0; i < this.autopickIndex.length; i++) {
128+
card = pack[this.autopickIndex[i]];
129+
pull(pack, card);
130+
}
131+
let difference = min - this.autopickIndex.length;
132+
for (var a = 0; a < difference; a++) {
133+
newIndex = random(0,pack.length - 1);
134+
this.autopickIndex.push(newIndex);
135+
card = pack[newIndex];
136+
pull(pack, card);
137+
}
138+
}
139+
this.pick();
122140
}
123141
kick() {
124142
this.send = () => {};

backend/player.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Player extends EventEmitter {
2020
isHost: false,
2121
time: 0,
2222
packs: [],
23-
autopickIndex: -1,
23+
autopickIndex: [],
2424
pool: [],
2525
cap: {
2626
packs: {}

backend/pool.js

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ const DraftNormal = ({ playersLength, sets }) => (
4949
.map(boosterGenerator)
5050
.map(addCardIdsToBoosterCards)
5151
);
52-
5352
// Get a random set and transform it to pack
5453
function getRandomPack(setList) {
5554
const code = chooseRandomSet(setList).code;

frontend/media/autoremove.png

8.3 KB
Loading

frontend/media/picked.png

9.62 KB
Loading

frontend/src/app.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ let App = {
3232
chaosDraftPacksNumber: 3,
3333
chaosSealedPacksNumber: 6,
3434
gametype: "draft",
35+
picksPerPack: 1,
36+
DoubleMasters: -1,
3537
gamesubtype: "regular",
3638
sets: [],
3739
setsDraft: [],
@@ -143,11 +145,13 @@ let App = {
143145
this.ws.send(msg);
144146
},
145147
initGameState(id) {
146-
const { gameStates } = App.state;
148+
const { gameStates, picksPerPack } = App.state;
147149
if (!gameStates[id]) {
148150
App.state.gameState = new GameState();
151+
App.state.gameState.setPicksPerPack(picksPerPack);
149152
} else {
150153
App.state.gameState = new GameState(gameStates[id]);
154+
App.state.picksPerPack = gameStates[id].picksPerPack;
151155
}
152156
App.state.gameState.on("updateGameState", (gameState) => {
153157
App.save("gameStates", {

frontend/src/events.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ const events = {
102102
},
103103

104104
create() {
105-
let {gametype, gamesubtype, seats, title, isPrivate, modernOnly, totalChaos, chaosDraftPacksNumber, chaosSealedPacksNumber} = App.state;
105+
let {gametype, gamesubtype, seats, title, isPrivate, modernOnly, totalChaos, chaosDraftPacksNumber, chaosSealedPacksNumber, picksPerPack} = App.state;
106106
seats = Number(seats);
107107

108108
//TODO: either accept to use the legacy types (draft, sealed, chaos draft ...) by keeping it like this
109109
// OR change backend to accept "regular draft" instead of "draft" and "regular sealed" instead of "sealed"
110110
const type = `${/regular/.test(gamesubtype) ? "" : gamesubtype + " "}${gametype}`;
111111

112-
let options = {type, seats, title, isPrivate, modernOnly, totalChaos};
112+
let options = {type, seats, title, isPrivate, modernOnly, totalChaos,picksPerPack};
113113

114114
switch (gamesubtype) {
115115
case "regular": {
@@ -144,6 +144,10 @@ const events = {
144144

145145
App.save(type, sets);
146146
},
147+
changePicksPerPack(event) {
148+
App.state.picksPerPack = event.currentTarget.value;
149+
App.update();
150+
},
147151
pool(cards) {
148152
const zoneName = App.state.side ? ZONE_SIDEBOARD : ZONE_MAIN;
149153
this.state.gameState.addToPool(zoneName, cards);
@@ -370,9 +374,12 @@ const clickPack = (card) => {
370374
App.state.gameState.updateAutopick(card.cardId);
371375
App.send("autopick", index);
372376
} else {
373-
App.state.gameState.resetPack();
374-
App.update();
375-
App.send("pick", index);
377+
if (App.state.picksPerPack == App.state.gameState.getAutopickCardIds().length ||
378+
pack.length == App.state.gameState.getAutopickCardIds().length){
379+
App.state.gameState.resetPack();
380+
App.update();
381+
App.send("pick");
382+
}
376383
}
377384
};
378385

frontend/src/game/Grid.jsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ const getZoneDetails = (appState, zoneName, cards) => {
2727
// Only 1 pick in decadent draft.
2828
return `Pick 1 / 1`;
2929
} else {
30-
return `Pick ${appState.pickNumber} / ${appState.packSize}`
30+
let turns = Math.ceil(appState.packSize / appState.picksPerPack );
31+
return `Pick ${appState.pickNumber} / ${turns}`
3132
}
3233
} else {
3334
return cards.length;
@@ -42,11 +43,13 @@ const zone = (zoneName, index) => {
4243

4344
const zoneTitle = zoneDisplayName + (zoneName === ZONE_PACK ? " " + App.state.round : "");
4445
const zoneDetails = getZoneDetails(App.state, zoneName, cards);
45-
46+
const min = Math.min(App.state.picksPerPack,cards.length);
47+
const selectUpTo = 'select ' + min + (min>1? ' cards': ' card');
48+
const elementsContent = zoneName === ZONE_PACK ? [zoneTitle, zoneDetails, selectUpTo]:[zoneTitle, zoneDetails];
4649
return (
4750
<div className='zone' key={index}>
4851
<h1>
49-
<Spaced elements={[zoneTitle, zoneDetails]}/>
52+
<Spaced elements={elementsContent}/>
5053
</h1>
5154
{cards.map((card, i) =>
5255
<Card key={i+zoneName+card.name+card.foil} card={card} zoneName={zoneName} />
@@ -96,11 +99,13 @@ class Card extends Component {
9699
render() {
97100
const {card, zoneName} = this.props;
98101
const isAutopickable = zoneName === ZONE_PACK && App.state.gameState.isAutopick(card.cardId);
99-
102+
const isAutoremovableAutopick = App.state.gameState.isAutoremovableAutopick(card.cardId);
100103
const className = `card
101-
${isAutopickable ? "autopick-card " : ""}
102104
${card.foil ? "foil-card " : ""}
105+
${isAutopickable ? "autopick-card " : ""}
106+
${isAutoremovableAutopick ? "autoremovable-pick " : ""}
103107
${this.state.flipped ? "flipped " : ""}`;
108+
104109

105110
const title
106111
= isAutopickable

frontend/src/game/StartPanel.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const StartPanel = () => {
1414
<span>
1515
<div>Type: {gameType}</div>
1616
<div>Info: {App.state.game.packsInfo}</div>
17+
<div>Picks per pack: {" " + App.state.picksPerPack }</div>
1718
{(App.state.isHost && !App.state.didGameStart)
1819
? <StartControls/>
1920
: <div />}

0 commit comments

Comments
 (0)