Last active
November 17, 2025 21:21
-
-
Save tnn4/bc827ae481fe81f4645fca4cead156ea to your computer and use it in GitHub Desktop.
how many pulls before you get kitasan black?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>How much $ Before I get Kitasan Black?</title> | |
| <script src="index.js" defer></script> | |
| </head> | |
| <body> | |
| <h1>How much money do I have to spend before I get Kitasan Black as of 11/17/25?</h1> | |
| A friend of mine recently recommended that I try out the gacha game that was all the rage in Japan Uma Musume. | |
| It was popular enough to generate about a billion dollars in revenue in 2021 alone. | |
| It's literally about gambling to get anime horse girls. | |
| One of the best horse girls Kitasan Black is notoriously difficult to obtain because she is SSR rare (whatever that means) and the chance to pull her is only 0.04% which translates to an expected value of 2500 (1/0.0004) pulls to get her once. | |
| Considering each pull costs 300 yen (about $2.25), you would expect to spend about 750,000 yen (about $5,625) to get Kitasan Black in Japan. | |
| The game was released in the US recently, and the rates are the similar. | |
| However, the game offers various discounts and bonuses for buying in bulk. | |
| For example, buying 10 pulls at once gives you a almost guaranteed SR (not SSR) character on the tenth pull at 97% and a SSR at 3%. | |
| In the US 5000 karats costs $69.99 and considering that 10 bulk pulls cost 1500 karats, that means 10 pulls cost about $21. | |
| Therefore, the expected cost to get Kitasan Black in the US is about $11,250 if you do not choose to re-roll. | |
| This is quite a bit more expensive than in Japan, but I that's to be expected given the different pricing strategies in different markets. | |
| Overall, if you're thinking about trying to get Kitasan Black, be prepared to spend a significant amount of money. | |
| Let's build a simple simulation to see how much it would cost on average to get her. | |
| Good luck! | |
| <div id="app"></div> | |
| <button onclick="runPulls()">Start</button> | |
| <div id="output"></div> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // There are 39 SSR characters each with a rate of 0.04% | |
| const SSR_RATE = 0.03; | |
| const SSR_COUNT = 39; | |
| const SSR_BULK_PULL_RATE = 0.03; | |
| // There are 30 SR characters each with a rate of 0.6% | |
| const SR_RATE = 0.18; | |
| const SR_BULK_PULL_RATE = 0.97; | |
| const SR_COUNT = 31; | |
| // There are 69 R characters each with a rate of 1.106% | |
| const R_RATE = 0.79; | |
| const R_COUNT = 69; | |
| // pull rate = percentage / # of characters | |
| let deck = []; | |
| let total_money = 0; | |
| let total_money_spent = 0; | |
| let karats=0; | |
| let got_kitasan_black = false; | |
| let pull_count = 0; | |
| const pullCharacter = () => { | |
| if (got_kitasan_black) { | |
| clearInterval(intervalId); | |
| clearInterval(setIntervalId2); | |
| console.log("Cleared intervals"); | |
| return; | |
| } | |
| // pay | |
| if (karats < 1500){ | |
| karats += 5000; | |
| total_money_spent += 69.99; | |
| } | |
| karats -= 1500; | |
| // pull | |
| const max = 100; | |
| const randomInteger = Math.floor(Math.random() * max); | |
| console.log(randomInteger); // e.g., 7 (can be 0-9) | |
| rarity = ""; | |
| for (let i = 0; i < 10; i++) { | |
| console.log(`Pull #${i + 1}`); | |
| let rarity = ""; | |
| // For the first 9 pulls, normal rates apply | |
| if (i < 9) { | |
| // SSR rate is 3% | |
| if (randomInteger < 4) { | |
| console.log("Pulled SSR!"); | |
| rarity = "SSR"; | |
| } | |
| else if (randomInteger <= 4 && randomInteger < 22) { | |
| console.log("Pulled SR!"); | |
| rarity = "SR"; | |
| } | |
| else { | |
| console.log("Pulled R!"); | |
| rarity = "R"; | |
| } | |
| if (rarity === "SSR") { | |
| // pick one of 39 SSR characters | |
| const characterIndex = Math.floor(Math.random() * SSR_COUNT); | |
| console.log(`Pulled SSR #${characterIndex + 1}`); | |
| deck.push(`SSR#${characterIndex + 1}`); | |
| } else if (rarity === "SR") { | |
| // pick one of 31 SR characters | |
| const characterIndex = Math.floor(Math.random() * SR_COUNT); | |
| console.log(`Pulled SR #${characterIndex + 1}`); | |
| deck.push(`SR#${characterIndex + 1}`); | |
| } else if (rarity === "R") { | |
| // pick one of 69 R characters | |
| const characterIndex = Math.floor(Math.random() * R_COUNT); | |
| console.log(`Pulled R #${characterIndex + 1}`); | |
| deck.push(`R#${characterIndex + 1}`); | |
| } | |
| } else { | |
| // On the 10th pull, guaranteed SR or better | |
| if (randomInteger < 4) { | |
| console.log("Pulled SSR on 10th pull!"); | |
| rarity = "SSR"; | |
| } else { | |
| console.log("Pulled SR on 10th pull!"); | |
| rarity = "SR"; | |
| } | |
| if (rarity === "SSR") { | |
| // pick one of 39 SSR characters | |
| const characterIndex = Math.floor(Math.random() * SSR_COUNT); | |
| console.log(`Pulled SSR #${characterIndex + 1}`); | |
| deck.push(`SSR#${characterIndex + 1}`); | |
| } else if (rarity === "SR") { | |
| // pick one of 31 SR characters | |
| const characterIndex = Math.floor(Math.random() * SR_COUNT); | |
| console.log(`Pulled SR #${characterIndex + 1}`); | |
| deck.push(`SR#${characterIndex + 1}`); | |
| } | |
| } | |
| } | |
| let div2 = document.getElementById("output"); | |
| div2.innerHTML = `<h3>Karats left: ${karats}</h3> | |
| <h3>Total money spent so far: $${total_money_spent.toFixed(2)}</h3> | |
| <h3>Total pulls so far: ${deck.length}</h3> | |
| <h3>Current deck: ${deck.join(", ")}</h3>`; | |
| if (deck.includes("SSR#1")) { | |
| console.log(`Got Kitasan Black! Total money spent: $${total_money_spent.toFixed(2)}`); | |
| got_kitasan_black = true; | |
| let div = document.getElementById("output"); | |
| div.innerHTML = `<h2>Got Kitasan Black! Total money spent: $${total_money_spent.toFixed(2)}</h2> | |
| <h3>Total pulls: ${deck.length}</h3> | |
| <h3>Deviance from expected pulls (2500): ${Math.sqrt((deck.length - 2500)**2)}</h3>`; | |
| return; | |
| } | |
| } | |
| function printDeck() { | |
| console.log(`Karats left: ${karats}`); | |
| console.log(`Total money spent so far: $${total_money_spent.toFixed(2)}`); | |
| console.log(`Current deck: ${deck.join(", ")}`); | |
| console.log(`Total pulls so far: ${deck.length}`); | |
| // check if Kitasan Black is in deck | |
| } | |
| const test = () => { | |
| console.log("Test function called"); | |
| } | |
| var intervalId; | |
| var setIntervalId; | |
| const runPulls = () => { | |
| pullCharacter(); | |
| intervalId = setInterval(pullCharacter,50); | |
| setIntervalId2 = setInterval(printDeck,50); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment