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

fixed difficulty distribution #18

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ private static int startGame(CommandContext<CommandSourceStack> context) throws
try {
board = BingoBoard.generate(
size,
difficulty.difficulty().number(),
difficulty.difficulty(),
teams.size(),
RandomSource.create(seed),
gamemode::isGoalAllowed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.gaming32.bingo.Bingo;
import io.github.gaming32.bingo.util.ResourceLocations;
import it.unimi.dsi.fastutil.floats.FloatList;
import net.minecraft.core.HolderLookup;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.RegistryOps;
Expand All @@ -29,20 +30,22 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.List;

public record BingoDifficulty(int number, @Nullable String fallbackName) {
public record BingoDifficulty(int number, @Nullable String fallbackName, @Nullable List<Float> distribution) {
public static final Codec<BingoDifficulty> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
ExtraCodecs.NON_NEGATIVE_INT.fieldOf("number").forGetter(BingoDifficulty::number),
Codec.STRING.optionalFieldOf("fallback_name").forGetter(d -> Optional.ofNullable(d.fallbackName))
Codec.STRING.optionalFieldOf("fallback_name").forGetter(d -> Optional.ofNullable(d.fallbackName)),
Codec.FLOAT.listOf().optionalFieldOf("distribution").forGetter(dist -> Optional.ofNullable(dist.distribution))
).apply(instance, BingoDifficulty::new)
);

private static Map<ResourceLocation, Holder> byId = Map.of();
private static NavigableMap<Integer, Holder> byNumber = ImmutableSortedMap.of();

private BingoDifficulty(int number, Optional<String> fallbackName) {
this(number, fallbackName.orElse(null));
private BingoDifficulty(int number, Optional<String> fallbackName, Optional<List<Float>> distribution) {
this(number, fallbackName.orElse(null), distribution.orElse(null));
}

public static Builder builder(ResourceLocation id) {
Expand Down Expand Up @@ -96,6 +99,7 @@ public static final class Builder {
private final ResourceLocation id;
private Integer number;
private String fallbackName;
private List<Float> distribution;

private Builder(ResourceLocation id) {
this.id = id;
Expand All @@ -111,10 +115,24 @@ public Builder fallbackName(String name) {
return this;
}

public Builder distribution(int... scaledBy5x5) {
final float[] unscaled = new float[scaledBy5x5.length];
for (int i = 0; i < scaledBy5x5.length; i++) {
unscaled[i] = scaledBy5x5[i] / 25f;
}
return this.distribution(unscaled);
}

public Builder distribution(float... unscaledDistribution) {
this.distribution = FloatList.of(unscaledDistribution);
return this;
}

public Holder build() {
return new Holder(id, new BingoDifficulty(
Objects.requireNonNull(number, "number"),
fallbackName
fallbackName,
distribution
));
}

Expand Down
61 changes: 40 additions & 21 deletions common/src/main/java/io/github/gaming32/bingo/game/BingoBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private static BingoBoard create(int size, Teams[] states, ActiveGoal[] goals) {

public static BingoBoard generate(
int size,
int difficulty,
BingoDifficulty difficulty,
int teamCount,
RandomSource rand,
Predicate<BingoGoal.Holder> isAllowedGoal,
Expand Down Expand Up @@ -108,7 +108,7 @@ public static BingoBoard generate(

public static BingoGoal.Holder[] generateGoals(
int size,
int difficulty,
BingoDifficulty difficulty,
RandomSource rand,
Predicate<BingoGoal.Holder> isAllowedGoal,
List<BingoGoal.Holder> requiredGoals,
Expand All @@ -129,7 +129,7 @@ public static BingoGoal.Holder[] generateGoals(
final Set<String> catalysts = new HashSet<>();

for (final BingoTag.Holder tag : excludedTags) {
tagCount.put(tag.id(), tag.tag().getMaxForDifficulty(difficulty, size));
tagCount.put(tag.id(), tag.tag().getMaxForDifficulty(difficulty.number(), size));
}

for (int i = 0; i < size * size; i++) {
Expand Down Expand Up @@ -186,7 +186,7 @@ public static BingoGoal.Holder[] generateGoals(

if (!goalCandidate.goal().getTags().isEmpty()) {
for (final BingoTag.Holder tag : goalCandidate.goal().getTags()) {
if (tagCount.getInt(tag.id()) >= tag.tag().getMaxForDifficulty(difficulty, size)) {
if (tagCount.getInt(tag.id()) >= tag.tag().getMaxForDifficulty(difficulty.number(), size)) {
continue goalGen;
}
}
Expand Down Expand Up @@ -265,25 +265,44 @@ private static boolean isOnSameLine(int size, int a, int b) {
return false;
}

private static int[] generateDifficulty(int size, int difficulty, RandomSource rand) {
private static int[] generateDifficulty(int size, BingoDifficulty difficulty, RandomSource rand) {
final int[] layout = new int[size * size];

final Iterator<Integer> available = BingoDifficulty.getNumbers()
.headSet(difficulty, true)
.descendingIterator();
if (!available.hasNext()) {
throw new IllegalArgumentException("No difficulty exists with number " + difficulty);
}
final int difficulty1 = available.next();
if (!available.hasNext()) {
Arrays.fill(layout, difficulty1);
if (difficulty.distribution() != null) {
Arrays.fill(layout, difficulty.number());
float[] cumDistribution = new float[difficulty.distribution().size()];
for (int d = 0; d < cumDistribution.length; d++) {
cumDistribution[d] = difficulty.distribution().get(d) * layout.length;
if (d > 0) {
cumDistribution[d] += cumDistribution[d - 1];
}
}
for (int i = 0; i < layout.length; ++i) {
for (int d = 0; d < cumDistribution.length; d++) {
if ((i + 1) <= cumDistribution[d]) {
layout[i] = d;
break;
}
}
}
BingoUtil.shuffle(layout, rand);
} else {
final int difficulty2 = available.next();
final int amountOf1 = rand.nextInt(size * size * 3 / 5, size * size * 3 / 5 + size);
final int[] indices = BingoUtil.shuffle(BingoUtil.generateIntArray(size * size), rand);
Arrays.fill(layout, difficulty2);
for (int i = 0; i < amountOf1; i++) {
layout[indices[i]] = difficulty1;
final Iterator<Integer> available = BingoDifficulty.getNumbers()
.headSet(difficulty.number(), true)
.descendingIterator();
if (!available.hasNext()) {
throw new IllegalArgumentException("No difficulty exists with number " + difficulty);
}
final int difficulty1 = available.next();
if (!available.hasNext()) {
Arrays.fill(layout, difficulty1);
} else {
final int difficulty2 = available.next();
final int amountOf1 = rand.nextInt(size * size * 3 / 5, size * size * 3 / 5 + size);
final int[] indices = BingoUtil.shuffle(BingoUtil.generateIntArray(size * size), rand);
Arrays.fill(layout, difficulty2);
for (int i = 0; i < amountOf1; i++) {
layout[indices[i]] = difficulty1;
}
}
}
return layout;
Expand Down