Attivare non più di M eventi al secondo, simulare N incrementi al secondo

0

Quale algoritmo dovrei usare, per simulare un flusso continuo di N incrementi ogni secondo - non scrivere un ciclo, ma piuttosto eventi a intervalli temporizzati, non più di M eventi al secondo?

Sto implementando un gioco incrementale , e la velocità di incremento per alcune risorse di Scrog ha una variazione molto ampia tasso di aumento. Il sistema che sto usando ha un timer per gli eventi, e questo è il meccanismo che voglio usare per generare la risorsa nel tempo.

Vincoli di progettazione

Gli input di questo algoritmo sono: il tasso effettivo di incremento di Scrog (ad esempio "14 al secondo", "578 al secondo") e il limite inferiore del periodo per ciascun timer (ad esempio "non inferiore a 10 al secondo") "," Non inferiore a 100 al secondo ").

Gli output di questo algoritmo sono: un piccolo insieme di tuple (intervallo-temporizzatore, quantità-scrog), spesso solo una tupla e tipicamente non più di una manciata, che quando prese insieme produrranno effettivamente la velocità specificata di incremento di Scrog al secondo.

  • Voglio simulare qualsiasi cosa da 1 incremento ogni pochi secondi, fino a trilioni al secondo.

  • L'incremento della risorsa Scrog deve essere eseguito da importi interi costanti. Voglio precalcolare gli importi e non occuparmi delle frazioni della risorsa.

  • Gli eventi dovrebbero essere attivati da timer a intervalli ripetuti.

  • Gli intervalli del timer generati dovrebbero essere il più grandi possibile, per eseguire la funzione il meno frequentemente possibile. Dato un tasso specifico di aumento, non voglio una funzione di polling che faccia inutili controlli "è ancora ora?"; che era noto in precedenza, questo algoritmo ha bisogno di impostare i timer per evitare polling.

  • Gli intervalli del timer generati devono essere maggiori di un limite minimo specificato ("M al secondo"), mentre abbastanza piccoli da aggregare simulare il tasso costante "N al secondo".

  • Nessuno stato può essere tenuto in un ciclo; invece, l'algoritmo deve precomputerare una raccolta di timer che ogni volta genererà un evento "incrementa lo scrog per n", periodicamente. Il periodo di ciascun timer e la quantità intera di Scrog prodotto da ciascun timer sono quindi costanti.

  • Gli eventi dovrebbero sparare costantemente, simulando un flusso continuo; ma non indefinitamente spesso, in modo che il gestore di eventi non sia sovraccarico.

  • È accettabile se l'algoritmo approssima solo la frequenza specificata, entro la tolleranza di M-per-secondo.

Quindi sto cercando un algoritmo generico, che simulerà un flusso continuo di Scrog a qualsiasi velocità (N al secondo), impostando eventi ripetuti a un piccolo numero di intervalli fissi, ogni intervallo non più frequente di M al secondo.

Esempio: fino a 10 eventi al secondo

Se limito il tasso effettivo di eventi a non più veloce di 0,1 secondi (10 volte al secondo), ciò significherebbe:

  • Quando la frequenza è "1 Scrog per 5 secondi", l'algoritmo può produrre il set { (5.0 seconds, 1 Scrog) } .
  • Quando la frequenza è "1 Scrog al secondo", l'algoritmo può produrre il set { (1.0 seconds, 1 Scrog) } .
  • Quando la frequenza è "7 Scrog al secondo", l'algoritmo può produrre il set { (0.143 seconds, 1 Scrog) } .
  • Quando la frequenza è "10 Scrog al secondo", l'algoritmo può produrre il set { (0.1 seconds, 1 Scrog) } .
  • Quando la frequenza è "500 Scrog al secondo", l'algoritmo può produrre il set { (0.1 seconds, 50 Scrog) } .

Ma sono confuso su come l'algoritmo dovrebbe gestire i tassi più velocemente di 10 secondi al secondo, più lentamente di centinaia al secondo.

  • Quando la frequenza è "14 Scrog al secondo", l'algoritmo può produrre il set { (0.1 seconds, 1 Scrog), (0.25 seconds, 1 Scrog) } , perché gli eventi attivati con quegli intervalli genereranno 14 Scrog al secondo.

Un semplice problema aritmetico?

Spogliato del contesto di eventi, timer, ecc. questo si riduce a me cercando di prendere alcuni numeri, con unità, e produrre altri numeri con unità.

Quindi questo è apparentemente un problema abbastanza semplice (?): progettare un algoritmo generale che, dati questi input, e i vincoli di cui sopra, produrrà quegli output.

Ma la mia aritmetica astratta non è abbastanza potente. Come deve essere scritto l'algoritmo in modo che produca tutti questi risultati, dati solo i vincoli e la velocità di Scrog effettiva corrente?

    
posta bignose 07.01.2018 - 01:30
fonte

2 risposte

2

Non fare affidamento sulla frequenza del loop.

Hai una percentuale di accumulo Scrog associata a ogni Player . Quindi, basta mettere un metodo awardScrogs() e lastTimeSrogsAwarded e invocare come necessario. Indipendentemente dalla frequenza con cui viene chiamata awardScrogs() , deve controllare lastScrogsAwarded e determinare al momento del richiamo quanti di questi Player necessitano.

Puoi controllare ulteriormente come vengono assegnati gli Scrogs aggiungendo minumumAwardAmount e / o minimumAwardPeriod . Il tuo awardScrogs() non farà nulla se i minimi non sono soddisfatti. Inoltre, se vuoi assicurarti che gli Scrogs vengano assegnati in gruppi di dimensioni particolari, aggiungi awardGroupSize per awardScrogs() per arrotondare sempre al multiplo più vicino di.

Potrebbe essere qualcosa del genere:

function awardScrogs() {
  var time = new Date.getTime();

  var period = time - this.lastTimeScrogsAwarded;
  if (period < minimumAwardPeriod) return;

  var potentialAward = period * scrogsAwardRate;
  var awardGroupCount = Math.floor(potentialAward / awardGroupSize);
  var actualAward = awardGroupCount * awardGroupSize;
  if (actualAward < minimumAwardAmount) return;

  this.scrogs += actualAward;
  this.save();
}

... o qualsiasi altra cosa.

Lo invochi ogni volta che hai bisogno di - e non più spesso.

Chiama awardScrogs() durante la costruzione dell'oggetto o immediatamente prima di leggere il valore da .scrogs e solo allora. Se non c'è niente da assegnare, non fa molto molto rapidamente e senza conseguenze. Se c'è un premio in sospeso, viene assegnato immediatamente, tutto in una volta, just-in-time, e sei sicuro di avere il valore più preciso e aggiornato ogni volta.

Allo scopo di mantenere un indice o una classifica, aggiorna quelli con un intervallo più lungo, da qualche parte tra 5 minuti e 24 ore. Mantieni separati i dati per evitare che il traffico sulla classifica blocchi le tue Player righe. E quando lo aggiorni, chiama awardScrogs() su ogni Player .

    
risposta data 08.01.2018 - 02:03
fonte
0

A parte i casi speciali, dovrai affrontare sia gli Scrog frazionari che i secondi frazionari - o entrambi.

Periodo fisso, intervalli variabili

Da una prospettiva puramente concettuale, potrebbe essere più sensato ridurre il ScrogMiningPeriod che serve per creare un altro Scrog. Attendi questo intervallo e incrementa ScrogCount . In pratica, questa non è una buona idea per diversi motivi.

  • Probabilmente non avrai un computer Hertz multi-trillion, quindi non puoi raggiungere quella velocità. Ovviamente, il tuo sistema operativo imporrà già un limite molto più restrittivo su questa tariffa.
  • Anche se potresti incrementare il valore in periodi di ns o μs, è uno spreco completo di risorse di calcolo.

Poiché non è possibile rendere l'intervallo di mining abbastanza piccolo per mantenere un incremento fisso, è opportuno mantenere il periodo di mining corretto e gestire incrementi diversi. In questo modo, devi solo gestire uno fattore di variazione.

A parte: dovresti impostare il periodo abbastanza piccolo affinché gli utenti possano percepire gli aggiornamenti come continui. Alcune volte al secondo dovrebbero essere più che sufficienti.

Incrementi frazionari

Poiché potresti voler incrementare gli Scrogs di meno di uno per intervallo, dovrai gestire gli Scrog frazionari. Scegli un'unità Scrog a grana sufficientemente fine (ad es. 1/1000) e fai tutti i tuoi calcoli in questa unità.

Siccome il tuo contatore ha bisogno di gestire trilioni di nuovi scrvi al secondo, avrai comunque bisogno di una grande contro-variabile. Quindi qualche altro ordine di grandezza non dovrebbe fare una differenza così grande.

Errori di arrotondamento

Se hai bisogno di un'elevata precisione nel lungo periodo, puoi assicurarti che la velocità di estrazione produca un intervallo esatto dopo ogni periodo. Se questa non è un'opzione, puoi definire una tabella di data mining in base alla frequenza, ovvero ottenere un importo leggermente diverso ogni x th intervallo.

Ad esempio, se vuoi aggiungere 1 Scrog al secondo e hai scelto il tuo intervallo di mining per 1/3 di secondo, e stai calcolando in 1/1000 Scrogs, la tua tabella potrebbe essere [333, 333, 334] .

Si noti che questo è più teorico, perché i timer non saranno comunque quelli esatti.

Integral Scrog Alternative

C'è un'alternativa ovvia (in realtà due - vedi sotto) che ho trascurato in precedenza. Tuttavia, non rende le cose più facili, ma forse preferiresti questo approccio.

Vuoi estrarre uno scrog dopo che è trascorso un certo intervallo di tempo (chiamalo P ). Quindi concettualmente, ti piacerebbe fare sleep(P); scrogCount++; in un ciclo.

Poiché non è possibile con una trilione di scrvi al secondo, vogliamo rendere più lungo il periodo di estrazione e compensare questo estraendo più di 1 scrog alla volta. Quindi otteniamo una velocità di mining R = S / P dove S è il numero di scrogs estratti per intervallo.

L'algoritmo aggiornato sarebbe sleep(P); scrogCount += S .

Slow Mining Se P è più grande di qualche valore di soglia - chiamalo 0.25ms - allora possiamo semplicemente impostare S = 1 e usare quell'algoritmo.

Fast Mining Altrimenti, dobbiamo moltiplicare S e P di qualche fattore fino a quando P raggiunge o surpases la soglia.

Il problema è che vogliamo mantenere S integrale e rendere P un valore ms integrale. Se abbiamo un periodo di mining davvero strano, questo potrebbe far sì che P diventi relativamente grande, così sembra che non stiamo estraendo nulla per un po 'e poi otteniamo un gigantesco batch.

Questo può essere gestito calcolando valori per S e P che quasi producono la velocità desiderata R , e quindi aggiungendo gli scrogs mancanti ad ogni x th iterazione, come descritto sopra.

Calcolo diretto

A seconda del resto della tua app, il modo più semplice per farlo potrebbe essere quello di calcolare il numero corrente di scrogs in qualsiasi momento. Invece di simulare la creazione dello scrog in background, potresti calcolare il scrogCount attuale in base alla velocità di estrazione, al conteggio dello scrigno precedente e al tempo trascorso da allora.

Questo ha il vantaggio di essere il più preciso (dato che i timer non si attiveranno necessariamente quando ci si aspetta che lo facciano).

    
risposta data 07.01.2018 - 17:23
fonte

Leggi altre domande sui tag