확률로 랜덤하게 아이템 뽑기

Gradle

implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'

 

Maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-math3</artifactId>
    <version>3.6.1</version>
</dependency>

 

Test

public class GachaUnitTest {
  @BeforeAll
  public static void setup() {

  }

  @Test
  @DisplayName("가챠 확률 테스트")
  public void should_GetRandomItem_When_Gacha() {
    List<Pair<String, Double>> items = getItems();
    List<String> itemsName = Lists.newArrayList();

    for (int testCount = 0; testCount < 1000; testCount++) {
      String itemName = getGachaItemName(items);

      boolean containsItem = items
          .stream()
          .anyMatch(stringDoublePair -> stringDoublePair.getKey().equals(itemName));

      assertThat(containsItem, is(true));

      itemsName.add(itemName);
    }

    List<Map<String, List<String>>> sortedItemMap = itemsName
        .stream()
        .collect(Collectors.groupingBy(i -> i))
        .entrySet()
        .stream()
        .sorted(Comparator.comparing(i -> i.getValue().size(), Comparator.reverseOrder()))
        .map(entry -> {
          Map<String, List<String>> map = Maps.newLinkedHashMap();
          map.put(entry.getKey(), entry.getValue());

          return map;
        })
        .toList();

    for (Map<String, List<String>> itemMap : sortedItemMap) {
      for (Map.Entry<String, List<String>> item : itemMap.entrySet()) {
        String key = item.getKey();
        List<String> values = item.getValue();
        int size = values.size();

        System.out.println(key + " - " + size);
      }
    }
  }

  private String getGachaItemName(List<Pair<String, Double>> items) {
    return new EnumeratedDistribution<>(items).sample();
  }

  private List<Pair<String, Double>> getItems() {
    Pair<String, Double> item1 = new Pair<>("item1", 1.5);
    Pair<String, Double> item2 = new Pair<>("item2", 4.1);
    Pair<String, Double> item3 = new Pair<>("item3", 3.7);
    Pair<String, Double> item4 = new Pair<>("item4", 7.3);
    Pair<String, Double> item5 = new Pair<>("item5", 2.0);
    Pair<String, Double> item6 = new Pair<>("item6", 2.8);
    Pair<String, Double> item7 = new Pair<>("item7", 6.9);
    Pair<String, Double> item8 = new Pair<>("item8", 9.0);
    Pair<String, Double> item9 = new Pair<>("item9", 8.8);
    Pair<String, Double> item10 = new Pair<>("item10", 5.2);

    return Lists.newArrayList(item1, item2, item3, item4, item5, item6, item7, item8, item9,
        item10);
  }
}

 

결과

item8 - 184
item9 - 155
item7 - 147
item4 - 124
item10 - 103
item2 - 84
item3 - 64
item6 - 62
item5 - 52
item1 - 25

 

확률이기 때문에 간헐적으로 item9가 더 많이 나올때도 있지만 item8과 그리 많이 차이나지 않는다.

 

사용법

  1. 라이브러리 추가
  2. List<Pair<T, 가중치 Double>> 형태로 된 데이터 준비 (보통은 T를 Entity로 많이 사용할 듯)
  3. new EnumeratedDistribution<>(items).sample();으로 랜덤 아이템 획득