Created
February 26, 2019 20:49
-
-
Save gerardpaapu/456e9dab7f7c97e4b7cde96adf5da6b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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