Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoiding drawing a new card from an era that will fail the tooClose check #121

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 55 additions & 4 deletions lib/items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ export function getRandomItem(deck: Item[], played: Item[]): Item {
[1000, 1800],
[1800, 2020],
];
const validPeriods = periods.filter(
([fromYear, toYear]) => !checkPeriodWillFail(played, fromYear, toYear)
);
const [fromYear, toYear] =
periods[Math.floor(Math.random() * periods.length)];
validPeriods[Math.floor(Math.random() * validPeriods.length)];
const avoidPeople = Math.random() > 0.5;
const candidates = deck.filter((candidate) => {
if (avoidPeople && candidate.instance_of.includes("human")) {
Expand All @@ -29,10 +32,58 @@ export function getRandomItem(deck: Item[], played: Item[]): Item {
return deck[Math.floor(Math.random() * deck.length)];
}

function tooClose(item: Item, played: Item[]) {
function getIdealDistance(played: Item[]) {
return 110 - 10 * played.length;
}

/**
* This function checks that the played cards won't cause tooClose to return
* true for all years in a period (possible for 1800-2020)
*/
function checkPeriodWillFail(
played: Item[],
fromYear: number,
toYear: number,
): boolean {
if (played.length > 11 || played.length === 0) {
return false;
}

const distance = getIdealDistance(played);

const playedYears = played.map(({ year }) => year).sort();
const interestingYears = playedYears.filter((year) =>
fromYear - distance < year && year < toYear + distance
);

if (interestingYears.length === 0) {
return false;
}

// If there is room at either end of the period, then we can proceed safely.
if (interestingYears[0] - fromYear >= distance) {
return false;
}

if (toYear - interestingYears[-1] >= distance) {
return false;
}

// If there is room in between cards, we can proceed safely.
for (let i = 0; i < interestingYears.length - 1; i++) {
if (interestingYears[i+1] - interestingYears[i] >= 2 * distance) {
return false;
}
}

return true;
}

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

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