This commit is contained in:
alberto brumana 2025-05-15 18:45:52 +02:00
parent 73f3f08b5d
commit 89f2df488e
30 changed files with 464 additions and 2 deletions

BIN
.DS_Store vendored

Binary file not shown.

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

6
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="homebrew-23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/TamaGolem.iml" filepath="$PROJECT_DIR$/TamaGolem.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

11
TamaGolem.iml Normal file
View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="it.arnaldo.unibs.tamagolem" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

BIN
src/.DS_Store vendored

Binary file not shown.

View file

@ -1,5 +1,11 @@
package it.arnaldo.unibs.tamagolem;
/**
* Enum che rappresenta gli elementi utilizzabili nel gioco TamaGolem.
* Ogni elemento può interagire con altri generando effetti positivi o negativi nei combattimenti.
*
* Gli elementi vengono selezionati in modo casuale a seconda della difficoltà scelta all'inizio del gioco.
*/
public enum Element {
ZANG_TUNG_TUNG,
TORE,

View file

@ -2,17 +2,39 @@ package it.arnaldo.unibs.tamagolem;
import java.util.*;
/**
* Rappresenta il grafo degli elementi del gioco, dove i nodi sono {@link GraphElement}
* e gli archi rappresentano interazioni (positive o negative) tra elementi.
*/
public class ElementGraph {
/** Insieme degli elementi (nodi) presenti nel grafo */
private final Set<GraphElement> elements;
/**
* Costruttore della classe ElementGraph.
* Inizializza un nuovo grafo vuoto.
*/
public ElementGraph() {
this.elements = new HashSet<>();
}
/**
* Aggiunge un nuovo elemento al grafo.
*
* @param element L'elemento da aggiungere
*/
public void addElement(GraphElement element) {
elements.add(element);
}
/**
* Restituisce il valore dell'interazione tra due elementi.
*
* @param fromElement L'elemento di partenza
* @param toElement L'elemento di arrivo
* @return Il valore dell'interazione
*/
public int getValue(Element fromElement, Element toElement) {
for (GraphElement graphElement : elements) {
if (graphElement.getElement().equals(fromElement)) {
@ -22,10 +44,18 @@ public class ElementGraph {
return 0;
}
/**
* Restituisce l'insieme di tutti gli elementi presenti nel grafo.
*
* @return Set di {@link GraphElement}
*/
public Set<GraphElement> getElements() {
return elements;
}
/**
* Stampa a schermo la matrice delle interazioni tra tutti gli elementi del grafo.
*/
public void printGraph() {
System.out.println("From element is the row name, to element is the column name");
List<Element> elements = getElementsNames(); // lista ordinata degli elementi
@ -59,6 +89,11 @@ public class ElementGraph {
}
/**
* Calcola la forza totale di tutte le interazioni del grafo.
*
* @return La somma dei valori assoluti di tutte le interazioni tra elementi
*/
public int getTotalStrength(){
int totalStrength = 0;
@ -69,6 +104,11 @@ public class ElementGraph {
return totalStrength;
}
/**
* Restituisce una lista ordinata degli elementi contenuti nel grafo.
*
* @return Lista di oggetti {@link Element}
*/
public List<Element> getElementsNames(){
List<Element> elements = new ArrayList<>();
for (GraphElement el : this.elements ){
@ -77,6 +117,14 @@ public class ElementGraph {
return elements;
}
/**
* Restituisce il valore di interazione tra due elementi.
* Metodo alternativo a {@link #getValue}, ma lavora direttamente con i link.
*
* @param fromElement L'elemento di partenza
* @param toElement L'elemento di destinazione
* @return Il valore dell'interazione
*/
public int getInteractionBetween(Element fromElement, Element toElement) {
for (GraphElement el : elements) {
if (el.getElement().equals(fromElement)){

View file

@ -1,22 +1,52 @@
package it.arnaldo.unibs.tamagolem;
/**
* Rappresenta un collegamento (arco) tra due elementi nel grafo delle interazioni.
* Ogni collegamento ha un valore numerico che indica la forza (positiva o negativa) dell'interazione.
*/
public class ElementLink {
/** Valore dell'interazione tra elementi */
private final int value;
/** L'elemento verso cui punta il collegamento */
private final Element element;
/**
* Costruttore della classe ElementLink.
*
* @param value Il valore dell'interazione
* @param element L'elemento collegato
*/
public ElementLink(int value, Element element) {
this.value = value;
this.element = element;
}
/**
* Restituisce il valore dell'interazione.
*
* @return Il valore numerico dell'interazione
*/
public int getValue() {
return value;
}
/**
* Restituisce l'elemento collegato.
*
* @return L'elemento di destinazione del collegamento
*/
public Element getElement() {
return element;
}
/**
* Restituisce la forza dell'interazione solo se positiva.
* Le interazioni negative non vengono conteggiate nel calcolo della forza totale.
*
* @return Il valore dell'interazione se positivo, altrimenti 0
*/
public int getTotalStrength() {
return value >= 0 ? value : 0;
}

View file

@ -1,5 +1,13 @@
package it.arnaldo.unibs.tamagolem;
/**
* Enum che rappresenta l'esito di un combattimento tra due TamaGolem.
*/
public enum FightEsit {
GOLEM1, GOLEM2
/** Indica che ha vinto il TamaGolem del primo giocatore */
GOLEM1,
/** Indica che ha vinto il TamaGolem del secondo giocatore */
GOLEM2
}

View file

@ -8,6 +8,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
/**
* Rappresenta una partita tra due giocatori nel gioco TamaGolem.
* Si occupa della configurazione, dello svolgimento e della gestione dei combattimenti.
*/
public class Game {
private final Player player1;
private final Player player2;
@ -21,6 +25,13 @@ public class Game {
private int lifePoints;
private HashMap<Element, Integer> stonesPerElement;
/**
* Costruisce una nuova istanza di gioco.
*
* @param player1 Il primo giocatore
* @param player2 Il secondo giocatore
* @param worldBalance Il grafo degli elementi e delle loro interazioni
*/
public Game(Player player1, Player player2, ElementGraph worldBalance) {
this.player1 = player1;
this.player2 = player2;
@ -28,18 +39,25 @@ public class Game {
this.stonesPerElement = new HashMap<>();
}
/** @return Il primo giocatore */
public Player getPlayer1() {
return player1;
}
/** @return Il secondo giocatore */
public Player getPlayer2() {
return player2;
}
/** @return Il grafo degli elementi e delle loro interazioni */
public ElementGraph getWorldBalance() {
return worldBalance;
}
/**
* Gestisce il ciclo principale del gioco, in cui i golem vengono configurati e combattono tra loro.
* Termina quando uno dei giocatori non ha più golem disponibili o sceglie di uscire.
*/
private void loop(){
// setup dei tamagolem
boolean golem1Setupped = setupGolem(player1.getNextTamaGolem(), player1);
@ -99,6 +117,13 @@ public class Game {
next();
}
/**
* Configura un nuovo TamaGolem per un giocatore, permettendo di assegnare pietre elementali.
*
* @param golem Il TamaGolem da configurare
* @param player Il giocatore proprietario del golem
* @return true se la configurazione è andata a buon fine, false se lutente ha scelto di uscire
*/
private boolean setupGolem(TamaGolem golem, Player player) {
System.out.println(PrettyStrings.frame("Setting up " + player.getName() + " TamaGolem", 30, true, true));
System.out.println("You can assign " + numberOfStones + " stones to your tamaGolem");
@ -133,11 +158,20 @@ public class Game {
return true;
}
/**
* Rimuove i TamaGolem morti dalla lista di ciascun giocatore.
*
* @param p1 Primo giocatore
* @param p2 Secondo giocatore
*/
private void checkDeathsTamagolems(Player p1, Player p2) {
p1.getTamaGolems().removeIf(tg -> !tg.isAlive());
p2.getTamaGolems().removeIf(tg -> !tg.isAlive());
}
/**
* Configura i parametri iniziali del gioco: numero di elementi, pietre, golem, punti vita, ecc.
*/
private void setup() {
// N
numberOfElements = worldBalance.getElements().size();
@ -176,6 +210,9 @@ public class Game {
}
/**
* Avvia il gioco: setup iniziale, ciclo di gioco e stampa finale del grafo.
*/
public void start() {
setup();
loop();
@ -183,10 +220,20 @@ public class Game {
next();
}
/**
* Verifica se uno dei due giocatori ha perso tutti i propri golem.
*
* @return true se uno dei due ha perso, false altrimenti
*/
private boolean checkVictory(){
return !(player1.isAlive() && player2.isAlive());
}
/**
* Genera il menu delle pietre elementali disponibili, con conteggio residuo.
*
* @return Array di stringhe da usare nel menu
*/
private String[] getMenuOptions() {
List<Element> elementsNames = worldBalance.getElementsNames();
String[] menuOptions = new String[numberOfElements];
@ -198,6 +245,12 @@ public class Game {
return menuOptions;
}
/**
* Esegue il combattimento tra due TamaGolem.
* Ogni turno entrambi usano una pietra, viene calcolato il danno, e si continua finché uno muore.
*
* @return Lesito del combattimento: GOLEM1 o GOLEM2
*/
public FightEsit fight() {
TamaGolem golem1 = player1.getNextTamaGolem();
TamaGolem golem2 = player2.getNextTamaGolem();
@ -225,6 +278,9 @@ public class Game {
return FightEsit.GOLEM2;
}
/**
* Attende che l'utente prema INVIO per continuare.
*/
public void next(){
Scanner reader = new Scanner(System.in);
System.out.print("Press ENTER to continue... ");

View file

@ -4,9 +4,19 @@ import it.kibo.fp.lib.InputData;
import it.kibo.fp.lib.Menu;
import it.kibo.fp.lib.PrettyStrings;
/**
* Classe che gestisce il ciclo principale del gioco e l'interazione iniziale con i giocatori.
* Si occupa della creazione di una nuova partita e dell'avvio del gioco.
*/
public class GameLoop {
/** Riferimento all'istanza corrente del gioco */
private Game game;
/**
* Avvia il menù iniziale e gestisce l'avvio di nuove partite.
* Permette ai giocatori di creare una nuova partita e selezionare la difficoltà.
*/
public void start() {
String[] firstMenuEntries = {"New game"};
Menu firstMenu = new Menu("TamaGolem", firstMenuEntries, true, true, false);
@ -21,6 +31,11 @@ public class GameLoop {
} while (firstmenuChoise == 1);
}
/**
* Crea una nuova partita chiedendo i nomi dei due giocatori e la modalità di difficoltà.
*
* @return true se la partita è stata creata con successo, false altrimenti
*/
public boolean createNewGame() {
String[] diffucultyMenuEntries = {"Easy", "Medium", "Hard"};
Menu difficultyMenu = new Menu("Select Mode", diffucultyMenuEntries, true, true, false);

View file

@ -3,27 +3,61 @@ package it.arnaldo.unibs.tamagolem;
import java.util.HashSet;
import java.util.Set;
/**
* Rappresenta un nodo (elemento) nel grafo degli elementi, con i relativi collegamenti ad altri elementi.
* Ogni collegamento è rappresentato da un oggetto {@link ElementLink}.
*/
public class GraphElement {
/** L'elemento associato a questo nodo del grafo */
private final Element element;
/** Insieme dei collegamenti ad altri elementi */
private final Set<ElementLink> links;
/**
* Costruttore della classe GraphElement.
*
* @param element L'elemento rappresentato da questo nodo
*/
public GraphElement(Element element) {
this.element = element;
this.links = new HashSet<>();
}
/**
* Restituisce l'elemento associato a questo nodo.
*
* @return L'elemento di tipo {@link Element}
*/
public Element getElement() {
return element;
}
/**
* Restituisce l'insieme dei collegamenti a elementi adiacenti.
*
* @return Un insieme di oggetti {@link ElementLink}
*/
public Set<ElementLink> getLinks() {
return links;
}
/**
* Aggiunge un collegamento (link) a questo nodo del grafo.
*
* @param link Il collegamento da aggiungere
*/
public void addLink(ElementLink link) {
links.add(link);
}
/**
* Restituisce il valore del collegamento con un altro elemento.
*
* @param element L'elemento adiacente di cui cercare il collegamento
* @return Il valore associato al collegamento
*/
public int getLinkValue(Element element) {
for (ElementLink link : links) {
if (link.getElement().equals(element)) {
@ -33,6 +67,11 @@ public class GraphElement {
return 0;
}
/**
* Calcola la forza totale di tutti i collegamenti dell'elemento.
*
* @return La somma delle forze di tutti i collegamenti
*/
public int getTotalStrength(){
int strength = 0;
for (ElementLink link : links) {

View file

@ -4,12 +4,31 @@ import it.kibo.fp.lib.RandomDraws;
import java.util.*;
/**
* Rappresenta un sistema lineare di equazioni intere utilizzato per determinare le interazioni tra elementi.
* Risolve il sistema tramite eliminazione di Gauss e genera soluzioni intere positive casuali.
*/
public class LinearSystem {
/** Numero di equazioni */
private final int n;
/** Numero di incognite (pari a n*(n-1)/2) */
private final int m;
/** Matrice dei coefficienti (dimensione n x m) */
private final int[][] A;
/** Vettore dei termini noti */
private final int[] b;
/**
* Costruttore della classe LinearSystem.
*
* @param n Numero di equazioni
* @param A Matrice dei coefficienti
* @param b Vettore dei termini noti
*/
public LinearSystem(int n, int[][] A, int[] b) {
this.n = n;
this.m = (n * (n - 1)) / 2;
@ -17,6 +36,12 @@ public class LinearSystem {
this.b = b;
}
/**
* Risolve il sistema lineare cercando una soluzione intera positiva non nulla.
*
* @return Un array di interi con la soluzione del sistema
* @throws IllegalStateException Se non esiste una soluzione intera positiva valida
*/
public int[] resolve() {
int[][] extendedMatrix = new int[n][m + 1];
@ -46,6 +71,12 @@ public class LinearSystem {
throw new IllegalStateException("Impossibile trovare una solutions intera senza zeri");
}
/**
* Verifica che tutti i numeri della soluzione siano maggiori di zero.
*
* @param x Soluzione da verificare
* @return true se tutti i valori sono positivi, false altrimenti
*/
private boolean validNumbers(int[] x) {
for (int xi : x) {
if (xi <= 0) return false;
@ -54,6 +85,14 @@ public class LinearSystem {
return true;
}
/**
* Costruisce una soluzione completa del sistema a partire da parametri liberi e matrice estesa.
*
* @param extendedMatrix La matrice aumentata del sistema
* @param parameters Valori delle variabili libere
* @param rank Grado del sistema
* @return Un array contenente la soluzione del sistema
*/
private int[] constructSolution(int[][] extendedMatrix, int[] parameters, int rank) {
int[] x = new int[m];
Arrays.fill(x, 0);
@ -93,6 +132,12 @@ public class LinearSystem {
return x;
}
/**
* Applica l'eliminazione di Gauss per determinare il rango della matrice.
*
* @param mat Matrice aumentata da trasformare
* @return Il rango della matrice
*/
private int gauss(int[][] mat) {
int row = 0;
for (int col = 0; col < m && row < n; col++) {
@ -130,10 +175,24 @@ public class LinearSystem {
return row;
}
/**
* Calcola il Massimo Comun Divisore (MCD) tra due numeri.
*
* @param a Primo numero
* @param b Secondo numero
* @return Il MCD
*/
private int mcd(int a, int b) {
return b == 0 ? a : mcd(b, a % b);
}
/**
* Calcola il Minimo Comune Multiplo (MCM) tra due numeri.
*
* @param a Primo numero
* @param b Secondo numero
* @return Il MCM
*/
private int mcm(int a, int b) {
return a / mcd(a, b) * b;
}

View file

@ -1,7 +1,17 @@
package it.arnaldo.unibs.tamagolem;
/**
* Enum che rappresenta i livelli di difficoltà disponibili nel gioco TamaGolem.
* Ogni modalità influenza il numero di elementi usati nel grafo delle interazioni.
*/
public enum Modes {
/** Modalità facile: numero ridotto di elementi (3-5) */
EASY,
/** Modalità media: numero intermedio di elementi (6-8) */
MEDIUM,
/** Modalità difficile: numero elevato di elementi (9-10) */
HARD
}

View file

@ -1,22 +1,51 @@
package it.arnaldo.unibs.tamagolem;
/**
* Rappresenta una coppia di elementi (ad esempio per descrivere un'interazione tra due elementi).
* È una classe semplice contenente due riferimenti a oggetti di tipo {@link Element}.
*/
public class Pair {
/** Primo elemento della coppia */
private final Element first;
/** Secondo elemento della coppia */
private final Element second;
/**
* Costruttore della classe Pair.
*
* @param first Il primo elemento della coppia
* @param second Il secondo elemento della coppia
*/
Pair(Element first, Element second) {
this.first = first;
this.second = second;
}
/**
* Restituisce il primo elemento della coppia.
*
* @return Il primo elemento
*/
public Element getFirst() {
return first;
}
/**
* Restituisce il secondo elemento della coppia.
*
* @return Il secondo elemento
*/
public Element getSecond() {
return second;
}
/**
* Restituisce una rappresentazione testuale della coppia di elementi.
*
* @return Una stringa nel formato "(elemento1, elemento2)"
*/
@Override
public String toString(){
return "(" + first.toString() + ", " + second.toString() + ")";

View file

@ -2,23 +2,51 @@ package it.arnaldo.unibs.tamagolem;
import java.util.ArrayList;
/**
* Rappresenta un giocatore nel gioco TamaGolem.
* Ogni giocatore ha un nome e una lista di TamaGolem a disposizione.
*/
public class Player {
/** Nome del giocatore */
private final String name;
/** Lista dei TamaGolem appartenenti al giocatore */
private final ArrayList<TamaGolem> tamaGolems;
/**
* Costruttore della classe Player.
*
* @param name Il nome del giocatore
*/
public Player(String name) {
this.name = name;
this.tamaGolems = new ArrayList<>();
}
/**
* Restituisce il nome del giocatore.
*
* @return Il nome del giocatore
*/
public String getName() {
return name;
}
/**
* Restituisce la lista dei TamaGolem del giocatore.
*
* @return Una lista di TamaGolem
*/
public ArrayList<TamaGolem> getTamaGolems() {
return tamaGolems;
}
/**
* Restituisce il prossimo TamaGolem disponibile (il primo nella lista).
*
* @return Il prossimo TamaGolem, oppure null se la lista è vuota
*/
public TamaGolem getNextTamaGolem() {
if (tamaGolems.isEmpty()) {
return null;
@ -27,14 +55,29 @@ public class Player {
}
}
/**
* Aggiunge un TamaGolem alla lista del giocatore.
*
* @param t Il TamaGolem da aggiungere
*/
public void addTamaGolem(TamaGolem t) {
tamaGolems.add(t);
}
/**
* Rimuove un TamaGolem dalla lista del giocatore.
*
* @param t Il TamaGolem da rimuovere
*/
public void removeTamaGolem(TamaGolem t) {
tamaGolems.remove(t);
}
/**
* Verifica se il giocatore ha ancora almeno un TamaGolem vivo.
*
* @return true se ha ancora golem disponibili, false altrimenti
*/
public boolean isAlive() {
return !tamaGolems.isEmpty();
}

View file

@ -3,23 +3,52 @@ package it.arnaldo.unibs.tamagolem;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Rappresenta un TamaGolem, ovvero una creatura che combatte usando pietre elementali.
* Ogni TamaGolem ha dei punti vita e una coda di pietre che utilizza ciclicamente in battaglia.
*/
public class TamaGolem {
/** Coda di pietre elementali che il TamaGolem utilizza nei combattimenti */
private final Deque<Element> elementalStones;
/** Punti vita del TamaGolem */
private int lifePoints;
/**
* Costruttore della classe TamaGolem.
*
* @param lifePoints I punti vita iniziali del TamaGolem
*/
public TamaGolem(int lifePoints) {
this.lifePoints = lifePoints;
this.elementalStones = new ArrayDeque<>();
}
/**
* Restituisce la coda di pietre elementali del TamaGolem.
*
* @return Una Deque contenente le pietre elementali
*/
public Deque<Element> getElementalStones() {
return elementalStones;
}
/**
* Aggiunge una pietra elementale alla coda del TamaGolem.
*
* @param stone La pietra da aggiungere
*/
public void addElementalStone(Element stone) {
elementalStones.add(stone);
}
/**
* Utilizza la prima pietra elementale nella coda e la reinserisce in fondo,
* simulando un utilizzo ciclico.
*
* @return La pietra utilizzata, oppure null se la coda è vuota
*/
public Element useElementalStone() {
if (!elementalStones.isEmpty()) {
Element removedStone = elementalStones.removeFirst();
@ -29,24 +58,48 @@ public class TamaGolem {
return null;
}
/**
* Restituisce i punti vita attuali del TamaGolem.
*
* @return I punti vita rimanenti
*/
public int getLifePoints() {
return lifePoints;
}
/**
* Applica un danno al TamaGolem, riducendone i punti vita.
*
* @param damage Quantità di danno da applicare
* @return true se il TamaGolem è morto (punti vita 0), false altrimenti
*/
public boolean getDamage(int damage) {
lifePoints -= damage;
return lifePoints <= 0;
}
/**
* Verifica se il TamaGolem è ancora vivo.
*
* @return true se i punti vita sono maggiori di zero, false altrimenti
*/
public boolean isAlive() {
return lifePoints > 0;
}
/**
* Restituisce una rappresentazione testuale dello stato del TamaGolem.
*
* @return Una stringa con i punti vita e le pietre elementali
*/
@Override
public String toString() {
return "LP: " + lifePoints + ", Elemental stones:" + elementalStones.toString();
}
/**
* Stampa a console lo stato corrente del TamaGolem.
*/
public void print() {
System.out.println(toString());

View file

@ -1,6 +1,14 @@
package it.arnaldo.unibs.tamagolem;
/**
* Classe principale del programma TamaGolem.
* Avvia il gioco creando un'istanza del {@link GameLoop} e chiamando il metodo {@code start()}.
*/
public class TamaGolemMain {
/**
* Metodo main del programma. Punto di ingresso dell'applicazione.
*/
public static void main(String[] args) {
GameLoop gameLoop = new GameLoop();
gameLoop.start();

View file

@ -4,8 +4,20 @@ import it.kibo.fp.lib.RandomDraws;
import java.util.*;
/**
* Classe utility per la costruzione del mondo di gioco.
* Si occupa di generare un grafo bilanciato di elementi e delle loro interazioni
* in base alla difficoltà scelta.
*/
public class WorldBuilder {
/**
* Costruisce un grafo di elementi e interazioni basato sulla difficoltà scelta.
* Il grafo rispetta determinate condizioni di equilibrio e interazione.
*
* @param difficulty La difficoltà selezionata (EASY, MEDIUM, HARD)
* @return Il grafo degli elementi costruito
*/
public static ElementGraph buildWorld(Modes difficulty) {
// genero un numero casuale che mi dice quanti elementi prendo
Element[] allElements = Element.values();
@ -81,6 +93,13 @@ public class WorldBuilder {
}
}
/**
* Genera una mappa direzionale valida delle interazioni tra tutti gli elementi selezionati.
* Garantisce che ogni elemento abbia almeno un arco entrante e uno uscente.
*
* @param elements Lista degli elementi selezionati
* @return Mappa delle direzioni valide tra gli elementi
*/
private static Map<Element, Map<Element, Integer>> generateValidDirections(List<Element> elements) {
int n = elements.size();
Map<Element, Map<Element, Integer>> linkDirections = new HashMap<>();