@@ -91,7 +91,7 @@ export default function GachaCalc({ location }: { location: string }) {
9191 const [ guaranteed , setGuaranteed ] = useState ( false )
9292 const [ guaranteedPity , setGuaranteedPity ] = useState ( 0 )
9393
94- const [ calculated , setCalculated ] = useState ( [ ] as ReducedSim [ ] )
94+ const [ calculated , setCalculated ] = useState ( [ [ ] ] as ReducedSim [ ] [ ] )
9595
9696 const [ gachaName , setGacha ] = useState ( Object . values ( gachas ) . map ( g => g . bannerName ) [ 0 ] )
9797
@@ -114,6 +114,9 @@ export default function GachaCalc({ location }: { location: string }) {
114114 ( ) => setCalculated ( calcSimsRegular ( current , pity , pulls , guaranteed , guaranteedPity , banner ) ) ,
115115 [ current , pity , pulls , guaranteed , guaranteedPity , banner ]
116116 )
117+ const consts = [ ]
118+ for ( let i = current ; i <= banner . maxConst ; i ++ ) consts . push ( i )
119+ console . log ( calculated )
117120
118121 const desc = "Gacha rate calculator for Genshin Impact."
119122 return (
@@ -135,7 +138,6 @@ export default function GachaCalc({ location }: { location: string }) {
135138 < h1 className = "text-5xl font-bold pb-2" >
136139 Gacha rate calculator
137140 </ h1 >
138-
139141 < SelectInput label = "Banner type" set = { ( g ) => {
140142 if ( current == banner . minConst )
141143 setCurrent ( ( Object . values ( gachas ) . find ( x => x . bannerName == g ) ?? Object . values ( gachas ) [ 0 ] ) . minConst )
@@ -148,15 +150,15 @@ export default function GachaCalc({ location }: { location: string }) {
148150 { banner . guaranteedPity && < NumberInput label = "Epitomized Path" set = { setGuaranteedPity } value = { guaranteedPity } min = { 0 } max = { banner . guaranteedPity - 1 } /> }
149151
150152 < h3 className = "text-lg font-bold pt-1" id = "resistance" > Results:</ h3 >
151- < div className = "columns-1 md:columns-2 mr-2" >
153+ < div className = "columns-1 md:columns-2 mr-2 mb-2 " >
152154 < div className = "w-full bg-slate-800 rounded-xl p-1 my-2 md:my-0 text-white col-start-1" >
153155 < Bar data = { ( {
154- labels : calculated . filter ( x => x ) . map ( c => getName ( c , banner ) ) ,
156+ labels : calculated [ calculated . length - 1 ] . filter ( x => x ) . map ( c => getName ( c . const , banner ) ) ,
155157 datasets : [
156158 {
157159 label : "Rate" ,
158160 backgroundColor : "rgb(75, 192, 192)" ,
159- data : calculated . filter ( x => x ) . map ( ( c , i , a ) => c . rate * 100 ) ,
161+ data : calculated [ calculated . length - 1 ] . filter ( x => x ) . map ( ( c , i , a ) => c . rate * 100 ) ,
160162 borderColor : "white" ,
161163 borderWidth : 2 ,
162164 xAxisID : "xAxes"
@@ -183,14 +185,14 @@ export default function GachaCalc({ location }: { location: string }) {
183185 } ) } /> </ div >
184186 < div className = "w-full bg-slate-800 rounded-xl p-1 my-2 md:my-0 text-white col-start-2" >
185187 < Line data = { ( {
186- labels : calculated . filter ( x => x ) . map ( c => getName ( c , banner ) ) ,
188+ labels : calculated [ calculated . length - 1 ] . filter ( x => x ) . map ( c => getName ( c . const , banner ) ) ,
187189 datasets : [
188190 {
189191 label : "Cumulative rate" ,
190192 borderColor : "rgb(255, 99, 132)" ,
191193 borderWidth : 2 ,
192194 fill : false ,
193- data : calculated . filter ( x => x ) . map ( ( c , i , a ) => a . slice ( i , a . length ) . reduce ( ( p , c ) => p + c . rate , 0 ) * 100 ) ,
195+ data : calculated [ calculated . length - 1 ] . filter ( x => x ) . map ( ( c , i , a ) => a . slice ( i , a . length ) . reduce ( ( p , c ) => p + c . rate , 0 ) * 100 ) ,
194196 } ,
195197 ] ,
196198 } ) } options = { ( {
@@ -215,6 +217,42 @@ export default function GachaCalc({ location }: { location: string }) {
215217 } ) } />
216218 </ div >
217219 </ div >
220+ < div className = "w-full bg-slate-800 rounded-xl p-1 my-2 md:my-0 text-white col-start-2" >
221+ < Line data = { ( {
222+ labels : calculated . map ( ( _ , i ) => i + pity ) ,
223+ datasets : consts . filter ( i => i >= 0 ) . map ( i => ( {
224+ label : getName ( i , banner ) ,
225+ backgroundColor : [ "#c9c9c9" , "#ff6363" , "#ffd863" , "#b1ff63" , "#63ff8a" , "#63ffff" , "#638aff" , "#b163ff" , "#ff63d8" ] [ i + 1 ] ,
226+ borderColor : [ "#c9c9c9" , "#ff6363" , "#ffd863" , "#b1ff63" , "#63ff8a" , "#63ffff" , "#638aff" , "#b163ff" , "#ff63d8" ] [ i + 1 ] ,
227+ fill : true ,
228+ data : calculated . map ( ( c ) => ( c ?. filter ( x => x . const >= i ) ?. reduce ( ( p , c ) => p + c . rate , 0 ) * 100 ) ) ,
229+ borderWidth : 2 ,
230+ xAxisID : "xAxes"
231+ } ) ) ,
232+ } ) } options = { ( {
233+ color : "white" ,
234+ backgroundColor : "#333333" ,
235+ interaction : {
236+ mode : "index" ,
237+ intersect : false
238+ } ,
239+ scales : {
240+ yAxes : {
241+ max : 100 ,
242+ min : 0 ,
243+ ticks : {
244+ color : "white" ,
245+ callback : ( v ) => `${ v } %`
246+ }
247+ } ,
248+ xAxes : {
249+ ticks : {
250+ color : "white"
251+ }
252+ }
253+ }
254+ } ) } />
255+ </ div >
218256 < table className = { `table-auto w-80 ${ styles . table } ${ styles . stattable } my-2 sm:text-base text-sm` } >
219257 < thead >
220258 < tr className = "divide-x divide-gray-200 dark:divide-gray-500" >
@@ -224,9 +262,9 @@ export default function GachaCalc({ location }: { location: string }) {
224262 </ tr >
225263 </ thead >
226264 < tbody className = "divide-y divide-gray-200 dark:divide-gray-500" >
227- { calculated . filter ( x => x )
265+ { calculated [ calculated . length - 1 ] . filter ( x => x )
228266 . map ( ( c , i , a ) => < tr className = { `pr-1 divide-x divide-gray-200 dark:divide-gray-500 ${ c . rate < 0.0005 ? "opacity-60" : "" } ` } key = { c . const } >
229- < td > { getName ( c , banner ) } </ td >
267+ < td > { getName ( c . const , banner ) } </ td >
230268 < td > { ( c . rate * 100 ) . toFixed ( 3 ) } %</ td >
231269 < td > { ( a . slice ( i , a . length ) . reduce ( ( p , c ) => p + c . rate , 0 ) * 100 ) . toFixed ( 2 ) } %</ td >
232270 </ tr > ) }
@@ -236,8 +274,8 @@ export default function GachaCalc({ location }: { location: string }) {
236274 )
237275}
238276
239- function getName ( c : ReducedSim , banner : Banner ) {
240- return c . const == banner . minConst ? "Not owned" : `${ banner . constFormat } ${ c . const } `
277+ function getName ( c : number , banner : Banner ) {
278+ return c == banner . minConst ? "Not owned" : `${ banner . constFormat } ${ c } `
241279}
242280
243281function NumberInput ( { value, set, label, min, max } : { value : number , set : ( newValue : number ) => unknown , label : string , min ?: number , max ?: number } ) {
@@ -284,20 +322,7 @@ function SelectInput({ value, set, label, options }: { value: string, set: (newV
284322 </ label > </ div >
285323}
286324
287- function calcSimsRegular ( current : number , pity : number , pulls : number , guaranteed : boolean , guaranteedPity : number , banner : Banner ) : ReducedSim [ ] {
288- // Max pity / const
289- if ( banner . guaranteed >= 1 && pulls + pity >= banner . maxPity * ( ( banner . maxConst + 1 ) * 2 - ( guaranteed ? 1 : 0 ) ) )
290- return [ {
291- const : banner . maxConst ,
292- rate : 1
293- } ]
294-
295- if ( banner . guaranteedPity && banner . guaranteedPity >= 1 && pulls + pity >= banner . maxPity * ( ( banner . maxConst + 1 ) * banner . guaranteedPity * 2 - ( guaranteed ? 1 : 0 ) ) )
296- return [ {
297- const : banner . maxConst ,
298- rate : 1
299- } ]
300-
325+ function calcSimsRegular ( current : number , pity : number , pulls : number , guaranteed : boolean , guaranteedPity : number , banner : Banner ) : ReducedSim [ ] [ ] {
301326 return calcSimsInt ( {
302327 pity,
303328 guaranteed,
@@ -307,31 +332,34 @@ function calcSimsRegular(current: number, pity: number, pulls: number, guarantee
307332 } , pulls , banner )
308333}
309334
310- function calcSimsInt ( starterSim : Sim , pulls : number , banner : Banner ) : ReducedSim [ ] {
335+ function calcSimsInt ( starterSim : Sim , pulls : number , banner : Banner ) : ReducedSim [ ] [ ] {
311336 console . time ( "calc" )
312- const sims : Sim [ ] = calcSimsExact ( [ starterSim ] , pulls , banner , 0 )
337+ const sims : Sim [ ] [ ] = calcSimsExact ( [ starterSim ] , pulls , banner , 0 )
313338 console . timeEnd ( "calc" )
314339
315- // Reducing to simple sims with less information
316- const reducedSims : ReducedSim [ ] = [ ]
317- sims . forEach ( ( sim : Sim ) => {
318- if ( sim . rate == 0 ) return
319340
320- const other = reducedSims [ sim . const + 1 ]
341+ return sims . map ( sim => {
342+ // Reducing to simple sims with less information
343+ const reducedSims : ReducedSim [ ] = [ ]
344+ sim . forEach ( ( sim : Sim ) => {
345+ if ( sim . rate == 0 ) return
321346
322- if ( other )
323- other . rate += sim . rate
324- else
325- reducedSims [ sim . const + 1 ] = {
326- const : sim . const ,
327- rate : sim . rate
328- }
329- } )
347+ const other = reducedSims [ sim . const + 1 ]
330348
331- return reducedSims
349+ if ( other )
350+ other . rate += sim . rate
351+ else
352+ reducedSims [ sim . const + 1 ] = {
353+ const : sim . const ,
354+ rate : sim . rate
355+ }
356+ } )
357+ return reducedSims
358+ } )
332359}
333360
334361function calcSimsExact ( sims : Sim [ ] , pulls : number , banner : Banner , prune = 1e-8 ) {
362+ const allSims : Sim [ ] [ ] = [ sims ]
335363 for ( let i = 0 ; i < pulls ; i ++ ) {
336364 const newSims : Record < number , Sim > = { }
337365
@@ -358,7 +386,7 @@ function calcSimsExact(sims: Sim[], pulls: number, banner: Banner, prune = 1e-8)
358386 if ( ! sim ) continue
359387 if ( sim . rate <= prune ) continue // Pruning
360388 if ( sim . const >= banner . maxConst ) { // Limited to C6
361- addOrMerge ( sim )
389+ addOrMerge ( { ... sim } )
362390 continue
363391 }
364392 const currentPity = sim . pity + 1
@@ -421,6 +449,7 @@ function calcSimsExact(sims: Sim[], pulls: number, banner: Banner, prune = 1e-8)
421449 }
422450
423451 sims = Object . values ( newSims )
452+ allSims . push ( sims )
424453 }
425- return sims
454+ return allSims
426455}
0 commit comments