diff --git a/README.md b/README.md index 8915a754..6c250db5 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ You can debug this application by adding the following configuration to your `la "cwd": "${workspaceFolder}", "runtimeExecutable": "npm", "runtimeArgs": [ - "run", "start-debug" + "run", "start-debug" ], "port": 1338 } diff --git a/backend/player/bot.js b/backend/player/bot.js index fe89f747..a600a259 100644 --- a/backend/player/bot.js +++ b/backend/player/bot.js @@ -1,4 +1,70 @@ -const {sample, pull, times} = require("lodash"); +const { sample, pull, times, shuffle } = require("lodash"); +const pileSort = require("pile-sort"); + +const RARITY_ORDER = ["Mythic", "Rare", "Uncommon", "Common", "Basic"]; +function sortByRarity (cards) { + return shuffle(cards).sort((a, b) => { + return RARITY_ORDER.indexOf(a.rarity) - RARITY_ORDER.indexOf(b.rarity); + }); +} + +const decidingPicksNumber = 6; +function samplePick (pack, pool, myColors) { + if (pool.length === decidingPicksNumber) { + const colorCount = pool.reduce( + (acc, pack) => { + pack.colorIdentity.forEach(color => { acc[color] += 1; }); + return acc; + }, + { + W: 0, + U: 0, + B: 0, + R: 0, + G: 0 + // TODO count colourless? + } + ); + + const countColors = Object.keys(colorCount).reduce( + (acc, color) => { + const count = colorCount[color]; + if (!acc[count]) { + acc[count] = []; + } + acc[count].push(color); + return acc; + }, + {} + ); + const orderedColors = Object.values(countColors) + .reduce( + (acc, next) => { + return [...acc, ...shuffle(next)]; + }, + [] + ); + + myColors.clear(); + orderedColors.slice(0, 2).forEach(color => myColors.add(color)); + } + + const [cardsInMyColors, cardsNotInMyColors] = pileSort(pack, [ + card => { + return ( + card.colorIdentity.length === 0 || + card.colorIdentity.some(color => myColors.has(color)) + // NOTE: this means if you if your colors are WU, you can find your bot + // picks a WG card (they match on W and are splashing?) + ); + } + ]); + + const orderedPicks = sortByRarity(cardsInMyColors); + if (orderedPicks.length) return orderedPicks[0]; + + return sortByRarity(cardsNotInMyColors)[0]; +} const Player = require("./index"); const logger = require("../logger"); @@ -14,15 +80,18 @@ module.exports = class Bot extends Player { this.gameId= gameId; this.picksPerPack = picksPerPack; this.burnsPerPack = burnsPerPack; + + this.myColors = new Set(["W", "U", "B", "R", "G"]); // bot chooses 2 colors at some point } getPack(pack) { const cardsToPick = Math.min(this.picksPerPack, pack.length); times(cardsToPick, () => { - const randomPick = sample(pack); - logger.info(`GameID: ${this.gameId}, Bot, picked: ${randomPick.name}`); - this.picks.push(randomPick.name); - pull(pack, randomPick); + const card = samplePick(pack, this.pool, this.myColors); + logger.info(`GameID: ${this.gameId}, Bot, picked: ${card.name}`); + this.pool.push(card); + this.picks.push(card.name); + pull(pack, card); }); // burn cards diff --git a/backend/player/index.js b/backend/player/index.js index 03b44ee2..1ccdfbe9 100644 --- a/backend/player/index.js +++ b/backend/player/index.js @@ -24,11 +24,11 @@ class Player extends EventEmitter { picks: [], burns: [] }, - pool: [], + pool: [], // cards you have picks from packs + picks: [], // string names of picked cards cap: { packs: {} }, - picks: [], draftLog: { round : {}, pack: [] diff --git a/package-lock.json b/package-lock.json index 8ce4db00..bf5971f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "jsonfile": "^6.1.0", "lodash": "^4.17.21", "node-schedule": "^2.1.1", + "pile-sort": "^1.0.2", "prop-types": "^15.8.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -3130,9 +3131,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001478", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz", - "integrity": "sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==", + "version": "1.0.30001477", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001477.tgz", + "integrity": "sha512-lZim4iUHhGcy5p+Ri/G7m84hJwncj+Kz7S5aD4hoQfslKZJgt0tHc/hafVbqHC5bbhHb+mrW2JOUHkI5KH7toQ==", "funding": [ { "type": "opencollective", @@ -3772,9 +3773,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.360", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.360.tgz", - "integrity": "sha512-EP/jdF15S+l3iSSzgUpUqeazvkbVFXNuVxwwLMVUSie3lUeH1HH70gKe0IS7TASB/0h5QPG2bLMzv2jelSztIQ==" + "version": "1.4.359", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz", + "integrity": "sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -6915,6 +6916,11 @@ "node": ">=6" } }, + "node_modules/pile-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pile-sort/-/pile-sort-1.0.2.tgz", + "integrity": "sha512-+sNglvYcHB5OHJfTmgmSIUli49LQ7qAZqKIF93cIo5oqV6hggbTNWLThKLOc8KDa0h+DrqhXs296SeCwVXZ+bg==" + }, "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", diff --git a/package.json b/package.json index aa2cadfb..971129cd 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "jsonfile": "^6.1.0", "lodash": "^4.17.21", "node-schedule": "^2.1.1", + "pile-sort": "^1.0.2", "prop-types": "^15.8.1", "react": "^17.0.2", "react-dom": "^17.0.2",