Skip to content

Instantly share code, notes, and snippets.

@gerardpaapu
Created February 26, 2019 20:49
Show Gist options
  • Save gerardpaapu/456e9dab7f7c97e4b7cde96adf5da6b7 to your computer and use it in GitHub Desktop.
Save gerardpaapu/456e9dab7f7c97e4b7cde96adf5da6b7 to your computer and use it in GitHub Desktop.
/*
The deck is:
4 Chancellor
0-4 Serum Powder
11 Fetch Spell (a one mana green sorcery that can fetch a basic)
4 Renegade Map
2 Forest
1 Mountain
34-38 Other
Our goal is to keep a hand that can hit two land-drops (and hopefully with our first
2-3 draws we can get the next one), so this is the algorithm:
Keep all hands:
- with at least one chancellor and at least two fetch spells
- with at least one chancellor, at least one fetch spell and at least one map
- with at least one forest and at least one fetcher
- with at least one land and at least one map
- with 2 or fewer cards
Exile all hands:
- with Serum Powder, no lands and no chancellor
Otherwise mulligan.
*/
const assert = require('assert');
const counts = arr => {
const result = Object.create(null);
for (const item of arr) {
result[item] = result[item] || 0;
result[item]++;
}
return result;
};
const copies = (n, s) => {
const result = [];
while (result.length < n) result.push(s);
return result;
};
const want_to_keep = hand => {
const c = counts(hand);
return (
(c['Chancellor of the Tangle'] && c['Fetch Spell'] > 1) ||
(c['Chancellor of the Tangle'] && c['Fetch Spell'] && c['Map']) ||
(c['Forest'] && c['Fetch Spell']) ||
(c['Forest'] && c['Map']) ||
(c['Mountain'] && c['Map'])
);
};
const want_to_exile = hand => {
const c = counts(hand);
return (
c['Serum Powder'] &&
!c['Forest'] &&
!c['Mountain'] &&
!c['Chancellor of the Tangle']
);
};
const serum_powder_4 = [
'Forest',
'Forest',
'Mountain',
...copies(4, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(11, 'Fetch Spell'),
...copies(34, 'Other')
];
const serum_powder_3 = [
'Forest',
'Forest',
'Mountain',
...copies(3, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(11, 'Fetch Spell'),
...copies(35, 'Other')
];
const serum_powder_2 = [
'Forest',
'Forest',
'Mountain',
...copies(2, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(11, 'Fetch Spell'),
...copies(36, 'Other')
];
const serum_powder_1 = [
'Forest',
'Forest',
'Mountain',
...copies(1, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(11, 'Fetch Spell'),
...copies(37, 'Other')
];
const serum_powder_0 = [
'Forest',
'Forest',
'Mountain',
...copies(0, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(11, 'Fetch Spell'),
...copies(38, 'Other')
];
const serum_powder_0_more_fetch = [
'Forest',
'Forest',
'Mountain',
...copies(0, 'Serum Powder'),
...copies(4, 'Map'),
...copies(4, 'Chancellor of the Tangle'),
...copies(15, 'Fetch Spell'),
...copies(34, 'Other')
];
const shuffle = arr => {
let i = arr.length;
while (i--) {
const j = (Math.random() * (i + 1)) | 0;
const tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
};
const draw_hand = (library, n) => {
shuffle(library);
return library.slice(0, n);
};
const run_for_deck = deck => {
let stats = [0, 0, 0, 0, 0, 0, 0, 0];
for (let i = 0; i < 100000; i++) {
let library = deck.slice();
assert.equal(library.length, 60);
let hand_size = 7;
let hand;
while (hand_size > 2) {
hand = draw_hand(library, hand_size);
if (want_to_keep(hand)) {
break;
}
if (want_to_exile(hand)) {
library = library.slice(hand_size);
// console.log(`Exiling: ${hand}`);
continue;
}
// mulligan;
hand_size--;
// console.log(`Mulling to ${hand_size}`);
}
// Our virtual hand size is the number of cards we kept that are not
// Serum Powder.
const virtual_hand_size = hand.filter(_ => _ !== 'Serum Powder').length;
// We're tracking how many hands of "at least" n we kept so we need
// to increment every slot below `virtual_hand_size`.
for (let i = virtual_hand_size; i >= 0; i--) {
stats[i]++;
}
// console.log(`Kept (${hand_size}): ${hand.join(', ')}`);
}
const percents = stats.map(n => n / 1000);
console.log(percents.join('\t'));
};
run_for_deck(serum_powder_4);
run_for_deck(serum_powder_3);
run_for_deck(serum_powder_2);
run_for_deck(serum_powder_1);
run_for_deck(serum_powder_0);
run_for_deck(serum_powder_0_more_fetch);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment