Skip to content

Commit

Permalink
better listing of the dice images (#352)
Browse files Browse the repository at this point in the history
  • Loading branch information
twonirwana authored Nov 1, 2023
1 parent 7eeca45 commit fc31b9b
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 28 deletions.
3 changes: 1 addition & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,7 @@ For the direct rolls it can be configured with the `channel_config` command.
The images will only be shown if the following conditions are met:

* The `answer_format` is set to `full` or `without_expression`
* No set of dice with more than 15 dice
* Not more the 10 sets of dice
* No set of dice with more than 30 dice
* No multi line result

There are the following options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Stopwatch;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.hash.Hashing;
import de.janno.discord.bot.BotMetrics;
import de.janno.evaluator.dice.Roll;
Expand Down Expand Up @@ -36,6 +40,22 @@ public class ImageResultCreator {
private static final String CACHE_FOLDER = "imageCache";
private static final String CACHE_INDEX_FILE = "imageCacheName.csv";
private final BigInteger MAX_ROLL_COMBINATION_TO_CACHE;
private final LoadingCache<Integer, BufferedImage> separatorImage = CacheBuilder.newBuilder()
.maximumSize(10)
.build(new CacheLoader<>() {
@Override
public @NonNull BufferedImage load(@NonNull Integer high) {
BufferedImage combined = new BufferedImage(15, high, BufferedImage.TYPE_INT_ARGB_PRE);

Graphics g = combined.getGraphics();
g.setColor(Color.lightGray);
g.fillRect(1, (high / 2) - 2, 13, 4);
g.setColor(Color.black);
g.drawRect(1, (high / 2) - 2, 13, 4);
g.dispose();
return combined;
}
});

public ImageResultCreator() {
this(1000);
Expand Down Expand Up @@ -101,9 +121,7 @@ String createRollCacheName(Roll roll, DiceStyleAndColor diceStyleAndColor) {
}
if (rolls.size() != 1 ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().isEmpty() ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().size() > 10 ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().stream().anyMatch(r -> r.getRandomElements().size() > 15) ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().stream().anyMatch(r -> r.getRandomElements().isEmpty()) ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().stream().mapToInt(r -> r.getRandomElements().size()).sum() > 30 ||
rolls.get(0).getRandomElementsInRoll().getRandomElements().stream()
.flatMap(r -> r.getRandomElements().stream())
.anyMatch(r -> diceStyleAndColor.getImageFor(r.getMaxInc(), r.getRollElement().asInteger().orElse(null), r.getRollElement().getColor()).isEmpty())
Expand Down Expand Up @@ -136,34 +154,50 @@ String createRollCacheName(Roll roll, DiceStyleAndColor diceStyleAndColor) {
private Supplier<? extends InputStream> createNewFileForRoll(Roll roll, File file, String name, DiceStyleAndColor diceStyleAndColor) {
Stopwatch stopwatch = Stopwatch.createStarted();

List<List<BufferedImage>> images = roll.getRandomElementsInRoll().getRandomElements().stream()
final List<List<BufferedImage>> images = roll.getRandomElementsInRoll().getRandomElements().stream()
.map(r -> r.getRandomElements().stream()
.flatMap(re -> diceStyleAndColor.getImageFor(re.getMaxInc(), re.getRollElement().asInteger().orElse(null), re.getRollElement().getColor()).stream())
.toList()
)
.filter(l -> !l.isEmpty())
.toList();
final int singleDiceSize = diceStyleAndColor.getDieHighAndWith();

BufferedImage separator = separatorImage.getUnchecked(singleDiceSize);
ImmutableList.Builder<BufferedImage> builder = ImmutableList.builder();
for (int i = 0; i < images.size() - 1; i++) {
builder.addAll(images.get(i));
builder.add(separator);
}
builder.addAll(images.get(images.size() - 1));

final List<BufferedImage> imagesWithSeparators = builder.build();

int maxInnerSize = images.stream()
.mapToInt(List::size)
.max().orElseThrow();
final int maxLineWidth = 640;

int singleDiceSize = diceStyleAndColor.getDieHighAndWith();
int w = singleDiceSize * (maxInnerSize);
int h = singleDiceSize * (images.size());
final int allInOneLineWidth = imagesWithSeparators.stream().mapToInt(BufferedImage::getWidth).sum();
final int numberOfImageLines = (int) Math.ceil(((double) allInOneLineWidth) / ((double) maxLineWidth));

final int w = Math.min(allInOneLineWidth, maxLineWidth);
final int h = singleDiceSize * numberOfImageLines;
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);

Graphics g = combined.getGraphics();

for (int i = 0; i < images.size(); i++) {
List<BufferedImage> line = images.get(i);
for (int j = 0; j < line.size(); j++) {
g.drawImage(line.get(j), singleDiceSize * j, singleDiceSize * i, singleDiceSize, singleDiceSize, null);
int currentLine = 0;
int currentLineWidth = 0;
for (BufferedImage image : imagesWithSeparators) {
if (image.getWidth() + currentLineWidth > maxLineWidth) {
currentLine++;
currentLineWidth = image.getWidth();
} else {
currentLineWidth += image.getWidth();
}
g.drawImage(image, currentLineWidth - image.getWidth(), singleDiceSize * currentLine, image.getWidth(), singleDiceSize, null);
}

g.dispose();
String indexPath = "%s/%s/%s".formatted(CACHE_FOLDER, diceStyleAndColor.toString(), CACHE_INDEX_FILE);
final String indexPath = "%s/%s/%s".formatted(CACHE_FOLDER, diceStyleAndColor.toString(), CACHE_INDEX_FILE);
BigInteger combinations = roll.getRandomElementsInRoll().getRandomElements()
.stream().flatMap(r -> r.getRandomElements().stream())
.map(r -> {
Expand All @@ -178,6 +212,7 @@ private Supplier<? extends InputStream> createNewFileForRoll(Roll roll, File fil
)
.map(BigInteger::valueOf)
.reduce(BigInteger.ONE, BigInteger::multiply);

//don't cache images that unlikely to ever get generated again
if (MAX_ROLL_COMBINATION_TO_CACHE.compareTo(combinations) < 0) {
BotMetrics.incrementImageResultMetricCounter(BotMetrics.CacheTag.CACHE_SKIP);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
Expand Down Expand Up @@ -75,15 +76,15 @@ static Stream<Arguments> generateDiceStyleDataPerColor() {
@BeforeEach
void setup() throws IOException {
File cacheDirectory = new File("imageCache/");
if(cacheDirectory.exists()){
if (cacheDirectory.exists()) {
FileUtils.cleanDirectory(cacheDirectory);
}
}

@AfterEach
void cleanUp() throws IOException {
File cacheDirectory = new File("imageCache/");
if(cacheDirectory.exists()){
if (cacheDirectory.exists()) {
FileUtils.cleanDirectory(cacheDirectory);
}
}
Expand Down Expand Up @@ -178,7 +179,7 @@ void getImageForRoll_blackGold() throws ExpressionException, IOException {
Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.polyhedral_alies_v1, "black_and_gold"));

assertThat(res).isNotNull();
assertThat(getDataHash(res)).isEqualTo("704e741a90a7ca38dacd7e571863ab55bb9ae47120d0b16e7278993ac7f33b82");
assertThat(getDataHash(res)).isEqualTo("a2c774609da21cd6982d3fad969a7ec87db430c1cb83cf7dadb61b3374cf5589");
}

@Test
Expand Down Expand Up @@ -271,14 +272,14 @@ void getImageForRoll_noCacheForLargeDiceSets() throws ExpressionException, IOExc
assertThat(res1).isNotNull();
File cacheFolder = new File("imageCache/");
assertThat(cacheFolder).isEmptyDirectory();
assertThat(getDataHash(res1)).isEqualTo("5672d47a89d51f0098bc154b22c72f1ea2059ba8d77a589adca8bd720c7ace2b");
assertThat(getDataHash(res1)).isEqualTo("c6ea9275d2ab8391ff4978a4fd8e3f36fa0ef0ab4dc6fa85074a175e2bd307b0");

List<Roll> rolls2 = new DiceEvaluator(new GivenNumberSupplier(1), 1000).evaluate("7d10");
Supplier<? extends InputStream> res2 = underTest.getImageForRoll(rolls2, new DiceStyleAndColor(DiceImageStyle.polyhedral_3d, "red_and_white"));

assertThat(cacheFolder).isEmptyDirectory();
assertThat(res2).isNotNull();
assertThat(getDataHash(res2)).isEqualTo("5672d47a89d51f0098bc154b22c72f1ea2059ba8d77a589adca8bd720c7ace2b");
assertThat(getDataHash(res2)).isEqualTo("c6ea9275d2ab8391ff4978a4fd8e3f36fa0ef0ab4dc6fa85074a175e2bd307b0");
}

@Test
Expand Down Expand Up @@ -349,7 +350,7 @@ void getImageForRoll_3dRedWhite() throws ExpressionException, IOException {
Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.polyhedral_3d, "red_and_white"));

assertThat(res).isNotNull();
assertThat(getDataHash(res)).isEqualTo("2956ce00e097a7332f6769e37c69c7120074918316102b614758d65486c8cbfb");
assertThat(getDataHash(res)).isEqualTo("5bb342eaacea0ef00fab10901e786a3b5f3b38b287f7c7961b9cf7f117694f6e");
}

@Test
Expand All @@ -369,12 +370,10 @@ void getImageForRoll_d6DotsBlackAndGold() throws ExpressionException, IOExceptio
Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.d6_dots, "black_and_gold"));

assertThat(res).isNotNull();
assertThat(getDataHash(res)).isEqualTo("bd8246680e77103a186bd6eae3cdc230b8847c92ff55fffdef1f3fbb74aed45c");
assertThat(getDataHash(res)).isEqualTo("d2cbedfb456d593a51fd5339c95b802ef1dc6157279083e4f9e947b86744226f");
}




@Test
void getImageForRoll_noDie_3dRedWhite() throws ExpressionException {
List<Roll> rolls = new DiceEvaluator(new GivenNumberSupplier(), 1000).evaluate("5");
Expand Down Expand Up @@ -491,15 +490,28 @@ void getImageForRoll_polyhedral_RdD() throws ExpressionException, IOException {
Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.polyhedral_RdD, DiceImageStyle.polyhedral_RdD.getDefaultColor()));

assertThat(res).isNotNull();
assertThat(getDataHash(res)).isEqualTo("de01222cf4ea85e2fe2eea6539ebdfe9809bfe88f6dfb8ece5736df9eeb6603d");
assertThat(getDataHash(res)).isEqualTo("134795311673058eac57eaeecb83010b9323b0f9056bd8d80af3355d81d3e674");
}

@Test
void getImageForRoll_polyhedral_RdD_specialColor() throws ExpressionException {
List<Roll> rolls = new DiceEvaluator(new GivenNumberSupplier( 99), 1000).evaluate("1d100");
List<Roll> rolls = new DiceEvaluator(new GivenNumberSupplier(99), 1000).evaluate("1d100");

Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.polyhedral_RdD, "special"));

assertThat(res).isNull();
}

@Test
@Disabled
void debug() throws ExpressionException, IOException {
List<Roll> rolls = new DiceEvaluator(new GivenNumberSupplier(4, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 20, 99, 8, 12), 1000).evaluate("1d4 + 6d6 + 1d7 + 1d8 + 1d10 +1d12 + 1d20 + 1d100 + 1d8 col 'special' + 1d12 col 'special'");

Supplier<? extends InputStream> res = underTest.getImageForRoll(rolls, new DiceStyleAndColor(DiceImageStyle.polyhedral_RdD, DiceImageStyle.polyhedral_RdD.getDefaultColor()));


File out = new File("out.png");
assertThat(res).isNotNull();
FileUtils.copyInputStreamToFile(res.get(), out);
}
}

0 comments on commit fc31b9b

Please sign in to comment.