Code, Learn

Utilizziamo le regular expression per interpretare il lancio dei dadi

17 Settembre 2020 - 4 minuti di lettura

Un paio di settimane fa ho iniziato un progetto con un mio amico applicando Extreme Programing [1] come metodologia di sviluppo.

Poiché sia io che il mio amico siamo appassionati di giochi di ruolo abbiamo deciso di scrivere un generatore/gestore di schede di personaggi in cui una delle caratteristiche principali è un simulatore di lancio di dadi che utilizza le regular expression [2] per mappare le notazioni dei dadi [3] durante la generazione del personaggio.

Breve digressione sulle regular expression e i dadi nei giochi di ruolo

Le regular expression, o espressioni regolari, sono sequenze di caratteri (come lettere, numeri ecc.) utili per identificare pattern all’interno di un testo.
Ogni volta che si gioca a un gioco di ruolo o da tavolo come Monopoly o backgammon si devono tirare uno o più dadi. Ad esempio se si tira un classico dado a 6 facce, la notazione del dado sarà d6 (d per il dado, 6 per le facce del dado).
Per diversi giochi di ruolo è necessario utilizzare dadi diversi da quelli classici, magari a 4, 8, 10, 12 e 20 facce e a volte è necessario lanciare più dadi contemporaneamente e poi sommare i risultati. Ad esempio, tirare tre dadi da 10 facce l’uno significherebbe usare la notazione 3d10.

Modelliamo le varie casistiche con le regular expression

Tornando al nostro software, vediamo come tradurre le varie casistiche utilizzando le regular expression, o regex per abbreviare.

regex per i dadi

La regex (? <numberOfDice> [\ d] +)? [dD] (? <faces> [\ d] +) restituisce due gruppi, uno numberOfDice facoltativo e faces; se numberOfDice non è definito dovrebbe ritornare 1 come risultato.

regex per la costante numerica

Per quanto riguarda gli interi costanti, la regex (? <constant> [\ d] +) la quale ritorna un gruppo con valore di tipo intero.
Questa espressione è utile per tutti i casi in cui si deve tirare il dado e aggiungere un numero intero al risultato. Alcuni esempi:

  • 2d6 + 2 significa tira due dadi e aggiungi due al risultato;
  • d6 + 2d8 significa tira un dado a 6 facce e due a 8 facce e calcola il risultato.

regex per l’operatore

L’espressione (? <operatore> [+ \ -])? restituisce un gruppo facoltativo in cui il valore è + o -; se non definito significa + (addizione).
Come visto precedentemente, questo operatore dovrebbe accoppiare più notazioni di dadi.

regex per l’esplosione o implosione

Esistono tiri di dado aperti dove il tiro esplode o implode. Ad esempio capita di dover fare un secondo lancio se il risultato è 6 (e così via) e poi sommare i risultati, oppure l’inverso (ovvero sottrarre) nel caso in cui il primo tiro è 1.
Alcuni esempi di notazione:

  • d6! significa tira di nuovo se il risultato è 6 Dove se il risultato è 6 hai il diritto di tirare di nuovo;
  • d6!5 significa che se il risultato è 5 o 6 puoi tirare ancora;
  • Implosione: utilizzare il punto esclamativo invertito “¡”, ad esempio d6¡ o d6¡2.

La regex (?<explode>![\d]*)?(?<implode>¡[\d]*)? restituisce due gruppi opzionali esplode e implode dove la cifra mancante è impostata di default al numero di facce del dado.

regex per la selettività

Una regola selettiva può essere applicata in alcuni giochi, come Warhammer 40K 2nd Edition, quando si effettuano tiri per gli attributi del personaggio per conservare i lanci di dado migliori o peggiori.
Ad esempio:

  • 3d10k2 significa tira tre dadi a 10 facce, mantieni i due migliori risultati e sommali
  • 3d10d2 indica lo stesso tiro ma mantenendo i due risultati peggiori.

I tiri selettivi possono essere tenuti o scartati, non entrambi.
La regex (? <selective> [kd] [\ d] *)? restituisce un gruppo opzionale in cui il numero di dadi è sempre definito senza alcun valore predefinito. La prima lettera indica se i dadi devono essere tenuti (k) o scartati (d).

Realizziamo la nostra regular expression

Unendo le precedenti regular expression otteniamo questo risultato:

(?<operator>[+\-])?(?:(?<dice>(?<numberOfDice>[\d]+)?[dD](?<faces>[\d]+)(?<explode>![\d]*)?(?<implode>¡[\d]*)?(?<selective>[kd][\d]+)?)|(?<constant>[\d]+))

Qualora voleste testare la regex ho preparato su regex101 [4] una sandbox.

Conclusioni

L’utilizzo delle regex ci aiuta nell’interpretazione delle notazioni ma non è sufficiente per calcolare i risultati, che è il vero obiettivo del nostro software. Per questo è necessario implementare la logica nel modo che preferite (ad esempio utilizzando value object o servizi). Si noti inoltre che la regex che abbiamo realizzato si applica solo ad un gruppo di notazioni come d6, -3d100!96k1 e non aggregati come d6 + 2-2d10d1.

Articolo scritto da