From 4b26b46d2ee039654a01bd4fc1730b7ff93f1ec5 Mon Sep 17 00:00:00 2001 From: Simone Zama Date: Mon, 14 Sep 2026 18:46:14 +0200 Subject: [PATCH] docs: fix code snippets --- docs/implementation/casadei.md | 4 +-- docs/implementation/ferar.md | 50 +++++++++++++++++----------------- docs/implementation/zama.md | 38 +++++++++++++------------- docs/processo.md | 1 + 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/docs/implementation/casadei.md b/docs/implementation/casadei.md index 1ae9eb0..2d7ff62 100644 --- a/docs/implementation/casadei.md +++ b/docs/implementation/casadei.md @@ -240,8 +240,8 @@ di copertura del codice. 3. [Architettura](../architettura.md) 4. [Design di dettaglio](design-di-dettaglio.md) 5. [Implementazione](../implementazione.md) - 1. [Alex Casadei **(prossimo)**](../implementation/ferar.md) - 2. [Luca Ferar](../implementation/ferar.md) + 1. [Alex Casadei](../implementation/ferar.md) + 2. [**Luca Ferar (prossimo)**](../implementation/ferar.md) 3. [Simone Zama](../implementation/zama.md) 6. [Testing](../testing.md) 7. [Retrospettiva](../retrospettiva.md) \ No newline at end of file diff --git a/docs/implementation/ferar.md b/docs/implementation/ferar.md index 592334e..642b165 100644 --- a/docs/implementation/ferar.md +++ b/docs/implementation/ferar.md @@ -23,7 +23,7 @@ L'elemento di Scala più rilevante utilizzato: - Enum per rappresentare i possibili semi della carta: -```scala 3 +```scala enum Suit: case Pentacles, Cups, Swords, Wands ``` @@ -45,7 +45,7 @@ Gli elementi di Scala più rilevanti utilizzati sono: - Utilizzo di tail recursion per l'implementazione del metodo `shuffle`: -```scala 3 +```scala def shuffle(): Deck = @tailrec def shuffleOn(cards: Vector[Card], shuffledCards: Vector[Card]): Vector[Card] = cards match @@ -59,7 +59,7 @@ Gli elementi di Scala più rilevanti utilizzati sono: - Utilizzo di pattern matching all'interno del metodo `shuffleOn`: -```scala 3 +```scala def shuffleOn(cards: Vector[Card], shuffledCards: Vector[Card]): Vector[Card] = cards match case Vector() => shuffledCards case _ => @@ -68,7 +68,7 @@ Gli elementi di Scala più rilevanti utilizzati sono: - Utilizzo di `Option` per gestire il caso in cui si tenti di estrarre una carta da un mazzo vuoto. L’implementazione sfrutta `headOption` e `map`: -```scala 3 +```scala def draw(): Option[(Card, Deck)] = cards.headOption.map(card => (card, DeckImpl(cards.tail))) ``` @@ -76,7 +76,7 @@ Gli elementi di Scala più rilevanti utilizzati sono: combinazione tra i quattro semi e i valori da asso a re, ottenendo così un mazzo composto da 40 carte. (La costruzione delle carte sfrutta la sintassi fornita dalla `CardDSL`): -```scala 3 +```scala object DeckFactory: def apply(): Deck = val cards = for @@ -113,7 +113,7 @@ L'elemento di Scala più rilevante: - Immutabilità e copy: le operazioni che modificano il campo non alterano l’istanza corrente, ma producono una nuova istanza di `FieldImpl` tramite `copy`. Questo permette di mantenere invariato lo stato precedente: -```scala 3 +```scala def addCard(card: Card): Field = copy(cards :+ card) ``` @@ -129,7 +129,7 @@ alla carta in cima alla pila. L’enum `Player` rappresenta i due giocatori della partita, `Player1` e `Player2`, e fornisce il metodo `other`, che permette di ottenere il giocatore avversario. -```scala 3 +```scala enum Player: case Player1, Player2 @@ -164,7 +164,7 @@ Aspetti rilevanti di Scala all'interno di questa implementazione sono: - Utilizzo di `Map` per associare ogni `Player` al proprio `Field`, permettendo di recuperare e aggiornare il campo di un giocatore attraverso la relativa chiave: -```scala 3 +```scala val players: Map[Player, Field] players(player) players.updated(player, updatedField) @@ -172,7 +172,7 @@ di un giocatore attraverso la relativa chiave: - Utilizzo di `Option` per rappresentare il risultato della pesca: -```scala 3 +```scala def draw(): Option[(Card, BoardImpl)] = val checked = checkDeck() checked.deck.draw().map((card, remainingDeck) => (card, checked.copy(deck = remainingDeck))) @@ -181,7 +181,7 @@ di un giocatore attraverso la relativa chiave: - Utilizzo di pattern matching nel metodo `placeCardInField` per distinguere il caso in cui venga fornito un indice da quello in cui non venga fornito: -```scala 3 +```scala def placeCardInField(card: Card, player: Player, index: Option[Int]): Board = index match case Some(i) if i < players(player).length && i >= 0 => @@ -207,7 +207,7 @@ un `CardBuilder` in un `Deck`. Ecco un esempio di un `Deck` con due carte creato con la DSL: -```scala 3 +```scala val deck = deck from (ace of Cups | two of Swords) ``` @@ -216,7 +216,7 @@ Gli elementi di Scala più rilevanti utilizzati sono: - Extension method: viene definito un metodo di estensione `|` per `Card`, che permette di utilizzare una carta come punto di partenza per la costruzione di un `CardBuilder`: -```scala 3 +```scala extension (card: Card) infix def |(other: Card): CardBuilder = CardBuilder(Vector(card, other)) ``` @@ -224,7 +224,7 @@ che permette di utilizzare una carta come punto di partenza per la costruzione d - Case class CardBuilder: rappresenta una struttura intermedia contenente le carte che verranno utilizzate per costruire il mazzo. L’operatore `|` permette di aggiungere ulteriori carte alla sequenza: -```scala 3 +```scala case class CardBuilder(cards: Vector[Card]): infix def |(other: Card): CardBuilder = CardBuilder(cards :+ other) ``` @@ -232,7 +232,7 @@ per costruire il mazzo. L’operatore `|` permette di aggiungere ulteriori carte - Given Conversion: permette di convertire implicitamente un `CardBuilder` in un `Deck`, rendendo possibile utilizzare direttamente una catena di carte nei contesti in cui è richiesto un mazzo: -```scala 3 +```scala given Conversion[CardBuilder, Deck] = b => DeckImpl(b.cards) ``` @@ -249,7 +249,7 @@ BoardDSL mette a disposizione tre entry point principali: L’entry point default board crea direttamente una board con un campo composto da quattro carte per ciascun giocatore a partire dal deck di default con 40 carte italiane e pila degli scarti vuota: -``` scala 3 +``` scala import BoardDSL.* val board: Board = default board ``` @@ -258,7 +258,7 @@ Per ottenere invece una configurazione personalizzabile si utilizza `board from che restituisce un `BoardBuilder`. Le personalizzazioni possono essere aggiunte attraverso il metodo `withCustom`: -```scala 3 +```scala import BoardDSL.* import CardDSL.* import FieldDSL.* @@ -273,7 +273,7 @@ Le personalizzazioni possibili sono rappresentate dal trait Customisation e dall relative implementazioni `PlayerOneCards`, `PlayerTwoCards`, `CustomDeck` e `CustomDiscard`: -```scala 3 +```scala sealed trait Customisation case class PlayerOneCards(field: Field) extends Customisation case class PlayerTwoCards(field: Field) extends Customisation @@ -290,7 +290,7 @@ La configurazione viene accumulata all’interno di `BoardBuilder` attraverso il `withCustom`, che non modifica il builder esistente ma ne restituisce uno nuovo contenente la personalizzazione aggiunta: -```scala 3 +```scala private def removeCards(deck: Deck, toRemove: List[Card]): Deck = val remaining = toRemove.foldLeft(deck.cards.toList) { (cards, target) => val id = cards.indexWhere(c => c.value == target.value && c.suit == target.suit) @@ -305,7 +305,7 @@ richiamare esplicitamente build. Questa DSL, può essere combinata con CardDSL, DeckDSL e FieldDSL per costruire una configurazione completa del Board: -```scala 3 +```scala val board = (board from default) .withCustom(playerOne(ace of Cups and two of Swords)) @@ -321,7 +321,7 @@ ha chiamato cactus. La fase della partita è rappresentata dall’`enum` `GamePhase`, che distingue quattro possibili stati: -```scala 3 +```scala enum GamePhase: case FirstTurns case Playing @@ -340,7 +340,7 @@ presenti nel rispettivo campo. L’object `Game` fornisce inoltre il metodo `apply(board: Board): Game`, che permette di creare una nuova partita a partire da un `Board`. La partita viene inizializzata nella fase `FirstTurns`, assegnando il primo turno a `Player1`: -```scala 3 +```scala object Game: def apply(board: Board): Game = val firstTurn = FirstTurn(board, Player1) @@ -351,7 +351,7 @@ Gli aspetti di scala principali sono: - Pattern matching nel metodo `advancePhase` per gestire le diverse fasi della partita e il giocatore che ha appena concluso il turno: -```scala 3 +```scala private def advancePhase(finishedTurn: Turn): Game = phase match case GamePhase.FirstTurns => @@ -365,14 +365,14 @@ concluso il turno: - Utilizzo di Map e higher-order functions nel metodo `playerScore` che utilizza `map` per associare ogni giocatore al proprio punteggio e `toMap` per ottenere la struttura finale: -```scala 3 +```scala def playerScore: Map[Player, Int] = Player.values.map(p => p -> currentTurn.board.getField(p).cardsList.map(_.value).sum).toMap ``` - Utilizzo di export, vengono esposti direttamente alcuni membri del `Turn` corrente, permettendo a `Game` di riutilizzarli senza dover accedere esplicitamente a `currentTurn`: -```scala 3 +```scala case class Game( phase: GamePhase, currentTurn: Turn, @@ -398,7 +398,7 @@ Per questi Showcase è stata realizzata la sola dichiarazione e configurazione t La loro effettiva integrazione e utilizzo nel gioco è stata invece lasciata a un altro membro del gruppo. Esempio di `showcase` utilizzando concretamente tutte le DSL: -```scala 3 +```scala private val deckForSixEffect = deck from (six of Swords) | (three of Cups) | (king of Cups) | (king of Swords) diff --git a/docs/implementation/zama.md b/docs/implementation/zama.md index 5afb055..de21329 100644 --- a/docs/implementation/zama.md +++ b/docs/implementation/zama.md @@ -28,7 +28,7 @@ possiedono dei campi utilizzati per indicare le carte in esse coinvolte. Aspetti rilevanti di Scala all'interno di questa implementazione sono: - Pattern matching per l'implementazione dei metodi `nextActions` e `execute`: -```scala 3 +```scala private def execute(currentTurn: Turn): Turn = this match case Observe => currentTurn.drawnFromField(0).drawnFromField(0) @@ -38,7 +38,7 @@ private def execute(currentTurn: Turn): Turn = ... ``` - Contextual programming per fornire il contesto opzionale del turno corrente al metodo `nextActions`: -```scala 3 +```scala def nextActions(using Option[Turn]): List[Action] = this match case Observe => List(Confirm) case Confirm | Cactus => List(EndTurn) @@ -74,7 +74,7 @@ Le funzionalità principali di `Turn` sono: Elementi rilevanti di Scala all'interno di questa implementazione sono: - Companion object con factory method per creare il turno. Sono presenti tre factory, una per ogni tipologia di turno da creare: - ```scala 3 + ```scala object Turns: object FirstTurn: def apply(...): Turn = ... @@ -84,7 +84,7 @@ Elementi rilevanti di Scala all'interno di questa implementazione sono: def apply(...): Turn = ... ``` - Companion object con extension methods per la manipolazione della `case class` del turno: - ```scala 3 + ```scala object Turns: extension (turn: Turn) @@ -107,7 +107,7 @@ al resto delle carte nel mazzo. La generazione di queste azioni è ottenuta tram di `Card` implementato nell'object `Effects`. Questo metodo individua il tipo di effetto tramite pattern matching sulla carta attivata e genera le azioni corrispondenti all'effetto in base alle informazioni contenute nello stato del turno corrente passato come argomento: -```scala 3 +```scala ... activated.value match case `six` => actionsFromFieldLength(getFieldLength(turn.player.other))(ObserveOpponent(_)) @@ -126,7 +126,7 @@ activated.value match Elementi rilevanti di Scala in questa implementazione sono: - Implementazione del metodo `effect` tramite extension method: - ```scala 3 + ```scala object Effects: extension (card: Card) def effect(on: Turn): List[Action] = ... @@ -147,7 +147,7 @@ giocatori. La classe estende il trait `Playable[Match]`, fornendo i metodi `act` cumulativi dei giocatori supera il punteggio limite impostato alla creazione del `Match`. La classe fornisce inoltre il metodo `nextGame` per ottenere l'istanza di `Match` da cui iniziare il prossimo `Game`: -```scala 3 +```scala def nextGame: Match = if !game.isOver then throw new IllegalStateException("Cannot start new game while current game has not ended.") copy(game = Game(newBoard from default)) @@ -156,13 +156,13 @@ def nextGame: Match = Elementi rilevanti di Scala in questa implementazione sono: - Utilizzo di `export` per dare accesso alle informazioni relative al `Game` in corso all'interno del `Match`: - ```scala 3 + ```scala export game.{act as _, isOver as isGameOver, *} ``` il metodo `act` di `Game` viene nascosto dato che il suo utilizzo è dettato dalla delegazione all'interno del metodo `act` di `Match`, e il metodo `isOver` è rinominato in `isGameOver`. - Companion object con factory method per creare il `Match`: - ```scala 3 + ```scala object Match: def apply(maxScore: Int, board: Board = newBoard from default): Match = Match(maxScore, Game(board), Map((Player1, 0), (Player2, 0))) @@ -177,7 +177,7 @@ ricopre durante il corso di un `Game`. - Tramite il metodo `play(turn: Turn): (Turn, Action)` l'`Opponent` osserva le azioni disponibili e, a seconda della sua attuale conoscenza delle carte in campo, sceglie quella piu' vantaggiosa. Una volta determinata l'azione, la conoscenza dell'`Opponent` viene aggiornata secondo le conseguenze che essa ha sul campo attuale: - ```scala 3 + ```scala def play(turn: Turn): (Turn, Action) = getChosenAction(turn) match case Observe => ... case ChooseDiscard(index) => ... @@ -189,7 +189,7 @@ ricopre durante il corso di un `Game`. ``` - Il metodo `react(action: Action, turn: Turn): Unit` permette a `Opponent` di aggiornare la propria conoscenza delle carte sul campo in base all'azione eseguita dall'utente: - ```scala 3 + ```scala def react(action: Action, turn: Turn): Unit = action match case ChooseDiscard(index) if knows(adversaryCards)(index) @@ -203,7 +203,7 @@ ricopre durante il corso di un `Game`. Elementi rilevanti di Scala in questa implementazione sono: - Pattern matching per la gestione della reazione all'azione `Swap`: - ```scala 3 + ```scala private def swapReaction(adversaryIndex: Int, ownIndex: Int): Unit = (knows(adversaryCards)(adversaryIndex), knows(knownCards)(ownIndex)) match case (true, true) => ... @@ -212,7 +212,7 @@ Elementi rilevanti di Scala in questa implementazione sono: case (_, _) => () ``` - Utilizzo di tipi funzionali per definire i predicati con cui filtrare le azioni favorevoli, ad esempio: - ```scala 3 + ```scala private def getChosenAction(turn: Turn): Action = val actions = turn.actions .filter(isDiscardable(_, turn)) @@ -239,7 +239,7 @@ scambiare una carta sul proprio campo con una carta sul campo dell'avversario L'implementazione è realizzata tramite i trait `Showcase` e `ShowcaseBoard`. `ShowcaseBoard` fornisce la `Board` utilizzata da `Showcase` per generare il turno tramite il metodo `apply`: -```scala 3 +```scala trait ShowcaseBoard: def apply(): Board @@ -247,7 +247,7 @@ trait SixEffect extends ShowcaseBoard: override def apply(): Board = boardForSixEffect ``` Le istanze di `Showcase` vengono create tramite mix-in con istanze di `ShowcaseBoard`: -```scala 3 +```scala trait Showcase: board: ShowCaseBoard => def turn: Turn = SimpleTurn(board(), Player1) @@ -266,7 +266,7 @@ di test, sono stati realizzati di object `CardDSL` e `FieldDSL`. `CardDSL` contiene le costanti utilizzate per indicare il valore delle carte in linguaggio naturale, e un extension method dei valori per creare una carta indicandone il valore e il seme: -```scala 3 +```scala object CardDSL: val king = 0 val ace = 1 @@ -276,7 +276,7 @@ object CardDSL: infix def of(suit: Suit): Card = CardImpl(value, Int) ``` Questa implementazione permette di creare una carta con la notazione ` of `: -```scala 3 +```scala import CardDSL.* val card: Card = ace of Swords ``` @@ -284,7 +284,7 @@ val card: Card = ace of Swords `FieldDSL` permette di creare le entità `Field` concatenando le carte in esse contenute con l'operatore `and`, questa funzionalità è implementata attraverso il trait `FieldBuilderLike[T]`, che fornisce il metodo `and` per concatenare un oggetto di tipo `T` a una carta: -```scala 3 +```scala sealed trait FieldBuilderLike[T]: infix def and(cardToAdd: Card): Field @@ -300,7 +300,7 @@ Un elemento rilevante di Scala in questa implementazione è la conversione impli da `Card` alla classe `FieldBuilderFromCard`, o da `Field` a `FieldBuilderFromField` è ottenuta tramite le istruzioni `given` per le implementazioni di `Conversion` con i rispettivi tipi: -```scala 3 +```scala object FieldDSL: given Conversion[Card, FieldBuilderLike[Card]] = FieldBuilderFromCard(_) given Conversion[Field, FieldBuilderLike[Field]] = FieldBuilderFromField(_) diff --git a/docs/processo.md b/docs/processo.md index 4f53130..e721a8b 100644 --- a/docs/processo.md +++ b/docs/processo.md @@ -59,6 +59,7 @@ queste actions sono: 1. [Sprint 1](process/sprint01.md) 2. [Sprint 2](process/sprint02.md) 3. [Sprint 3](process/sprint03.md) + 4. [Sprint 4](process/sprint04.md) 2. [**Requisiti (prossimo)**](requisiti.md) 3. [Architettura](architettura.md) 4. [Design di dettaglio](design-di-dettaglio.md)