Skip to content

Commit

Permalink
Merge pull request #11 from nekooftheabyss/dev
Browse files Browse the repository at this point in the history
microoptimization
  • Loading branch information
retraigo authored Aug 4, 2022
2 parents 42cfde0 + d1a3ee3 commit 1e32ee5
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"deno.enable": true
"deno.enable": true,
"deno.unstable": true
}
2 changes: 1 addition & 1 deletion failures/roll1.ts → algorithms/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { GachaChoice } from "../mod.ts";
export function roll<ItemType>(
choices: GachaChoice<ItemType>[],
): GachaChoice<ItemType> {
let filteredChoices = [];
const filteredChoices = [];
for (let i = 0; i < choices.length; ++i) {
for (let chance = choices[i].chance; chance > 0.0; --chance) {
filteredChoices.push(i);
Expand Down
4 changes: 2 additions & 2 deletions failures/roll2.ts → algorithms/v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import type { GachaChoice } from "../mod.ts";
export function roll<ItemType>(
choices: GachaChoice<ItemType>[],
): GachaChoice<ItemType> {
let filteredChoices = choices;
const filteredChoices = [];
let total = 0.0;
for (let i = 0; i < choices.length; ++i) {
if (choices[i].chance > 0.0) {
filteredChoices.push(choices[i]);
total += choices[i].chance;
}
}
let result = Math.random() * total;
const result = Math.random() * total;
let going = 0.0;
for (let i = 0; i < filteredChoices.length; ++i) {
going += filteredChoices[i].chance;
Expand Down
24 changes: 24 additions & 0 deletions algorithms/v3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { GachaChoice } from "../mod.ts";

/**
* Roll one from an array of gacha choices.
* @param {GachaChoice[]} choices - Choices to roll from.
* @returns {GachaChoice} Items rolled.
*/
export function roll<ItemType>(
choices: GachaChoice<ItemType>[],
): GachaChoice<ItemType> {
const total = choices.reduce(
(acc: number, val: GachaChoice<ItemType>) => acc + val.chance,
0,
);
const result = Math.random() * total;
let going = 0.0;
for (let i = 0; i < choices.length; ++i) {
going += choices[i].chance;
if (result < going) {
return choices[i];
}
}
return choices[Math.floor(Math.random() * choices.length)];
}
28 changes: 28 additions & 0 deletions algorithms/v4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { GachaChoice } from "../mod.ts";

/**
* Roll one from an array of gacha choices.
* @param {GachaChoice[]} choices - Choices to roll from.
* @returns {GachaChoice} Items rolled.
*/
export function roll<ItemType>(
choices: GachaChoice<ItemType>[],
): GachaChoice<ItemType> {
let total = 0;
let i = 0;
while (i < choices.length) {
total += choices[i].chance;
i += 1;
}
const result = Math.random() * total;
let going = 0.0;
i = 0;
while (i < choices.length) {
going += choices[i].chance;
if (result < going) {
return choices[i];
}
i += 1;
}
return choices[Math.floor(Math.random() * choices.length)];
}
29 changes: 29 additions & 0 deletions algorithms/v4_sub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { GachaChoice } from "../mod.ts";

// Dropped before release since it was slightly faster than v4.

/**
* Roll one from an array of gacha choices.
* @param {GachaChoice[]} choices - Choices to roll from.
* @returns {GachaChoice} Items rolled.
*/
export function roll<ItemType>(
choices: GachaChoice<ItemType>[],
): GachaChoice<ItemType> {
let total = 0;
let i = 0;
while (i < choices.length) {
total += choices[i].chance;
i += 1;
}
const result = Math.random() * total;
i -= 1;
while (i > -1) {
total -= choices[i].chance;
if (result > total) {
return choices[i];
}
i -= 1;
}
return choices[Math.floor(Math.random() * choices.length)];
}
51 changes: 51 additions & 0 deletions benches/100k_rolls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { roll as roll1 } from "../algorithms/v1.ts";
import { roll as roll2 } from "../algorithms/v2.ts";
import { roll as roll3 } from "../algorithms/v3.ts";
import { roll as roll4 } from "../algorithms/v4.ts";
import { roll as roll4_sub } from "../algorithms/v4_sub.ts";
import { GachaMachine } from "../mod.ts";

import pokemon from "../testdata/pokemon.json" assert { type: "json" };

const items = pokemon.slice(0, 151).map((x) => ({
result: x.id,
chance: x.tier === "legendary" ? 11 : x.tier === "mythic" ? 1 : 25,
}));

Deno.bench("nop", () => {});

Deno.bench("Algorithm V1", () => {
for (let i = 0; i < 1e6; ++i) {
roll1(items);
}
});

Deno.bench("Algorithm V2", () => {
for (let i = 0; i < 1e6; ++i) {
roll2(items);
}
});

Deno.bench("Algorithm V3", () => {
for (let i = 0; i < 1e6; ++i) {
roll3(items);
}
});

Deno.bench("Algorithm V4 _ Sub", () => {
for (let i = 0; i < 1e6; ++i) {
roll4_sub(items);
}
});

Deno.bench("Algorithm V4", () => {
for (let i = 0; i < 1e6; ++i) {
roll4(items);
}
});

Deno.bench("Algorithm V4 in Fortuna", () => {
for (let i = 0; i < 1e6; ++i) {
GachaMachine.roll(items);
}
});
51 changes: 51 additions & 0 deletions benches/1_roll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { roll as roll1 } from "../algorithms/v1.ts";
import { roll as roll2 } from "../algorithms/v2.ts";
import { roll as roll3 } from "../algorithms/v3.ts";
import { roll as roll4 } from "../algorithms/v4.ts";
import { roll as roll4_sub } from "../algorithms/v4_sub.ts";
import { GachaMachine } from "../mod.ts";

import pokemon from "../testdata/pokemon.json" assert { type: "json" };

const items = pokemon.slice(0, 151).map((x) => ({
result: x.id,
chance: x.tier === "legendary" ? 11 : x.tier === "mythic" ? 1 : 25,
}));

Deno.bench("nop", () => {});

Deno.bench("Algorithm V1", () => {
for (let i = 0; i < 1e2; ++i) {
roll1(items);
}
});

Deno.bench("Algorithm V2", () => {
for (let i = 0; i < 1e2; ++i) {
roll2(items);
}
});

Deno.bench("Algorithm V3", () => {
for (let i = 0; i < 1e2; ++i) {
roll3(items);
}
});

Deno.bench("Algorithm V4 _ Sub", () => {
for (let i = 0; i < 1e2; ++i) {
roll4_sub(items);
}
});

Deno.bench("Algorithm V4", () => {
for (let i = 0; i < 1e2; ++i) {
roll4(items);
}
});

Deno.bench("Algorithm V4 in Fortuna", () => {
for (let i = 0; i < 1e2; ++i) {
GachaMachine.roll(items);
}
});
6 changes: 6 additions & 0 deletions deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"tasks": {
"bench": "deno bench --unstable benches/100k_rolls.ts",
"test": "deno run --allow-hrtime test.ts"
}
}
31 changes: 17 additions & 14 deletions mod.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class GachaMachine {
return Array.from(this.items.reduce((acc, val)=>acc.add(val.tier), new Set()).entries()).map((x)=>x[0]);
}
configItems(items) {
let newItems = items = items.sort((a, b)=>a.tier - b.tier).map((x)=>({
const newItems = items = items.sort((a, b)=>a.tier - b.tier).map((x)=>({
chance: x.chance,
result: x.result,
tier: x.tier
}));
this.items = newItems;
}
configTiers(items) {
let tiers = [];
const tiers = [];
const pool = this.pool;
for(let i = 0; i < pool.length; ++i){
tiers[pool[i]] = {
Expand All @@ -37,44 +37,47 @@ class GachaMachine {
tiers[items[i1 - 1].tier].items += 1;
tiers[items[i1 - 1].tier].chance += items[i1 - 1].chance;
}
let tierList = [];
for(let i2 in tiers){
tierList.push(tiers[i2]);
}
this.tiers = tierList;
this.tiers = tiers;
}
get(num = 1, detailed = false, pool = this.pool) {
if (detailed) {
let result = [];
const result = [];
for(let i = num; i > 0; --i){
result.push(this.choose(pool, detailed));
}
return result;
} else {
let result1 = [];
const result1 = [];
for(let i1 = num; i1 > 0; --i1){
result1.push(this.choose(pool));
}
return result1;
}
}
choose(pool = this.pool, detailed) {
let tier = GachaMachine.roll(this.tiers.filter((x)=>pool.includes(x.tier)).map((x)=>({
const tier = GachaMachine.roll(this.tiers.filter((x)=>pool.includes(x.tier)).map((x)=>({
chance: x.chance,
result: x.tier
})));
const result = GachaMachine.roll(this.items.filter((x)=>x.tier == tier.result));
return detailed ? result : result.result;
}
static roll(choices) {
const total = choices.reduce((acc, val)=>acc + val.chance, 0);
let result = Math.random() * total;
static roll(choices, totalChance) {
let total = totalChance || 0;
let i = 0;
while(i < choices.length){
total += choices[i].chance;
i += 1;
}
const result = Math.random() * total;
let going = 0.0;
for(let i = 0; i < choices.length; ++i){
i = 0;
while(i < choices.length){
going += choices[i].chance;
if (result < going) {
return choices[i];
}
i += 1;
}
return choices[Math.floor(Math.random() * choices.length)];
}
Expand Down
14 changes: 9 additions & 5 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,21 @@ export class GachaMachine<ItemType> {
choices: GachaChoice<ItemType>[],
totalChance?: number,
): GachaChoice<ItemType> {
const total = totalChance || choices.reduce(
(acc: number, val: GachaChoice<ItemType>) => acc + val.chance,
0,
);
let total = totalChance || 0;
let i = 0;
while (i < choices.length) {
total += choices[i].chance;
i += 1;
}
const result = Math.random() * total;
let going = 0.0;
for (let i = 0; i < choices.length; ++i) {
i = 0;
while (i < choices.length) {
going += choices[i].chance;
if (result < going) {
return choices[i];
}
i += 1;
}
return choices[Math.floor(Math.random() * choices.length)];
}
Expand Down
2 changes: 2 additions & 0 deletions test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const items = pokemon.slice(0, 151).map((x) => ({
weight: x.tier === "legendary" ? 10 : x.tier === "mythic" ? 1 : 25,
}));


const timeConfig = performance.now();

const machine = new GachaMachine(items);
Expand Down Expand Up @@ -91,3 +92,4 @@ console.log(
["s", "ms", "us", "ns"],
),
);
// console.log(items.map(x => `GachaChoice {${JSON.stringify(x)}}`).join(",\n"))

0 comments on commit 1e32ee5

Please sign in to comment.