Skip to content

Instantly share code, notes, and snippets.

@gintenlabo
Created September 9, 2024 16:06
Show Gist options
  • Save gintenlabo/c08197ce3bf074dc816338e0c790823d to your computer and use it in GitHub Desktop.
Save gintenlabo/c08197ce3bf074dc816338e0c790823d to your computer and use it in GitHub Desktop.
スタンのグルール果敢における最適な境界ランドの採用枚数を計算するスクリプト
const getRandomInt = (min: number, max: number): number => {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
};
const sample = <T>(n: number, arr: readonly T[]): T[] => {
const result = [...arr];
const len = result.length;
for (let i = 0; i < n; i += 1) {
if (i >= len) {
break;
}
const j = getRandomInt(i, len);
[result[i], result[j]] = [result[j], result[i]];
}
if (result.length > n) {
result.length = n;
}
return result;
};
const cardTypes = [
'spell',
'multiLand',
'valueLand',
'basicLand',
'vergeLand',
] as const;
type CardType = (typeof cardTypes)[number];
const inspectResults = ['ok', 'bad', 'screw', 'flood'];
type InspectResult = (typeof inspectResults)[number];
const inspectHand = (hand: CardType[]): InspectResult => {
let multi = 0;
let value = 0;
let basic = 0;
let verge = 0;
hand.forEach((card) => {
switch (card) {
case 'multiLand':
multi += 1;
break;
case 'valueLand':
value += 1;
break;
case 'basicLand':
basic += 1;
break;
case 'vergeLand':
verge += 1;
break
default:
break;
}
});
const lands = multi + value + basic + verge;
if (lands <= 1) {
return 'screw';
} else if (lands >= 5) {
return 'flood';
} else if (multi >= 1) {
return 'ok';
} else if (basic >= 1 && verge >= 1) {
return 'ok';
}
return 'bad';
}
const cardsInDeck = 60;
const spells = 39;
const multiLands = 8;
const valueLands = 2;
const replicate = <T>(n: number, x: T): T[] =>
Array.from({ length: n }, () => x)
const main = () => {
for (let vergeLands = 0; vergeLands <= 4; vergeLands += 1) {
const basicLands = cardsInDeck - spells - multiLands - valueLands - vergeLands;
console.log('basic lands:', basicLands);
console.log('verge lands:', vergeLands);
const deck: CardType[] = [
...replicate(spells, 'spell'),
...replicate(multiLands, 'multiLand'),
...replicate(valueLands, 'valueLand'),
...replicate(basicLands, 'basicLand'),
...replicate(vergeLands, 'vergeLand'),
];
const results: Record<InspectResult, number> = Object.fromEntries(
inspectResults.map((result) => [result, 0]),
);
const trials = 10000000;
for (let i = 0; i < trials; ++i) {
const result = inspectHand(sample(7, deck));
results[result] += 1;
}
console.log(`results (${trials} trials):`);
inspectResults.forEach((result) => {
console.log(`${result}:`, results[result] / trials);
});
console.log('');
}
};
main();
@gintenlabo
Copy link
Author

結果の一例:

basic lands: 11
verge lands: 0
results (10000000 trials):
ok: 0.5435565
bad: 0.194224
screw: 0.2174485
flood: 0.044771

basic lands: 10
verge lands: 1
results (10000000 trials):
ok: 0.5776958
bad: 0.1604605
screw: 0.2170057
flood: 0.044838

basic lands: 9
verge lands: 2
results (10000000 trials):
ok: 0.6047591
bad: 0.133299
screw: 0.2171137
flood: 0.0448282

basic lands: 8
verge lands: 3
results (10000000 trials):
ok: 0.6249837
bad: 0.1130775
screw: 0.2171119
flood: 0.0448269

basic lands: 7
verge lands: 4
results (10000000 trials):
ok: 0.6377226
bad: 0.1001455
screw: 0.2173297
flood: 0.0448022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment