Ottavio Franceschi

Developer

Studente di Informatica presso l'Università degli Studi di Trento,
con una forte predisposizione all'ascolto, capacità di apprendimento rapido e una costante motivazione verso l'acquisizione di nuove competenze.
Durante il mio percorso accademico, ho sviluppato e gestito diversi progetti personali, tra cui questo sito web, interamente realizzato da me. Questa piattaforma rappresenta una raccolta delle mie esperienze pratiche e delle competenze acquisite in vari linguaggi di programmazione, dimostrando la mia versatilità e attitudine a imparare rapidamente nuove tecnologie.

"Talk is cheap, show me the code"
"Le parole contano poco, mostrami il codice"
-Linus Torvalds

Ispirandomi alle parole di Linus Torvalds, sono convinto che il modo più efficace per presentare i miei progetti sia offrire una visione completa che includa non solo i risultati finali, ma anche il processo che li ha generati. Per questo motivo, oltre a fornire spiegazioni dettagliate, metto a disposizione il codice che ho personalmente scritto. Credo che questo approccio trasparente sia fondamentale per dimostrare sia le mie competenze tecniche, sia la mia capacità di risolvere problemi complessi attraverso il codice.

CUBE  WAVE

Linguaggio: javascript (p5.js )

Per iniziare, presento il codice che alimenta l'animazione visibile nella homepage del sito, sviluppata utilizzando la libreria JavaScript p5.js. Questo progetto rappresenta uno dei tanti esempi di come mi piace esplorare le potenzialità del codice nel mio tempo libero, spinto dalla curiosità e dalla voglia di sperimentare nuove idee creative. L'animazione è progettata per mostrare le mie competenze in sviluppo front-end, mettendo in evidenza l'uso di tecnologie moderne per creare esperienze visive dinamiche e coinvolgenti.

Esegui

<!DOCTYPE html>
<html lang="">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Cube Wave</title>
        <style> body {padding: 0; margin: 0;} </style>
        <link rel="stylesheet" href="style.css">
        <script src="../../p5.js"></script>
        <script src="../../addons/p5.dom.js"></script>
        <script src="../../addons/p5.sound.js"></script>
        <script src="main.js"></script>
    </head>
    <body>
    </body>
</html>

let angle = 0;
let maxD;
var angleVariation = -0.025;
var offsetVariation = 2;
var blockSize = 40;
var maxH = 1500; //500, 1500
                    
function setup() {
    let cnv = createCanvas(900, 700, WEBGL);
    cnv.position(0,0);
    maxD = dist(0, 0, 450, 450);
}
                    
function draw() {
    background(245);
    ortho(-1250, 1250, -1250, 1250, -1400, 1400);
    translate(0,-100);
    directionalLight(200, 255, 200, 0, 0, -1);
    directionalLight(155, 155, 100, -1, 0, 0);
    rotateX(-QUARTER_PI);
    rotateY(-QUARTER_PI);

    for (let j=-900/2 + (blockSize*2); j<900-(blockSize*2); j+=blockSize) {
        for (let i=-900/2 + (blockSize*2); i<900-(blockSize*2); i+=blockSize) {
            push();
            let d = dist(i, j, 900/4, 900/4);
            let offset = map(d, 0, maxD, -offsetVariation, offsetVariation);
            let a = angle + offset;
            let h = map(sin(a), -1, 1 , 1, maxH);
            translate(i, 0, j);
            noStroke();
            ambientMaterial(255);
            box(blockSize, h, blockSize);
            pop();
         }
    }
    angle += angleVariation;
}

SMART  ROCKETS

Linguaggio: python3

Il secondo progetto che presento è incentrato su uno dei miei maggiori interessi: l'intelligenza artificiale. In questo caso, ho sviluppato un sistema basato su un algoritmo genetico per ottimizzare il comportamento di una serie di razzi. La simulazione inizia con una generazione di 100 razzi, ognuno con traiettorie di volo completamente casuali, che tentano di raggiungere la luna. Al termine del tempo prestabilito, i razzi vengono valutati in base alla loro prestazione. Successivamente, viene generata una nuova popolazione, derivata dai razzi con i risultati migliori, affinando così il comportamento di ogni generazione successiva

Simulazione

import asyncio
import pygame
import scripts.rocket as rocket
import scripts.gui as GUI
import scripts.obstacle as obstacle
import scripts.population as population
                        
#variable setup
population_size = 100
lifespan = 400
starting_point = [500.0-16.0, 750.0-32.0]
                        
#assets setup
lifespan_index = 0
population_array = population.Population(population_size, lifespan, starting_point)
generation_count = 1
target = obstacle.Obstacle([500.0-64.0, 32], 128, 128, True)
obstacles = obstacle.Obstacle([300.0, 350.0], 400, 16)


#pygame setup
pygame.init()
clock = pygame.time.Clock()
background = pygame.display.set_mode((1000, 750), pygame.SRCALPHA|pygame.SCALED, 32)
background.fill((0,0,0))
running = True

#populate the population
population_array.populate()

#main
async def main():
    
    global running
    global lifespan_index
    global generation_count
    count = 0

    while running:
        clock.tick(30)
        background.fill((0,0,0))
        population_array.manage_collision_whit(target)
        population_array.manage_collision_whit(obstacles)
        population_array.check_bounds(background)
        population_array.update_status()
        population_array.show(background)
        target.show(background)
        obstacles.show(background)

        #exit condition
        if pygame.event.get(pygame.QUIT):
            break
        if population_array.index==lifespan-1 or not population_array.is_population_alive():
            population_array.new_generation(target)
        await asyncio.sleep(0)
        GUI.update_GUI(background, population_array.index, population_array.generation_count, population_array.successful_rockets)
        pygame.display.update()

        #update loop variables
        population_array.index += 1


asyncio.run(main())

pygame.quit()

import pygame
import random
import scripts.rocket as rocket

class Population:
    def __init__(self, population_size = 0, lifespan = 0, starting_point:list = [0.0, 0.0]) -> None:
        self.size = population_size
        self.lifespan = lifespan
        self.rockets = []
        self.suitable_parents = []
        self.index = 0
        self.generation_count = 1
        self.starting_point = starting_point
        self.successful_rockets = 0

    def populate(self) -> None:
        for item in range(self.size):
            self.rockets.append(rocket.Rocket(self.lifespan, self.starting_point))

    def show(self, surface) -> None:
        for item in self.rockets:
            item.show(surface)

    def update_status(self) -> None:
        for item in self.rockets:
            item.update_status(self.index)

    def __normalize_fitness(self) -> None:
        best_fitness = 0
        for item in self.rockets:
            best_fitness = max(item.fitness, best_fitness)
        for item in self.rockets:
            item.fitness /= best_fitness

    def evaluate(self, target) -> None:
        for item in self.rockets:
            item.evaluate(target)
        self.__normalize_fitness()
        self.suitable_parents = []
        for item in self.rockets:
            index = round(item.fitness*100)
            for i in range(index):
                self.suitable_parents.append(item)
    
    def selection(self) -> rocket.Rocket:
        parent_a = random.choice(self.suitable_parents)
        parent_b = random.choice(self.suitable_parents)
        new_dna = parent_a.cross_dna(parent_b)
        new_rocket = rocket.Rocket(self.lifespan, self.starting_point, parent_dna=new_dna)
        new_rocket.dna.mutation()
        return new_rocket

    def new_generation(self, target) -> None:
        self.generation_count += 1
        self.index = 0
        self.evaluate(target)
        new_rockets = []
        for item in self.rockets:
            new_rockets.append(self.selection())
        self.rockets = new_rockets

    def manage_collision_whit(self, obstacle) -> None:
        self.successful_rockets = 0
        for item in self.rockets:
            item.check_object_hit(obstacle, self.index)
            if item.target_reached:
                self.successful_rockets += 1
    
    def check_bounds(self, surface) -> None:
        for item in self.rockets:
            item.check_bounds(surface)

    def is_population_alive(self) -> bool:
        alive = True
        for item in self.rockets:
            if item.crashed or item.target_reached:
                alive = False
            else:
                alive = True
                break
        return alive

import pygame
import numpy
import scripts.dna as dna

class Rocket:
    def __init__(self, lifespan:int = None, position:list = None, velocity:list = None, acceleration:list = None, parent_dna:list = None) -> None:
        if position == None:
            position = pygame.math.Vector2(0.0, 0.0)
        if velocity == None:
            velocity = pygame.math.Vector2(0.0, 0.0)
        if acceleration == None:
            acceleration = pygame.math.Vector2(0.0, 0.0)
        self.position = pygame.math.Vector2(position)
        self.velocity = pygame.math.Vector2(velocity)
        self.acceleration = pygame.math.Vector2(acceleration)
        self.direction = numpy.rad2deg(numpy.arctan2(*self.velocity))-180
        self.img = pygame.image.load('./assets/img/rocket_32.png')
        self.new_img = self.img
        self.lifespan = lifespan
        self.dna = dna.DNA(self.lifespan, parent_dna)
        self.rectangle = pygame.Rect(self.position[0], self.position[1], 32, 32)
        self.fitness = -1
        self.target_reached = False
        self.crashed = False
        self.time_to_reach = lifespan

    def update_velocity(self, value) -> None:
        self.velocity += value
    
    def update_position(self, value) -> None:
        self.position += value
    
    def update_acceleration(self, value) -> None:
        self.acceleration += value
    
    def update_direction(self) -> None:
        self.direction = numpy.rad2deg(numpy.arctan2(*self.velocity))-180

    def apply_force(self, force) -> None:
        self.update_acceleration(force)

    def check_object_hit(self, object, index) -> None:
        if self.rectangle.colliderect(object.rectangle) and object.is_target:
            self.target_reached = True
            self.position = object.position
            self.time_to_reach = self.lifespan - index
            self.rectangle = pygame.Rect(object.position.x, object.position.y, 32, 32)
        elif self.rectangle.colliderect(object.rectangle) and not object.is_target:
            self.crashed = True

    def check_bounds(self, surface) -> None:
        if not pygame.Rect(0, 0, surface.get_width(), surface.get_height()).collidepoint(self.position.x, self.position.y):
            self.crashed = True


    def update_status(self, genes_index) -> None:
        if not self.crashed and not self.target_reached:
            self.apply_force(self.dna.genes[genes_index])
            self.update_velocity(self.acceleration)
            self.update_position(self.velocity)
            self.acceleration = pygame.math.Vector2([0.0,0.0])
            self.update_direction()
            self.new_img = pygame.transform.rotate(self.img, self.direction)
            self.rectangle = pygame.Rect(self.position[0], self.position[1], 32, 32)

    def get_position(self) -> list:
        return [self.position.x, self.position.y]

    def show(self, surface) -> None:
        surface.blit(self.new_img, self.get_position())

    def new_dna(self, parent_dna = None) -> None:
        self.dna = dna.DNA(self.lifespan, parent_dna)

    def evaluate(self, target) -> None:
        if not self.target_reached:
            self.fitness = 1/(abs(self.position.distance_to(target.position)))
            if self.crashed:
                self.fitness /= 10
        else:
            self.fitness = 1*self.time_to_reach

    def cross_dna(self, other_rocket_b) -> list:
        return self.dna.cross(other_rocket_b.dna)

import pygame
import random

class DNA:
    def __init__(self, lifespan, parent_dna:list = None) -> None:
        self.lifespan = lifespan
        self.genes = []
        if parent_dna is None:
            for i in range(self.lifespan):
                self.genes.append(pygame.math.Vector2([random.uniform(-3.14,3.14)*0.5, random.uniform(-3.14, 3.14)*0.5]))
        else:
            self.genes = parent_dna

    def cross(self, other_dna_b) -> list:
        new_dna = []
        for gene_a, gene_b in zip(self.genes, other_dna_b.genes):
            rng_value = random.randint(1, 2)
            if (rng_value == 1):
                new_dna.append(gene_a)
            elif (rng_value == 2):
                new_dna.append(gene_b)
        return new_dna
    
    def mutation(self) -> None:
        for i in range(len(self.genes)):
            if random.uniform(0.0, 10.0)<0.65:
                self.genes[i] = pygame.math.Vector2([random.uniform(-3.14,3.14)*0.5, random.uniform(-3.14, 3.14)*0.5])

import pygame

class Obstacle:
    def __init__(self, position, size_x, size_y, is_target = False) -> None:
        self.position = pygame.math.Vector2(position)
        self.is_target = is_target
        if self.is_target:
            self.img = pygame.image.load("./assets/img/moon.png")
            self.img = pygame.transform.scale(self.img, [size_x, size_y])
        else:
            self.img = None
        self.rectangle = pygame.Rect(position[0], position[1], size_x, size_y)

    def get_position(self) -> list:
        return [self.position.x, self.position.y]
    
    def show(self, surface) -> None:
        if self.is_target:
            surface.blit(self.img, self.get_position())
        else:
            pygame.draw.rect(surface, pygame.Color(255,255,255), self.rectangle)

Primo assioma di Leo Beiser sui computer:
"Quando lo metti in memoria, ricordati dove lo metti."

CICLI  CICLABILI

Linguaggio: C++

Questo progetto è il risultato di un lavoro di gruppo composto da tre persone, svolto per il corso di Algoritmi e Strutture Dati presso l'università degli studi di Trento. L'obiettivo era, dato un file contenente un grafo e una serie di coppie di nodi, calcolare il percorso più breve tra i due nodi di ciascuna coppia e elaborare un file di output con i risultati. Dopo aver esplorato diverse soluzioni, abbiamo stabilito che il metodo ottimale consisteva nel trasformare il grafo in un albero e applicare la tecnica del Lowest Common Ancestor (LCA) per determinare la distanza tra i nodi richiesti. Questo progetto è significativo per me in quanto dimostra la mia capacità di collaborare efficacemente in un team e di affrontare problemi complessi in modo sistematico. Inoltre, è possibile consultare il PDF contenente le istruzioni originali, per avere una visione più chiara del compito assegnato e valutare il mio lavoro in maniera più completa.

Visualizza PDF
/**
* Cicli Ciclabili, main.cpp
* Obiettivo: dato un grafo ed una serie di coppie di nodi,
* calcolare il cammino più breve esistente tra i due nodi
* di ogni coppia
*
* @authors: M**** B****, I**** F****, Ottavio Franceschi
* @version: 3.0.0.3 12/12/2019 22:27
*/

#include <fstream>
#include <queue>
#include <vector>

using namespace std;

typedef struct Node {
    vector<int> adjacent;
    int level = -1;
    int parent = -1;
}Node;

vector<Node> graph;

void BreadthFirstSearch(int startingNode);
bool elementXisInVector(int X, vector<int>& ; vector);
int lowerCommonAncestor(int startingNode, int endingNode);

int main() {
    ifstream in("input.txt");
    ofstream out("output.txt");

    int INPUT_NODES_NUMBER, INPUT_ARCS_NUMBER, INPUT_REQUEST_NUMBER;
    in >> INPUT_NODES_NUMBER >> INPUT_ARCS_NUMBER >> INPUT_REQUEST_NUMBER;

    graph = vector<Node>(INPUT_NODES_NUMBER);

    for (int i=0; i<INPUT_ARCS_NUMBER; i++) {
        int fromNode, toNode;
        in >> fromNode >> toNode;
        graph[fromNode].adjacent.emplace_back(toNode);
        graph[toNode].adjacent.emplace_back(fromNode);
    }

    BreadthFirstSearch(0);

    for (int i=0; i<INPUT_REQUEST_NUMBER; i++) {
        int startingFrom, endingInto;
        in >> startingFrom >> endingInto;
        out << lowerCommonAncestor(startingFrom, endingInto) << endl;
    }
}

int lowerCommonAncestor(int startingNode, int endingNode) {
    int path = 0;
    int currentNodeFromStart = startingNode;
    while (graph[currentNodeFromStart].level > graph[endingNode].level) {
        currentNodeFromStart = graph[currentNodeFromStart].parent;
        path = path + 1;
    }
    int currentNodeFromEnd = endingNode;
    while (graph[currentNodeFromEnd].level > graph[startingNode].level) {
        currentNodeFromEnd = graph[currentNodeFromEnd].parent;
        path = path + 1;
    }

    while (currentNodeFromEnd != currentNodeFromStart) {
        if (elementXisInVector(currentNodeFromEnd, graph[currentNodeFromStart].adjacent))
            path = path - 1;
        currentNodeFromEnd = graph[currentNodeFromEnd].parent;
        currentNodeFromStart = graph[currentNodeFromStart].parent;
        path = path + 2;
    }

    return path;
}

void BreadthFirstSearch(int startingNode) {
    graph[startingNode].level=0;

    queue<int> nodesToEvaluate = queue<int>();
    nodesToEvaluate.emplace(startingNode);

    while(!nodesToEvaluate.empty()) {
        int currentNode = nodesToEvaluate.front();
        nodesToEvaluate.pop();
        for (int i=0; i<graph[currentNode].adjacent.size(); i++) {
            if (graph[graph[currentNode].adjacent[i]].level == -1) {
                graph[graph[currentNode].adjacent[i]].level = graph[currentNode].level + 1;
                graph[graph[currentNode].adjacent[i]].parent = currentNode;
                nodesToEvaluate.emplace(graph[currentNode].adjacent[i]);
            }
        }
    }
}

bool elementXisInVector(int X, vector<int>& vector) {
    for (int i : vector) {
        if (i == X) {
            return true;
        }
    }
    return false;
}


/**
* @changelog
* @version 4.0.0.0
* 95/100 è un buon risultato, ma si può fare meglio di così?
* Una soluzione (l'output 15) esce per via del tempo.
* Nei test, l'output 15 risulta corretto e impeiega solo 1,218 sec.
* Riguardando il codice non si trova nulla di tipo "mangia-tempo".
*
* @version 3.0.0.3(sottoposta 95/100)
* @date 12/12/2019 22:26
* Scartata l'idea di salvare la cricca nella struct. il controllo della cricca ora è nell'LCA (spostata sopra nel ciclo while).
*
* @version 3.0.0.2
* @date 12/12/2019
* Primo tentativo di implementare il riconoscimento delle cricche nella BFS;
* Aggiunta la funzione bool che controlla se due nodi sono nella stessa cricca.
*
* @version 3.0.0.1
* @date 12/12/2019 21:07
* Migliorato l'agoritmo LCA. Ora l'output è corretto. Si necessita ora solo il modo di individuare le cricche.
*
* @version 3.0.0.0 (sottoposta 0/100)
* @date 12/12/2019 20:49
* Scartata l'idea Irini-Albero perchè nessuno di noi sa risolvere il propblema dei pochi input errati;
* Rinumerate le versioni;
* Sviluppo e implementazione del "parente comune più vicino" (https://en.wikipedia.org/wiki/Lowest_common_ancestor).
*
* @version 2.0.0.0 (sottoposta 0/100)
* @date 10/12/2019 16:33
* Scartato l'agoritmo di Dijkstra perchè ci si è resi conto che funziona come erdos;
* Implementazione della nuova idea Irini-Albero (Si prende il nodo più connesso e si trattan i suoi vicini come radici di alberi diversi. Così basta chiamre erdos solo dal nodo iniziale).
* L'algoritmo riesce a completare in tempo più input di erdos, ma gli output risultano errati in un numero molto ridotto delle richieste. Da migliorare.
* Il problema sembrebbe essere nel nodo zero. Le richieste che coinvolgono quel nodo risultano errate di 1 -> ERRATA CORRIGE: quando prendo come nodo zero il nodo più connesso ho un certo errore in alcune richieste, se prendo un nodo a caso ho altri errori in altre richieste, ma le richieste non passano dal nodo zero.
*
*
* @version 1.0.1.2 (sottoposta 30/100)
* @date 09/12/2019 22:34
* Cambiato il tipo della coda nell'algoritmo di Dijkstra, da set ordinato senza copie a semplice queue
* poichè i nodi vengono inseriti nella coda già in base al livello (come in una BFS);
*
* @version 1.0.1.1 (non sottoposta)
* @date 09/12/2019 21:09
* Migliorato l'agoritmo di Dijkstra:
*  - rimosso l'operatore "==" del tipo Node (non utilizzato in std::set) e aggiornato l'operatore "<" (usato anche come "==" --> se a<b e b<a sono entrambi false allora a==b);
*  - errata corrige: l'operatore "==" non può essere rimosso altrimenti il codice non compila;
*
* @version 1.0.1.0 (non sottoposta)
* @date 09/12/2019 15:26
* Scartato l'utilizzo dell'algritmo di Erdos (Impega troppo tempo anche con le migliorie apportate);
* Sviluppo dell'algoritmo di Dijkstra.
* L'algoritmo di Dijkstra impega un tempo magiore di Erdos
*
*
* @version 1.0.0.0 (non sottoposta)
* @date 07/12/2019
* Algoritmo di Erdos migliorato:
*  - ora si ferma ad asseganre livelli quando arriva al nodo di arrivo,
*  - modificato il tipo da void ad int,
*  - il valore ritornato è il livello dell'endingNode (Nodo di arrivo);
*
* @version 0.0.0.2 (sottoposta 30/100)
* @date 05/12/2019 22:46
* Scartate le 2 versioni precendenti del codice (non funzionanti)
* basate su BreadthFirstSearch (la prima) e Erdos (la seconda);
* Riscritto il main();
* Creata una nuova funzione di Erdos;
* Resa globale la varaibile "graph".
*
* @version 0.0.0.1 (non sottoposta)
* @date n/d
* n/d
*
* @version 0.0.0.0 (non sottoposta)
* @date n/d
* n/d
*/

KNIFFEL

Linguaggio: Java

Questo progetto è nato dalla mia curiosità di sviluppare in Java un gioco da tavolo, Kniffel, che mia sorella mi aveva mostrato tempo fa. Il gioco ha un regolamento piuttosto semplice: si gioca con 5 dadi, cercando di ottenere il punteggio più alto contro uno o più avversari. Durante il gioco, i partecipanti devono realizzare specifiche combinazioni di dadi, ciascuna delle quali assegna un punteggio. Ogni combinazione può essere utilizzata una sola volta, e la partita termina dopo 13 turni di lancio, anche se non tutte le combinazioni sono state completate. Il mio obiettivo principale, oltre a implementare le regole di gioco, è stato rendere l'applicazione più flessibile, offrendo la possibilità di selezionare il numero di giocatori, inclusa un'opzione per giocare in solitaria.

package sample;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.util.Random;

public class Main extends Application {

    public static Player currentPlayer;
    public static Scene currentScene;

    @Override
    public void start(Stage primaryStage) {

        primaryStage.setTitle("Beatrix Dices");

        primaryStage.setOnCloseRequest(e -> {
            e.consume();
            Boxes.CHOICE("Do you want to quit?", "Yes", "No");
            if (Boxes.answer) {
                primaryStage.close();
            }
        });

        primaryStage.setScene(Menus.menu(primaryStage));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
package sample;

import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlurType;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Menus {
    public static int N=0;

    public static Scene menu(Stage parentStage) {
        Button start = new Button("New Game");
        start.setOnAction(e -> {
            parentStage.setScene(Menus.start(parentStage));
        });
        Button settings = new Button("Settings");
        Button rules = new Button("Rules");
        Button exit = new Button("Quit");
        exit.setOnAction(e -> {
            Boxes.CHOICE("Do you want to quit?", "Yes", "No");
            if (Boxes.answer) {
                parentStage.close();
            }
        });

        VBox menu = new VBox();
        menu.setAlignment(Pos.CENTER);
        menu.setSpacing(20);
        menu.getChildren().addAll(start, settings, rules, exit);
        Scene mainScene = new Scene(menu, 1200, 800);
        return mainScene;
    }

    public static Scene start(Stage parentStage) {
        Label n_player = new Label("How many players?");
        TextField inputField = new TextField();
        Dice dices[] = new Dice[5];
        for (int i=0; i<dices.length; i++) {
            dices[i] = new Dice(i+1);
        }

        Button confirm = new Button("Confirm");
        confirm.setOnAction(e -> {
            try {
                Starting.N = Integer.parseInt(inputField.getText());
                Player players[] = new Player[Starting.N];
                for (int i=0; i<players.length; i++) {
                    players[i] = new Player(i+1);
                }
                parentStage.setScene(players[0].getScene(parentStage, players, dices, 0));
            } catch (NumberFormatException exception) {
                Boxes.ALERT("Warning", inputField.getText() + " is not a valid integer umber");
            }
        });

        VBox choice = new VBox();
        choice.setAlignment(Pos.CENTER);
        choice.setSpacing(20);
        choice.getChildren().addAll(n_player, inputField, confirm);

        Scene result = new Scene(choice, 1200, 800);

        return result;
    }

    public static Scene gameOver(Stage parentStage, Player[] players) {
        for (int i=0; i<players.length; i++) {
            if (players[i].getTopScore() >= 63) {
                players[i].addScore(35);
            }
        }

        Label end = new Label("THE GAME IS OVER");
        List<Player> sortedPlayers = Arrays.asList(players);
        sortedPlayers.sort(new byScore());

        Button newGame = new Button("Play again");
        newGame.setOnAction(e -> {
            parentStage.setScene(Menus.start(parentStage));
        });
        Button quit = new Button("Quit");
        quit.setOnAction(e -> {
            Boxes.CHOICE("Do you want to quit?", "Yes", "No");
            if(Boxes.answer)
                parentStage.close();
        });
        HBox btns = new HBox();
        btns.setSpacing(50);
        btns.setAlignment(Pos.CENTER);
        btns.getChildren().addAll(newGame, quit);

        Label[] points = new Label[sortedPlayers.size()];
        for (int i=sortedPlayers.size()-1; i>=0; i--) {
            Player currentPlayer = sortedPlayers.get(i);
            int position = i+1;
            points[i] = new Label(position + "- " + currentPlayer.getName() + " score: " + currentPlayer.getTotalScore());
        }

        VBox names = new VBox();
        names.setAlignment(Pos.CENTER);
        names.setSpacing(20);
        names.getChildren().add(end);
        for (Label point : points) {
            names.getChildren().add(point);
        }
        names.getChildren().add(btns);

        BorderPane root = new BorderPane();
        root.setCenter(names);

        return new Scene(root, 1200, 800);

    }
}
package sample;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.util.*;

public class Player {
    private String name;
    private int topScore;
    private int totalScore;
    private ArrayList<PointCombo> toDoList = new ArrayList<>();
    private ArrayList<PointCombo> doneList = new ArrayList<>();
    private ArrayList<PointCombo> lostList = new ArrayList<>();
    public ArrayList<PointCombo> chooseList = new ArrayList<>();
    private int rollsLeft;

    public Player(int n) {
        Stage playerInfo = new Stage();
        playerInfo.setTitle("Insert Player info");
        playerInfo.initModality(Modality.APPLICATION_MODAL);
        playerInfo.setOnCloseRequest(e -> {
            e.consume();
            Boxes.ALERT("Warning", "Must insert player info");
        });

        Label name = new Label("Insert player " + n + " name:");
        TextField inputName = new TextField();

        Button confirm = new Button("Confirm");
        confirm.setOnAction(e -> {
            try {
                this.name = inputName.getText();
                if (this.name.length() == 0) {
                    throw new Exception();
                }
                this.totalScore = 0;
                this.topScore = 0;
                this.getToDoList().add(new PointCombo(Combos.ones, 0));
                this.getToDoList().add(new PointCombo(Combos.twos, 0));
                this.getToDoList().add(new PointCombo(Combos.threes, 0));
                this.getToDoList().add(new PointCombo(Combos.fours, 0));
                this.getToDoList().add(new PointCombo(Combos.fives, 0));
                this.getToDoList().add(new PointCombo(Combos.sixs, 0));
                this.getToDoList().add(new PointCombo(Combos.tris, 0));
                this.getToDoList().add(new PointCombo(Combos.poker, 0));
                this.getToDoList().add(new PointCombo(Combos.small_road, 0));
                this.getToDoList().add(new PointCombo(Combos.big_road, 0));
                this.getToDoList().add(new PointCombo(Combos.full, 0));
                this.getToDoList().add(new PointCombo(Combos.pokerer, 0));
                this.getToDoList().add(new PointCombo(Combos.possibility, 0));
                this.rollsLeft = 2;
                playerInfo.close();
            } catch (Exception ex) {
                Boxes.ALERT("Wanring", "Must have a name");
            }
        });

        VBox main = new VBox();

        main.getChildren().addAll(name, inputName, confirm);
        main.setSpacing(10);
        main.setAlignment(Pos.CENTER);
        main.setPadding(new Insets(10, 10, 10, 10));

        Scene scene = new Scene(main, 400, 300);
        playerInfo.setScene(scene);
        playerInfo.showAndWait();

    }

    public Player(String name, int score) {
        this.setName(name);
        this.totalScore = score;
        this.topScore = 0;
        this.getToDoList().add(new PointCombo(Combos.ones, 0));
        this.getToDoList().add(new PointCombo(Combos.twos, 0));
        this.getToDoList().add(new PointCombo(Combos.threes, 0));
        this.getToDoList().add(new PointCombo(Combos.fours, 0));
        this.getToDoList().add(new PointCombo(Combos.fives, 0));
        this.getToDoList().add(new PointCombo(Combos.sixs, 0));
        this.getToDoList().add(new PointCombo(Combos.tris, 0));
        this.getToDoList().add(new PointCombo(Combos.poker, 0));
        this.getToDoList().add(new PointCombo(Combos.small_road, 0));
        this.getToDoList().add(new PointCombo(Combos.big_road, 0));
        this.getToDoList().add(new PointCombo(Combos.full, 0));
        this.getToDoList().add(new PointCombo(Combos.pokerer, 0));
        this.getToDoList().add(new PointCombo(Combos.possibility, 0));
        this.rollsLeft = 3;
    }

    public void addScore(int score) {
        this.totalScore += score;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getTopScore() {
        return topScore;
    }

    public int getTotalScore() {
        return totalScore;
    }

    public String getName() {
        return name;
    }

    public ArrayList<PointCombo> getToDoList() {
        return toDoList;
    }

    public ArrayList<PointCombo> getDoneList() {
        return doneList;
    }

    public int getRollsLeft() {
        return rollsLeft;
    }

    public ArrayList<PointCombo> getLostList() {
        return lostList;
    }

    public void setRollsLeft(int rollsLeft) {
        this.rollsLeft = rollsLeft;
    }

    public boolean checkBonus() {
        return this.getTopScore() >= 63;
    }

    public Scene getScene(Stage parentStage, Player[] player, Dice[] dices, int playerNumber) {
        System.out.println(this.getToDoList().size() == 0);
        if (this.getToDoList().size() == 0) {
            return Menus.gameOver(parentStage, player);
        }
        BorderPane mainPane = new BorderPane();
        VBox left = new VBox();
        VBox right = new VBox();
        HBox bottom = new HBox();
        GridPane showDices = new GridPane();

        Random rnd = new Random(System.currentTimeMillis());
        for (int i = 0; i < dices.length; i++) {
            if (!dices[i].isHold()) {
                dices[i].setValue(rnd.nextInt(6 - 1 + 1) + 1);
            } else {
                dices[i].setValue(dices[i].getValue());
            }
        }

        Label showName = new Label(this.name);
        showName.setAlignment(Pos.CENTER);
        showName.setPadding(new Insets(10, 10, 10, 10));
        StackPane name = new StackPane();
        name.getChildren().add(showName);

        mainPane.setTop(name);

        Button stop = new Button("Check combos");
        stop.setOnAction(event -> {
            this.setRollsLeft(2);
            this.showCombos(this, dices);
            Dice.resetDices(dices);
            parentStage.setScene(player[(playerNumber+1)%player.length].getScene(parentStage, player, dices, (playerNumber+1)%player.length));
        });
        Button roll = new Button("Re-Roll (" + this.getRollsLeft() + " left)");
        roll.setOnAction(event -> {
            if (this.getRollsLeft() > 0) {
                this.setRollsLeft(this.getRollsLeft() - 1);
                parentStage.setScene(getScene(parentStage, player, dices, playerNumber));
            } else {
                this.setRollsLeft(2);
                this.showCombos(this, dices);
                Dice.resetDices(dices);
                parentStage.setScene(player[(playerNumber+1)%player.length].getScene(parentStage, player, dices, (playerNumber+1)%player.length));
            }
        });
        bottom.getChildren().addAll(roll, stop);
        bottom.setAlignment(Pos.CENTER);
        bottom.setSpacing(50);
        bottom.setPadding(new Insets(20, 20, 20, 20));


        mainPane.setBottom(bottom);

        Label showScore = new Label("Total Score:");
        Label showInt = new Label("" + this.totalScore);
        Label showBonus = new Label("Bonus related score :");
        Label showIntBonus = new Label("" + this.topScore);

        left.getChildren().addAll(showScore, showInt, showBonus, showIntBonus);
        left.setAlignment(Pos.CENTER);
        left.setSpacing(10);

        mainPane.setLeft(left);

        Label toDo = new Label("To Do Combos:");
        Label done = new Label("Combos Done:");
        Label lost = new Label("Lost Combos:");

        ListView<PointCombo> toDoListView = new ListView<>();
        for (PointCombo combo : this.getToDoList()) {
            toDoListView.getItems().add(combo);
        }
        ListView<PointCombo%gt doneListView = new ListView<>();
        for (PointCombo combo : this.getDoneList()) {
            doneListView.getItems().add(combo);
        }
        ListView<PointCombo> lostListView = new ListView<>();
        for (PointCombo combo : this.getLostList()) {
            lostListView.getItems().add(combo);
        }

        right.getChildren().addAll(toDo, toDoListView, done, doneListView, lost, lostListView);
        right.setAlignment(Pos.CENTER);
        right.setSpacing(10);

        mainPane.setRight(right);

        Node[] getDices = new StackPane[6];
        for (int i = 0; i < dices.length; i++) {
            getDices[i] = dices[i].show();
        }

        ColumnConstraints col0 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);
        ColumnConstraints col1 = new ColumnConstraints(150);
        col0.setHgrow(Priority.NEVER);
        ColumnConstraints col2 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);
        ColumnConstraints col3 = new ColumnConstraints(150);
        col0.setHgrow(Priority.NEVER);
        ColumnConstraints col4 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);
        ColumnConstraints col5 = new ColumnConstraints(150);
        col0.setHgrow(Priority.NEVER);
        ColumnConstraints col6 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);
        ColumnConstraints col7 = new ColumnConstraints(150);
        col0.setHgrow(Priority.NEVER);
        ColumnConstraints col8 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);
        ColumnConstraints col9 = new ColumnConstraints(150);
        col0.setHgrow(Priority.NEVER);
        ColumnConstraints col10 = new ColumnConstraints(10);
        col0.setHgrow(Priority.ALWAYS);

        RowConstraints row0 = new RowConstraints(10);
        row0.setVgrow(Priority.ALWAYS);
        RowConstraints row1 = new RowConstraints(150);
        row0.setVgrow(Priority.NEVER);
        RowConstraints row2 = new RowConstraints(10);
        row0.setVgrow(Priority.ALWAYS);
        RowConstraints row3 = new RowConstraints(150);
        row0.setVgrow(Priority.NEVER);
        RowConstraints row4 = new RowConstraints(10);
        row0.setVgrow(Priority.ALWAYS);

        showDices.getColumnConstraints().addAll(col0, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10);
        showDices.getRowConstraints().addAll(row0, row1, row2, row3, row4);
        showDices.setAlignment(Pos.CENTER);

        GridPane.setConstraints(getDices[0], 1, 1);
        GridPane.setConstraints(getDices[1], 3, 3);
        GridPane.setConstraints(getDices[2], 5, 1);
        GridPane.setConstraints(getDices[3], 7, 3);
        GridPane.setConstraints(getDices[4], 9, 1);

        showDices.getChildren().addAll(getDices[0], getDices[1], getDices[2], getDices[3], getDices[4]);
        mainPane.setCenter(showDices);

        return new Scene(mainPane, 1200, 800);
    }

    public void showCombos(Player currentPlayer, Dice[] dices) {
        Stage comboStage = new Stage();
        comboStage.setTitle("Combos");
        comboStage.initModality(Modality.APPLICATION_MODAL);
        comboStage.setOnCloseRequest(e -> {
            e.consume();
            Boxes.ALERT("Warning", "Choose a combo");
        });
        boolean none = checkCombos(currentPlayer, dices);

        if (none) {
            comboStage.setScene(this.noneCombos(comboStage, currentPlayer, dices));
        } else {
            comboStage.setScene(this.someCombos(comboStage, currentPlayer, dices));
        }

        comboStage.showAndWait();
    }

    private Scene noneCombos(Stage parentStage, Player currentPlayer, Dice[] dices) {
        ListView<PointCombo> lost = new ListView<>();
        for(PointCombo combo : this.getToDoList()) {
            lost.getItems().add(combo);
        }
        Button loseBtn = new Button("Lose this combo");
        loseBtn.setOnAction(e -> {
            PointCombo lostCombo = lost.getSelectionModel().getSelectedItem();
            currentPlayer.getToDoList().remove(lostCombo);
            currentPlayer.getLostList().add(lostCombo);
            currentPlayer.chooseList.clear();
            parentStage.close();
        });

        VBox root = new VBox();
        root.setSpacing(10);
        root.setAlignment(Pos.CENTER);
        root.getChildren().addAll(lost, loseBtn);

        return new Scene(root, 800, 600);
    }

    private Scene someCombos(Stage parentStage, Player currentPlayer, Dice[] dices) {
        ListView<PointCombo> chooseCombos = new ListView<>();
        for(PointCombo combo : chooseList) {
            chooseCombos.getItems().add(combo);
        }
        Button chooseThis = new Button("Choose this");
        chooseThis.setOnAction(e -> {
            PointCombo choosen = chooseCombos.getSelectionModel().getSelectedItem();
            currentPlayer.getDoneList().add(choosen);
            currentPlayer.getToDoList().remove(choosen);
            currentPlayer.addScore(choosen.getComboScore());
            if (choosen.equals(new PointCombo(Combos.ones, 0)) || choosen.equals(new PointCombo(Combos.twos, 0)) || choosen.equals(new PointCombo(Combos.threes, 0)) || choosen.equals(new PointCombo(Combos.fours, 0)) || choosen.equals(new PointCombo(Combos.fives, 0)) || choosen.equals(new PointCombo(Combos.sixs, 0))) {
                currentPlayer.addTopScore(choosen.getComboScore());
            }
            currentPlayer.chooseList.clear();
            parentStage.close();
        });
        Button lose = new Button("Lose a combo");
        lose.setOnAction(e -> {
            parentStage.setScene(this.noneCombos(parentStage, currentPlayer, dices));
        });
        HBox btns = new HBox();
        btns.setAlignment(Pos.CENTER);
        btns.setSpacing(50);
        btns.getChildren().addAll(chooseThis, lose);

        VBox main = new VBox();
        main.setAlignment(Pos.CENTER);
        main.setSpacing(10);
        main.getChildren().addAll(chooseCombos, btns);

        return new Scene(main, 800, 600);
    }

    private void addTopScore(int comboScore) {
        this.topScore += comboScore;
    }

    private boolean checkCombos(Player currentPlayer, Dice[] dices) {
        boolean ones = Player.hasOnes(currentPlayer, dices);
        if (ones) {
            int value = Dice.howMany(dices, 1);
            currentPlayer.chooseList.add(new PointCombo(Combos.ones, value));
        }
        boolean twos = Player.hasTwos(currentPlayer, dices);
        if (twos) {
            int value = Dice.howMany(dices, 2);
            currentPlayer.chooseList.add(new PointCombo(Combos.twos, value));
        }
        boolean threes = Player.hasThrees(currentPlayer, dices);
        if (threes) {
            int value = Dice.howMany(dices, 3);
            currentPlayer.chooseList.add(new PointCombo(Combos.threes, value));
        }
        boolean fours = Player.hasFours(currentPlayer, dices);
        if (fours) {
            int value = Dice.howMany(dices, 4);
            currentPlayer.chooseList.add(new PointCombo(Combos.fours, value));
        }
        boolean fives = Player.hasFives(currentPlayer, dices);
        if (fives) {
            int value = Dice.howMany(dices, 5);
            currentPlayer.chooseList.add(new PointCombo(Combos.fives, value));
        }
        boolean sixs = Player.hasSixes(currentPlayer, dices);
        if (sixs) {
            int value = Dice.howMany(dices, 6);
            currentPlayer.chooseList.add(new PointCombo(Combos.sixs, value));
        }


        boolean tris = Player.hasTris(currentPlayer, dices);
        if (tris)
            currentPlayer.chooseList.add(new PointCombo(Combos.tris, Dice.sumValue(dices)));
        boolean poker = Player.hasPoker(currentPlayer, dices);
        if (poker)
            currentPlayer.chooseList.add(new PointCombo(Combos.poker, Dice.sumValue(dices)));
        boolean small_road = Player.hasSmallRoad(currentPlayer, dices);
        if (small_road)
            currentPlayer.chooseList.add(new PointCombo(Combos.small_road, 30));
        boolean big_road = Player.hasBigRoad(currentPlayer, dices);
        if (big_road)
            currentPlayer.chooseList.add(new PointCombo(Combos.big_road, 40));
        boolean full = Player.hasFull(currentPlayer, dices);
        if (full)
            currentPlayer.chooseList.add(new PointCombo(Combos.full, 25));
        boolean superpoker = Player.hasSuperpoker(currentPlayer, dices);
        if (superpoker)
            currentPlayer.chooseList.add(new PointCombo(Combos.pokerer, 50));
        boolean possibility = Player.hasPossibility(currentPlayer, dices);
        if (possibility)
            currentPlayer.chooseList.add(new PointCombo(Combos.possibility, Dice.sumValue(dices)));

        return !(ones || twos || threes || fours || fives || sixs || tris || poker || small_road || big_road || full || superpoker || possibility);
    }

    private static boolean hasOnes(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.ones, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.ones, 0))) {
            return false;
        }

        return dices[0].getValue() == 1 || dices[1].getValue() == 1 || dices[2].getValue() == 1 || dices[3].getValue() == 1 || dices[4].getValue() == 1;
    }

    private static boolean hasTwos(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.twos, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.twos, 0))) {
            return false;
        }

        return dices[0].getValue() == 2 || dices[1].getValue() == 2 || dices[2].getValue() == 2 || dices[3].getValue() == 2 || dices[4].getValue() == 2;
    }

    private static boolean hasThrees(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.threes, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.threes, 0))) {
            return false;
        }

        return dices[0].getValue() == 3 || dices[1].getValue() == 3 || dices[2].getValue() == 3 || dices[3].getValue() == 3 || dices[4].getValue() == 3;
    }

    private static boolean hasFours(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.fours, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.fours, 0))) {
            return false;
        }

        return dices[0].getValue() == 4 || dices[1].getValue() == 4 || dices[2].getValue() == 4 || dices[3].getValue() == 4 || dices[4].getValue() == 4;
    }

    private static boolean hasFives(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.fives, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.fives, 0))) {
            return false;
        }

        return dices[0].getValue() == 5 || dices[1].getValue() == 5 || dices[2].getValue() == 5 || dices[3].getValue() == 5 || dices[4].getValue() == 5;
    }

    private static boolean hasSixes(Player currentPlayer, Dice[] dices) {
        if(currentPlayer.getDoneList().contains(new PointCombo(Combos.sixs, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.sixs, 0))) {
            return false;
        }

        return dices[0].getValue() == 6 || dices[1].getValue() == 6 || dices[2].getValue() == 6 || dices[3].getValue() == 6 || dices[4].getValue() == 6;
    }

    private static boolean hasTris(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.tris, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.tris, 0))) {
            return false;
        }

        for (int number = 1; number<=6; number++) {
            int count = 0;
            for (Dice dice : dices) {
                if (dice.getValue() == number)
                    count += 1;
                if (count == 3)
                    return true;
            }
        }

        return false;
    }

    private static boolean hasPoker(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.poker, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.poker, 0))) {
            return false;
        }

        for (int number = 1; number<=6; number++) {
            int count = 0;
            for (Dice dice : dices) {
                if (dice.getValue() == number)
                    count += 1;
                if (count == 4)
                    return true;
            }
        }

        return false;
    }

    private static boolean hasSuperpoker(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.pokerer, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.pokerer, 0))) {
            return false;
        }

        return dices[0].getValue() == dices[1].getValue() && dices[1].getValue() == dices[2].getValue() && dices[2].getValue() == dices[3].getValue() && dices[3].getValue() == dices[4].getValue();
    }

    //Ogni tanto non trova la small road. La causa?
    private static boolean hasSmallRoad(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.small_road, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.small_road, 0))) {
            return false;
        }

        List<Dice> sortedDices = new ArrayList<Dice>(Arrays.asList(dices));

        boolean result = true;
        for (int i=0; i<sortedDices.size()-2; i++) {
            if (sortedDices.get(i).getValue() != sortedDices.get(i+1).getValue()-1) {
                result = false;
                break;
            }
        }
        if (!result) {
            for (int i=1; i<sortedDices.size()-1; i++) {
                if (sortedDices.get(i).getValue() != sortedDices.get(i+1).getValue()-1) {
                    result = false;
                    break;
                }
            }
        }
        if (!result) {
            System.out.println(sortedDices.size() + " size1 in remove");
            for (int i = 0; i < sortedDices.size() - 1; i++) {
                if (sortedDices.get(i).getValue() == sortedDices.get(i + 1).getValue()) {
                    System.out.println("Before RMV");
                    sortedDices.remove(i);
                    System.out.println("After RMV");
                    break;
                }
            }
            if (sortedDices.size() == 4) {
                System.out.println(sortedDices.size() + " size2");
                for (int i = sortedDices.size() - 1; i >= 1; i--) {
                    if (!(dices[i].getValue() == dices[i - 1].getValue() + 1)) {
                        return false;
                    }
                }
            }
        }

        return true;
    }

    private static boolean hasBigRoad(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.big_road, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.big_road, 0))) {
            return false;
        }

        List<Dice> sortedDices = Arrays.asList(dices);
        sortedDices.sort(new byValue());

        for(int i=sortedDices.size()-1; i>=1; i--) {
            if(!(dices[i].getValue() == dices[i-1].getValue()+1)) {
                return false;
            }
        }
        return true;
    }

    //TO-DO
    private static boolean hasFull(Player currentPlayer, Dice[] dices) {
        if (currentPlayer.getDoneList().contains(new PointCombo(Combos.full, 0)) || currentPlayer.getLostList().contains(new PointCombo(Combos.full, 0))) {
            return false;
        }

        List<Dice> sortedDices = Arrays.asList(dices);
        sortedDices.sort(new byValue());

        boolean small_full = sortedDices.get(0).getValue() == sortedDices.get(1).getValue() && sortedDices.get(1).getValue() == sortedDices.get(2).getValue() && sortedDices.get(3).getValue() == sortedDices.get(4).getValue();
        boolean big_full = sortedDices.get(2).getValue() == sortedDices.get(3).getValue() && sortedDices.get(3).getValue() == sortedDices.get(4).getValue() && sortedDices.get(0).getValue() == sortedDices.get(1).getValue();
        return small_full || big_full;
    }

    private static boolean hasPossibility(Player currentPlayer, Dice[] dices) {
        return currentPlayer.getToDoList().contains(new PointCombo(Combos.possibility, 0)) && !currentPlayer.getLostList().contains(new PointCombo(Combos.possibility, 0));
    }
}
package sample;

import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

public class Dice {
    private int value;
    private boolean hold = false;
    final static private Border blackBorder = new Border(new BorderStroke(Color.BLACK, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT));
    final static private Border redBorder = new Border(new BorderStroke(Color.RED, BorderStrokeStyle.DASHED, CornerRadii.EMPTY, BorderWidths.DEFAULT));

    public Dice (int value) {
        this.value = value;
    }

    public Node show() {
        StackPane figure = new StackPane();
        if (!this.hold) {
            figure.setBorder(Dice.blackBorder);
        } else {
            figure.setBorder(Dice.redBorder);
        }

        switch (this.value) {
            case 1: {
                Circle num = new Circle(10);
                num.setFill(Color.BLUE);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(num);
                break;
            }
            case 2: {
                GridPane grid = new GridPane();
                grid.getColumnConstraints().addAll(new ColumnConstraints(50), new ColumnConstraints(50), new ColumnConstraints(50));
                grid.getRowConstraints().addAll(new RowConstraints(50), new RowConstraints(50), new RowConstraints(50));

                BorderPane container1 = new BorderPane();
                Circle num1 = new Circle(10);
                num1.setFill(Color.RED);

                BorderPane container2 = new BorderPane();
                Circle num2 = new Circle(10);
                num2.setFill(Color.RED);

                container1.setCenter(num1);
                container2.setCenter(num2);

                GridPane.setConstraints(container1, 0, 0);
                GridPane.setConstraints(container2, 2, 2);
                grid.getChildren().addAll(container1, container2);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(grid);
                break;
            }
            case 3: {
                GridPane grid = new GridPane();
                grid.getColumnConstraints().addAll(new ColumnConstraints(50), new ColumnConstraints(50), new ColumnConstraints(50));
                grid.getRowConstraints().addAll(new RowConstraints(50), new RowConstraints(50), new RowConstraints(50));

                BorderPane container1 = new BorderPane();
                Circle num1 = new Circle(10);
                num1.setFill(Color.BLUE);

                BorderPane container2 = new BorderPane();
                Circle num2 = new Circle(10);
                num2.setFill(Color.BLUE);

                BorderPane container3 = new BorderPane();
                Circle num3 = new Circle(10);
                num3.setFill(Color.BLUE);

                container1.setCenter(num1);
                container2.setCenter(num2);
                container3.setCenter(num3);

                GridPane.setConstraints(container1, 0, 0);
                GridPane.setConstraints(container2, 1, 1);
                GridPane.setConstraints(container3, 2, 2);
                grid.getChildren().addAll(container1, container2, container3);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(grid);
                break;
            }
            case 4: {
                GridPane grid = new GridPane();
                grid.getColumnConstraints().addAll(new ColumnConstraints(50), new ColumnConstraints(50), new ColumnConstraints(50));
                grid.getRowConstraints().addAll(new RowConstraints(50), new RowConstraints(50), new RowConstraints(50));

                BorderPane container1 = new BorderPane();
                Circle num1 = new Circle(10);
                num1.setFill(Color.RED);

                BorderPane container2 = new BorderPane();
                Circle num2 = new Circle(10);
                num2.setFill(Color.RED);

                BorderPane container3 = new BorderPane();
                Circle num3 = new Circle(10);
                num3.setFill(Color.RED);

                BorderPane container4 = new BorderPane();
                Circle num4 = new Circle(10);
                num4.setFill(Color.RED);

                container1.setCenter(num1);
                container2.setCenter(num2);
                container3.setCenter(num3);
                container4.setCenter(num4);

                GridPane.setConstraints(container1, 0, 0);
                GridPane.setConstraints(container2, 2, 0);
                GridPane.setConstraints(container3, 2, 2);
                GridPane.setConstraints(container4, 0, 2);
                grid.getChildren().addAll(container1, container2, container3, container4);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(grid);
                break;
            }
            case 5: {
                GridPane grid = new GridPane();
                grid.getColumnConstraints().addAll(new ColumnConstraints(50), new ColumnConstraints(50), new ColumnConstraints(50));
                grid.getRowConstraints().addAll(new RowConstraints(50), new RowConstraints(50), new RowConstraints(50));

                BorderPane container1 = new BorderPane();
                Circle num1 = new Circle(10);
                num1.setFill(Color.BLUE);

                BorderPane container2 = new BorderPane();
                Circle num2 = new Circle(10);
                num2.setFill(Color.BLUE);

                BorderPane container3 = new BorderPane();
                Circle num3 = new Circle(10);
                num3.setFill(Color.BLUE);

                BorderPane container4 = new BorderPane();
                Circle num4 = new Circle(10);
                num4.setFill(Color.BLUE);

                BorderPane container5 = new BorderPane();
                Circle num5 = new Circle(10);
                num5.setFill(Color.BLUE);

                container1.setCenter(num1);
                container2.setCenter(num2);
                container3.setCenter(num3);
                container4.setCenter(num4);
                container5.setCenter(num5);

                GridPane.setConstraints(container1, 0, 0);
                GridPane.setConstraints(container2, 2, 0);
                GridPane.setConstraints(container3, 2, 2);
                GridPane.setConstraints(container4, 0, 2);
                GridPane.setConstraints(container5, 1, 1);
                grid.getChildren().addAll(container1, container2, container3, container4, container5);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(grid);
                break;
            }
            case 6: {
                GridPane grid = new GridPane();
                grid.getColumnConstraints().addAll(new ColumnConstraints(50), new ColumnConstraints(50), new ColumnConstraints(50));
                grid.getRowConstraints().addAll(new RowConstraints(50), new RowConstraints(50), new RowConstraints(50));

                BorderPane container1 = new BorderPane();
                Circle num1 = new Circle(10);
                num1.setFill(Color.RED);

                BorderPane container2 = new BorderPane();
                Circle num2 = new Circle(10);
                num2.setFill(Color.RED);

                BorderPane container3 = new BorderPane();
                Circle num3 = new Circle(10);
                num3.setFill(Color.RED);

                BorderPane container4 = new BorderPane();
                Circle num4 = new Circle(10);
                num4.setFill(Color.RED);

                BorderPane container5 = new BorderPane();
                Circle num5 = new Circle(10);
                num5.setFill(Color.RED);

                BorderPane container6 = new BorderPane();
                Circle num6 = new Circle(10);
                num6.setFill(Color.RED);

                container1.setCenter(num1);
                container2.setCenter(num2);
                container3.setCenter(num3);
                container4.setCenter(num4);
                container5.setCenter(num5);
                container6.setCenter(num6);

                GridPane.setConstraints(container1, 0, 0);
                GridPane.setConstraints(container2, 2, 0);
                GridPane.setConstraints(container3, 2, 2);
                GridPane.setConstraints(container4, 0, 2);
                GridPane.setConstraints(container5, 0, 1);
                GridPane.setConstraints(container1, 2, 1);
                grid.getChildren().addAll(container1, container2, container3, container4, container5, container6);

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(grid);
                break;
            }
            default: {
                Label error = new Label("Error in Dice.show()\nNo value matching\nswitch statement");

                figure.setAlignment(Pos.CENTER);
                figure.getChildren().add(error);

            }
        }

        figure.setOnMouseClicked(mouseEvent -> {
            if (this.hold) {
                this.hold = false;
                figure.setBorder(Dice.blackBorder);
            } else {
                this.hold = true;
                figure.setBorder(Dice.redBorder);
            }
        });
        return figure;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public boolean isHold() {
        return hold;
    }

    public static int howMany(Dice[] dices, int number) {
        int count = 0;
        for (Dice d : dices) {
            if (d.getValue() == number)
                count += 1;
        }

        return number*count;
    }

    public static int sumValue(Dice[] dices) {
        int sum = 0;
        for (Dice d : dices) {
            sum += d.getValue();
        }
        return sum;
    }

    public static void resetDices(Dice[] dices) {
        for(int i=0; i<dices.length; i++) {
            dices[i].hold = false;
        }
    }
}
package sample;

public enum Combos {
    ones,
    twos,
    threes,
    fours,
    fives,
    sixs,

    tris,
    poker,
    small_road,
    big_road,
    full,
    pokerer,
    possibility;

    @Override
    public String toString() {
        switch (this) {
            case ones: return "Ones";
            case twos: return "Twoes";
            case threes: return "Threes";
            case fours: return "Fours";
            case fives: return "Fives";
            case sixs: return "Sixs";
            case tris: return "Tris";
            case poker: return "Poker";
            case small_road: return "Small Road";
            case big_road: return "Big Road";
            case full: return "Full House";
            case pokerer: return "Super-Poker";
            case possibility: return "Possibility";
            default: return "Error in Combos.toString()\nNo matching found\nin switch statement";
        }
    }
}
package sample;

import java.util.Objects;

public class PointCombo {
    private Combos combo;
    private int comboScore;

    public PointCombo (Combos combo, int comboScore) {
        this.combo = combo;
        this.comboScore = comboScore;
    }

    public PointCombo (Combos combo) {
        this.combo = combo;
    }

    public Combos getCombo() {
        return this.combo;
    }

    public int getComboScore() {
        return this.comboScore;
    }

    @Override
    public int hashCode() {
        return Objects.hash(combo);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PointCombo that = (PointCombo) o;
        return combo == that.combo;
    }

    @Override
    public String toString() {
        return combo.toString() + " " + comboScore;
    }
}
package sample;

import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class Boxes {
    static boolean answer = false;

    public static void ALERT(String title, String message) {
        Stage alertStage = new Stage();
        alertStage.setTitle(title);
        alertStage.initModality(Modality.APPLICATION_MODAL);

        Label msg= new Label(message);

        StackPane layout = new StackPane();
        layout.getChildren().add(msg);

        Scene scene = new Scene(layout, 300, 200, Color.RED);

        alertStage.setScene(scene);
        alertStage.showAndWait();
    }

    public static void CHOICE(String question, String trueAns, String falseAns) {
        Stage choiceStage = new Stage();
        choiceStage.setTitle("Warning");
        choiceStage.initModality(Modality.APPLICATION_MODAL);

        Label qst = new Label(question);
        Button trueBtn = new Button(trueAns);
        trueBtn.setOnAction(e -> {
            Boxes.answer = true;
            choiceStage.close();
        });
        Button falseBtn = new Button(falseAns);
        falseBtn.setOnAction(e -> {
            Boxes.answer = false;
            choiceStage.close();
        });

        HBox buttons = new HBox();
        buttons.setSpacing(50);
        buttons.setAlignment(Pos.CENTER);
        buttons.getChildren().addAll(trueBtn, falseBtn);

        VBox main = new VBox();
        main.setAlignment(Pos.CENTER);
        main.setSpacing(10);
        main.getChildren().addAll(qst, buttons);

        Scene scene = new Scene(main, 300, 200, Color.RED);
        choiceStage.setScene(scene);
        choiceStage.showAndWait();

    }
}
package sample;

import java.util.Comparator;

public class byScore implements Comparator<Player> {

    @Override
    public int compare(Player o1, Player o2) {
        return o2.getTotalScore() - o1.getTotalScore();
    }
}
package sample;

import java.util.Comparator;

public class byValue implements Comparator<Dice> {

    @Override
    public int compare(Dice o1, Dice o2) {
        return o1.getValue() - o2.getValue();
    }
}

Terza legge di Greer:
"Un computer fa quello che gli dici, non quello che vuoi."

CUBE  RUN

Linguaggio: C#

Questo progetto, sviluppato con Unity, nasce da una delle mie grandi passioni: i videogiochi. Affascinato dal funzionamento e dalla complessità di questi media che mi hanno sempre appassionato, ho deciso di creare un gioco semplice ma coinvolgente per esplorare il processo di sviluppo e acquisire competenze dirette in questo ambito.
Data la vasta quantità di file generati dal lavoro su Unity, ho selezionato quelli più significativi per fornire una panoramica chiara del mio approccio, delle mie capacità di programmazione in C# e della mia padronanza della piattaforma Unity.

Gioca
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    public float score;
    public GameObject completePanel;

    private bool isEnded = false;
    private bool gameCompleted = false;

    public bool isGameCompleted() => gameCompleted;

    public void setGameCompleted(bool boolean)
    {
        this.gameCompleted = boolean;
    }

    public void EndGame()
    {
        if (!isEnded)
        {
            FindObjectOfType<AudioManager>().StopSound("Theme");
            FindObjectOfType<AudioManager>().PlaySound("PlayerCrash");
            isEnded = true;
        }
    }

    void RestartScene()
    {
        PlayerPrefs.SetInt("CurrentScore", 0);
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void NextLevel()
    {
        if (!isEnded)
        {
            FindObjectOfType<AudioManager>().StopSound("Theme");
            FindObjectOfType<AudioManager>().PlaySound("LevelCompleted");
            completePanel.SetActive(true);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey("r"))
        {
            if (isEnded) {
                this.RestartScene();
            }
        }
    }
}
using UnityEngine;
using UnityEngine.UI;

public class PlayerCollision : MonoBehaviour
{
    public Movement playerMovement;
    public Text text;
    private GameManager game;

    private void Start()
    {
        this.game = FindObjectOfType<GameManager>();
    }
    void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.tag == "Obstacle")
        {
            text.enabled = true;
            playerMovement.enabled = false;
            game.EndGame();
        }
    }
}
using UnityEngine;
using UnityEngine.UI;

public class Movement : MonoBehaviour
{
    public Rigidbody rb;
    public float force = 2000f;
    public float sideForce = 500f;
    public Text text;
    private GameManager game;

    private void Start()
    {
        this.game = FindObjectOfType<GameManager>();
    }

    void FixedUpdate() {

        rb.AddForce(force * Time.deltaTime, 0, 0);

        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rb.AddForce(0, 0, sideForce * Time.deltaTime, ForceMode.VelocityChange);
        } 
        else if (Input.GetKey(KeyCode.RightArrow))
        {
            rb.AddForce(0, 0, -sideForce * Time.deltaTime, ForceMode.VelocityChange);
        }

        if(rb.position.y < -1f)
        {
            text.enabled = true;
            game.EndGame();
        }
    }
}
using UnityEngine;
using UnityEngine.Audio;
using System;

public class AudioManager : MonoBehaviour
{
    public Sound[] sounds;
    public SoundArray array;

    private void Awake()
    {
        foreach(Sound sound in sounds)
        {
            sound.source = gameObject.AddComponent<AudioSource>();
            sound.source.clip = sound.clip;
            sound.source.volume = sound.volume;
            sound.source.pitch = sound.pitch;
            sound.source.loop = sound.loop;
        }

        array.source = gameObject.AddComponent<AudioSource>();
        System.Random rng = new System.Random();
        int theme = rng.Next(0, array.clips.Length);
        array.source.clip = array.clips[theme];
        array.source.volume = array.volume;
        array.source.pitch = array.pitch;
        array.source.loop = array.loop;
    }

    public void PlaySound(string soundName)
    {
        if (soundName == "Theme")
        {
            array.source.Play();
        } else { 
            Sound s = Array.Find(sounds, sound => sound.name == soundName);
            if (s == null)
            {
                Debug.LogWarning("No sound found with " + soundName + " name");
                return;
            }

            s.source.Play();
        }
    }

    private void Start()
    {
        PlaySound("Theme");
    }

    public void StopSound(string soundName)
    {
        if (soundName == "Theme")
        {
            array.source.Stop();
        }
        else
        {
            Sound s = Array.Find(sounds, sound => sound.name == soundName);
            if (s == null)
            {
                Debug.LogWarning("No sound found with " + soundName + " name");
                return;
            }

            s.source.Stop();
        }
    }
}

TOP  GUN

Linguaggio: python3

"Questo progetto, nato dalla mia passione per i videogiochi, è stato sviluppato interamente in Python. Dopo aver realizzato diversi progetti simili utilizzando Unity, ho voluto affrontare una nuova sfida: creare un gioco partendo esclusivamente dal codice, senza l'ausilio di strumenti o ambienti di sviluppo avanzati. L'obiettivo era comprendere le differenze nel processo di sviluppo quando si lavora in modo puro e minimale, focalizzandomi su concetti fondamentali e implementazioni di base.
Questa esperienza mi ha permesso di approfondire aspetti chiave come la gestione degli asset e la logica di gioco, nonché di affinare le mie competenze di programmazione in Python in un contesto che richiede maggiore flessibilità e adattamento rispetto all’utilizzo di un motore di gioco completo.

Simulazione
import pygame
import logging
import random
import scripts.input as INPUT
import scripts.movement as MOVEMENTS
import scripts.planes as planes
import scripts.ai as AI
import scripts.gui as GUI

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s", filemode='w', filename="./main.log")
logger = logging.getLogger('GameManager')
logger.setLevel(logging.INFO)

pygame.init()
logger.info("PyGame succesfully initialized")
clock = pygame.time.Clock()
logger.info("Clock initialized")

bg = pygame.display.set_mode((1000, 700), pygame.SRCALPHA|pygame.RESIZABLE, 32)
player = planes.Player([50, bg.get_height()/2])
bg_img = pygame.image.load('./assets/img/bg.png')
bg.blit(bg_img, (0,0))
bg.blit(player.img, (player.position))
logger.info("Basic assets loaded succesfully")

movements = {'up':False, 'down':False, 'left':False, 'right':False, 'firing':False}
buttons = []
bullets = []
enemies = []
clouds = []
power_ups = []
game_over = False

while True:
    clock.tick(60)
    level = round(player.score/5000)
    if level == 0:
        level = 1
    bg_img = pygame.transform.scale(bg_img, (bg.get_width(), bg.get_height()))
    bg.blit(bg_img, (0,0))
    for cloud in clouds:
        bg.blit(cloud.img, (cloud.position))
    for power in power_ups:
        bg .blit(power.img, power.position)
    for bullet in bullets:
        bg.blit(bullet.img, bullet.position)
    for enemy in enemies:
        bg.blit(enemy.img, enemy.position)
    bg.blit(player.img, (player.position))

    GUI.update(bg, player)

    INPUT.event_manager(pygame.event.get(), movements, buttons)
    game_over = AI.collision(player, bullets, enemies, power_ups)
    if game_over:
        AI.game_over()
    AI.spawn_cloud(clouds)
    AI.spawn_enemies(enemies, level, random.randint(700, pygame.display.get_surface().get_size()[0]))
    AI.spawn_powerup(power_ups)
    AI.enemy_behavior(enemies, bullets)
    MOVEMENTS.player(movements, player, bg, bullets)
    MOVEMENTS.bullets(bullets, bg)
    MOVEMENTS.enemies(enemies)
    MOVEMENTS.power_ups(power_ups)
    MOVEMENTS.clouds(clouds)
    pygame.display.update()
import pygame
import logging

logger = logging.getLogger('GameManager.InputManager')

def key_manager(movements, event):
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_DOWN:
            movements['down'] = True
            movements['up'] = False
        elif event.key == pygame.K_UP:
            movements['down'] = False
            movements['up'] = True
        if event.key == pygame.K_LEFT:
            movements['left'] = True
            movements['right'] = False
        elif event.key == pygame.K_RIGHT:
            movements['left'] = False
            movements['right'] = True
        if event.key == pygame.K_SPACE:
            movements['firing'] = True
    if event.type == pygame.KEYUP:
        if event.key == pygame.K_DOWN:
            movements['down'] = False
        elif event.key == pygame.K_UP:
            movements['up'] = False
        if event.key == pygame.K_LEFT:
            movements['left'] = False
        elif event.key == pygame.K_RIGHT:
            movements['right'] = False
        if event.key == pygame.K_SPACE:
            movements['firing'] = False

def mouse_manager(buttons, event):
    pass


def event_manager(events, movements, buttons):
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)
        elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
            key_manager(movements, event)
        elif event.type == pygame.MOUSEBUTTONUP:
            logger.info('Mouse Event called')
            mouse_manager(buttons, event)
import pygame
import scripts.planes as planes
import logging

logger = logging.getLogger('GameManager.MovementHandler')

def player(movements, target, display, bullets):
    if movements['up'] == True and target.position[1]>0:
        target.position[1] -= 10
    elif movements['down'] == True and target.position[1]<(display.get_height()-64):
        target.position[1] += 10
    if movements['left'] == True and target.position[0]>0:
        target.position[0] -= 10
    elif movements['right'] == True and target.position[0]<250:
        target.position[0] += 10
    if movements['firing'] == True:
        if target.tick == 0 and target.ammo > 0:
            target.tick = 10
            position = target.position.copy()
            position[0] += 51
            bullets.append(planes.Bullet(position, 'ally', target.dmg, target.bullet_img))
            target.ammo -= 1
        else:
            target.tick -= 1

def bullets(bullets, display):
    for bullet in bullets:
        if bullet.type == 'ally':
            if bullet.position[0] > display.get_width():
                bullets.remove(bullet)
                del bullet
            else:
                bullet.position[0] += 50
        elif bullet.type == 'enemy':
            if bullet.position[0] < 0:
                bullets.remove(bullet)
                del bullet
            else:
                bullet.position[0] -= 15
        else:
            logger.warning("Bullet type set is not correct")
            bullets.remove(bullet)
            del bullet            

def clouds(clouds):
    for cloud in clouds:
        if cloud.position[0] > -200:
            cloud.position[0] -= (cloud.speed+5)
        else:
            clouds.remove(cloud)
            del cloud

def enemies(enemies):
    for enemy in enemies:
        if (enemy.position[1] < 0 and enemy.start=='bot') or (enemy.position[1] > 1000 and enemy.start=='top'):
            enemies.remove(enemy)
            del enemy
        else:
            if enemy.start == 'top':
                enemy.position[1] += 7
            elif enemy.start == 'bot':
                enemy.position[1] -= 7
            else:
                logger.debug("Enemy created is corrupted. Removing it")
                enemies.remove(enemy)
                del enemy
                logger.debug("Corrupted enemy removed")
                continue
            enemy.position[0] -= 2

def power_ups(power_ups):
    for power in power_ups:
        if power.position[0] > -200:
            power.position[0] -= 5
        else:
            power_ups.remove(power)
            del power
import pygame
import random
import logging

logger = logging.getLogger('GameManager.Objects')

class Player():
    def __init__(self, position):
        self.img = pygame.image.load('./assets/img/player_plane.gif')
        self.bullet_img = 'player_bullet.png'
        self.position = position
        self.dmg = 34
        self.max_hp = 1000
        self.hp = self.max_hp
        self.ammo = 500
        self.score = 0
        self.tick = 0

class Bullet():
    def __init__(self, position, b_type, damage, img):
        self.img = pygame.image.load('./assets/img/'+img)
        self.position = position
        self.dmg = damage
        self.type = b_type

class Enemy():
    def __init__(self, position, level, start, pattern):
        self.img = pygame.image.load('./assets/img/enemy_plane.png')
        self.bullet_img = 'enemy_bullet.png'
        self.position = position
        self.level = level
        self.dmg = 10 * self.level
        self.hp = 100 * self.level
        self.start = start
        self.pattern = pattern

class Cloud():
    def __init__(self, position):
        self.img = pygame.image.load('./assets/img/cloud'+str(random.randint(0,10))+'.png')
        self.speed = random.randint(1,5)
        self.position = position

class PowerUp():
    def __init__(self, n_type, position):
        self.position = position
        if n_type == 0:
            self.effect = 'ammo'
            self.img = pygame.image.load('./assets/img/ammo.png')
            self.ammo = 250
            self.healt = 0
            self.score = 0
            self.dmg = 0
        elif n_type == 1:
            self.effect = 'heal'
            self.img = pygame.image.load('./assets/img/heal.png')
            self.ammo = 0
            self.healt = 25
            self.score = 0
            self.dmg = 0
        elif n_type == 2:
            self.effect = 'score'
            self.img = pygame.image.load('./assets/img/score.png')
            self.ammo = 0
            self.healt = 0
            self.score = 250
            self.dmg = 0
        elif n_type == 3:
            self.effect = 'dmgu'
            self.img = pygame.image.load('./assets/img/dmgu.png')
            self.ammo = 0
            self.healt = 0
            self.score = 0
            self.dmg = 5
        else:
            logger.error("Power Up creation failed. Forcing quit")
            pygame.quit()
            exit(1)
import pygame
import random
import scripts.planes as planes
import logging

logger = logging.getLogger('GameManager.AI')

def collision(player, bullets, enemies, power_ups):
    result = False
    for power_up in power_ups:
        if __hit(power_up, player):
            player.hp += power_up.healt
            player.hp = min(player.max_hp, player.hp)
            player.dmg += power_up.dmg
            player.score += power_up.score
            player.ammo += power_up.ammo
            power_ups.remove(power_up)
            del power_up
    for bullet in bullets:
        if bullet.type == 'enemy' and __hit(bullet, player):
            player.hp -= bullet.dmg
            bullets.remove(bullet)
            del bullet
            if player.hp <= 0:
                result = True
        elif bullet.type == 'ally':
            for enemy in enemies:
                if __hit(bullet, enemy):
                    enemy.hp -= bullet.dmg
                    bullets.remove(bullet)
                    player.score += 10*enemy.level
                    del bullet
                    if enemy.hp <= 0:
                        player.score += 200*enemy.level
                        #trigger explosion animation at enemy.position
                        enemies.remove(enemy)
                        del enemy
                    break
    return result

def spawn_powerup(power_ups):
    if random.randint(0,1000) < 2:
        power_ups.append(planes.PowerUp(random.randint(0,3), [2000, random.randint(100, 600)]))

def spawn_cloud(clouds):
    if random.randint(0, 100) < 5 and len(clouds)<10:
        clouds.append(planes.Cloud([2000, random.randint(100, 700)]))

def spawn_enemy(enemies, level, x_pos, y_pos):
    start=''
    height=0
    if random.randint(0, 100) < 2 and len(enemies)<10:
        if random.randint(0,1) == 0:
            start = 'bot'
            height += 1000
        else:
            height = -100
            start = 'top'
        enemies.append(planes.Enemy([x_pos, height], level, start))

def spawn_enemies(enemies, level, xpos):
    start=''
    y_pos=0
    if random.randint()


def enemy_behavior(enemies, bullets):
    for enemy in enemies:
        if random.randint(0, 100) < 2:
            bullets.append(planes.Bullet(enemy.position.copy(), 'enemy', enemy.dmg, enemy.bullet_img))

def __hit(target1, target2):
    if (abs(target1.position[0]-target2.position[0])<60 and abs(target1.position[1]-target2.position[1])<60):
        #print("Target1-"+str(type(target1))+" hit target2-"+str(type(target2)))
        return True
    return False
import pygame
import logging

logger = logging.getLogger('GameManager.GuiManager')

def update(display, player):
    myfont = pygame.font.SysFont('Courier New', 30)
    score = myfont.render("Score: "+str(player.score), False, (0, 0, 0))
    healt = myfont.render("HP: "+str(player.hp), False, (0, 0, 0))
    ammo = myfont.render("Ammo: "+str(player.ammo), False, (0, 0, 0))
    display.blit(score, ((display.get_width()/2)-200, 0))
    display.blit(healt, (0, display.get_height()-50))
    display.blit(ammo, (display.get_width()-200, display.get_height()-50))

Quinta legge dell'inattendibilità:
"Errare è umano, ma per incasinare davvero tutto ci vuole un computer."

DATABASE  DIAGRAM

Linguaggio: Entity Relationship Diagram

Questo diagramma rappresenta il risultato di un assignment universitario svolto per il corso di Database. Anche se il progetto non richiede l'implementazione di codice, ho trovato particolarmente stimolante affrontare la sfida di risolvere un problema attraverso la progettazione di un modello concettuale. Questo lavoro mi ha permesso di approfondire la comprensione delle strutture dei dati e delle relazioni tra essi, aspetti fondamentali per la progettazione di database efficienti e funzionali. Come in precedenza, è possibile consultare la richiesta originale in formato PDF per avere una visione chiara e trasparente delle istruzioni fornitemi e delle soluzioni adottate.

Visualizza PDF

DATABASE  QUERIES

Linguaggio: SQL

Questo progetto rappresenta il risultato di un assignment del corso di Database, in cui l'obiettivo era creare una correlazione diretta tra una serie di richieste e il codice SQL necessario per soddisfarle. L'attività è stata particolarmente interessante perché ha richiesto un approccio metodico nella traduzione delle istruzioni in query SQL efficienti, evidenziando la logica e la precisione necessarie nella gestione dei dati.
Anche i questo caso il PDF contenente le istruzioni originali dell'assignment è disponibile, consentendo di comprendere al meglio il contesto del progetto e valutare come ciascuna richiesta sia stata tradotta in operazioni concrete sul database.

Visualizza PDF
/*Query 1*/

SELECT "name"
FROM "Beers"
WHERE "manf" = 'Anheuser-Busch'

/*Query 2*/

SELECT "bar"
FROM "Sells"
WHERE "beer" = 'Miller'
AND ROUND(CAST("price" AS decimal), 2) IN (
    SELECT ROUND(CAST("price" AS decimal), 2)
    FROM "Sells"
    WHERE "beer" = 'Bud'
    )

/*Query 3*/

SELECT "name", "manf"
FROM "Beers"
WHERE "name" IN (
    SELECT "beer"
    FROM "Likes"
    WHERE "drinker" = 'Fred'
    )

/*Query 4*/

SELECT "name"
FROM "Beers" b1
WHERE NOT EXISTS (
    SELECT *
    FROM "Beers"
    WHERE "manf" = b1."manf"
    AND "name" <> b1."name"
    )

/*Query 5*/

SELECT DISTINCT "beer"
FROM "Sells"
WHERE ROUND(CAST("price" AS decimal), 2) >= ALL (
    SELECT ROUND(CAST("price" AS decimal), 2)
    FROM "Sells"
    )

/*Query 6*/

(SELECT * FROM "Likes")
INTERSECT
(
    SELECT "drinker", "beer"
    FROM "Frequents" f1, "Sells" s1
    WHERE f1."bar" = s1."bar"
)

/*Query 7*/

SELECT DISTINCT ROUND(CAST("price" AS decimal), 2)
FROM "Sells"

/*Query 8*/

SELECT DISTINCT "bar"
FROM "Sells"
WHERE "beer" IN (
    SELECT "beer"
    FROM "Likes"
    WHERE "drinker" = 'Joe'
    )

/*Query 9*/

SELECT DISTINCT "drinker"
FROM "Frequents" f1
WHERE "bar" IN (
    SELECT "bar"
    FROM "Sells" s1, "Likes" l1
    WHERE l1."beer" = s1."beer"
    AND f1."drinker" = l1."drinker"
    )

/*Query 10*/

SELECT DISTINCT "drinker"
FROM "Frequents"
WHERE "drinker" NOT IN(
    SELECT "drinker"
    FROM "Frequents" f1
    WHERE NOT EXISTS(
        SELECT *
        FROM "Sells" s1
        JOIN "Likes" l1 ON s1."beer"=l1."beer"
        WHERE f1."bar" = s1."bar"
        AND f1."drinker" = l1."drinker"
        )
    )

"A user interface is like a joke. If you have to explain it, it's not that good."
"L'interfaccia utente è come una barzeletta. Se la devi spiegare, non ti è venuta bene"
-Martin LeBlanc

Contattami:

franceschi.developer@gmail.com