Skip to content

Commit

Permalink
Prevent falling back to a random card except in very rare circumstances
Browse files Browse the repository at this point in the history
As pointed out in
#121, it was previously possible for duplicate years or even duplicate cards to be drawn because we'd fall back to the random card choice too often. This was because the tooClose function could return true too easily for certain circumstances.

This makes it so tooClose is slightly less strict, but also only applies that function as a second pass, meaning we should fall back to a set of relevant cards instead of the whole deck.
  • Loading branch information
tom-james-watson committed Jul 1, 2024
1 parent 3c065bd commit c05b4d6
Showing 1 changed file with 17 additions and 12 deletions.
29 changes: 17 additions & 12 deletions lib/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,34 @@ export function getRandomItem(deck: Item[], played: Item[]): Item {
const [fromYear, toYear] =
periods[Math.floor(Math.random() * periods.length)];
const avoidPeople = Math.random() > 0.5;

const candidates = deck.filter((candidate) => {
if (avoidPeople && candidate.instance_of.includes("human")) {
return false;
}
if (candidate.year < fromYear || candidate.year > toYear) {
return false;
}
if (tooClose(candidate, played)) {
return false;
}
if (avoidPeople && candidate.instance_of.includes("human")) return false;
if (candidate.year <= fromYear || candidate.year >= toYear) return false;
if (played.some((p) => p.year === candidate.year)) return false;
return true;
});

const betterCandidates = candidates.filter(
(candidate) => !tooClose(candidate, played)
);

if (betterCandidates.length > 0) {
return betterCandidates[
Math.floor(Math.random() * betterCandidates.length)
];
}

if (candidates.length > 0) {
return candidates[Math.floor(Math.random() * candidates.length)];
}

return deck[Math.floor(Math.random() * deck.length)];
}

function tooClose(item: Item, played: Item[]) {
let distance = (played.length < 40) ? 5 : 1;
if (played.length < 11)
distance = 110 - 10 * played.length;
let distance = played.length < 40 ? 5 : 1;
if (played.length < 11) distance = 55 - 5 * played.length;

return played.some((p) => Math.abs(item.year - p.year) < distance);
}
Expand Down

0 comments on commit c05b4d6

Please sign in to comment.