Ultimately, I give credit to WolfiaBot for it's implementation in Java for guiding me towards a solution. But I diverge from it's logic by allowing the roles themselves to decide how much they should allocate based on the values provided to them.
- A new
Detective is added every 5 players, after at least 5 players are in game (not including said players).
- A new
Werewolf is added every 4 players.
- The remaining role slots are handed to
Villager
... and the program ends once it logs the role distribution of 1, 2 and 7 respectively.
It is theortically possible to implement this logic into the ratios by having the same failover, and I have no idea how the literal role allocation differs from ratio allocation... likely the same if it's using the same equations. It may also be possible to continue this by allowing multiple greedy roles before it terminates (removing the need for a break, but also offsetting the remaining allocation of roles to the end) - and requiring some sort of distribution code (literal split / round robin / or another ratio).
Role#getChosenRole() is currently set as a placeholder method returning name, but could serve as a role group or wildcard (when extended from Role for both).
Code Source
https://github.com/wolfiabot/Wolfia/blob/5e84f31e/src/main/java/space/npstr/wolfia/game/mafia/MafiaInfo.java#L89
https://github.com/wolfiabot/Wolfia/blob/5e84f31e/src/main/java/space/npstr/wolfia/game/CharakterSetup.java#L30
class Role {
constructor(name, each, min = 1, afterMin = false) {
this.name = name;
this.each = each;
this.min = min;
this.afterMin = afterMin;
}
// future
getChosenRole() {
return this.name;
}
quantityFrom(playerCount) {
// Take any remaining role slots
if (this.each <= 0) return Infinity;
if (playerCount < this.min) return 0;
// ⌊ ({count} - {reset?min:0}) / {each} ⌋
return Math.floor((playerCount - (this.afterMin ? this.min : 0)) / this.each);
}
}
const roles = [
new Role("Detective", 5, 5, true),
new Role("Villager", 0),
new Role("Werewolf", 4),
]
.filter((_, index, array) => array.findIndex((r, i) => r.each === 0 && index === i))
.sort((a, b) => b.each - a.each);
function getRoleCounts(playerCount) {
const result = {};
let remaining = playerCount;
for (const role of roles) {
const count = role.quantityFrom(playerCount);
if (count === 0) continue;
else if (count === Infinity) {
result[role.name] = remaining;
console.log("Found %s, it will take all remaining slots", role.name);
break;
}
else {
result[role.name] = count;
remaining -= count;
}
}
return result;
}
console.log(getRoleCounts(10));
Ultimately, I give credit to WolfiaBot for it's implementation in Java for guiding me towards a solution. But I diverge from it's logic by allowing the roles themselves to decide how much they should allocate based on the values provided to them.
Detectiveis added every 5 players, after at least 5 players are in game (not including said players).Werewolfis added every 4 players.Villager... and the program ends once it logs the role distribution of 1, 2 and 7 respectively.
It is theortically possible to implement this logic into the ratios by having the same failover, and I have no idea how the literal role allocation differs from ratio allocation... likely the same if it's using the same equations. It may also be possible to continue this by allowing multiple greedy roles before it terminates (removing the need for a break, but also offsetting the remaining allocation of roles to the end) - and requiring some sort of distribution code (literal split / round robin / or another ratio).
Code Source
https://github.com/wolfiabot/Wolfia/blob/5e84f31e/src/main/java/space/npstr/wolfia/game/mafia/MafiaInfo.java#L89
https://github.com/wolfiabot/Wolfia/blob/5e84f31e/src/main/java/space/npstr/wolfia/game/CharakterSetup.java#L30