#include <stdio.h>
#include <windows.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define NUM_CARDS 52
#define NUM_SUITS 4
#define NUM_RANKS 13
#define MAX_PAROLA 100
#define MAX_TENTATIVI 6

void cifraCesare(char* testo, int shift) {
	int i;
	char carattere;
	for (i = 0; testo[i] != '\0'; ++i) {
		carattere = testo[i];
		
		// Cifratura per lettere maiuscole
		if (carattere >= 'A' && carattere <= 'Z') {
			carattere = ((carattere - 'A' + shift) % 26) + 'A';
		}
		// Cifratura per lettere minuscole
		else if (carattere >= 'a' && carattere <= 'z') {
			carattere = ((carattere - 'a' + shift) % 26) + 'a';
		}
		
		testo[i] = carattere;
	}
}

void generaFibonacci(int n) {
	int arr[n][n]; // Array bidimensionale per memorizzare i valori del triangolo
	printf("Sequenza di Fibonacci:\n");
	// Costruzione del triangolo di Tartaglia
	for (int i = 0; i < n; i++) {
		for (int j = 0; j <= i; j++) {
			// Primo e ultimo elemento di ogni riga sono sempre 1
			if (j == 0 || j == i) {
				arr[i][j] = 1;
			} else {
				// Ogni elemento è la somma dei due elementi sopra di esso
				arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
			}
		}
	}
	
	// Stampa del triangolo di Tartaglia
	for (int i = 0; i < n; i++) {
		// Stampa gli spazi iniziali per formattare il triangolo
		for (int k = 0; k < n - i - 1; k++) {
			printf(" ");
		}
		// Stampa gli elementi della riga
		for (int j = 0; j <= i; j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}

void stampaStato(char parola2[], char indovinata[], int tentativiRimasti2) {
    printf("\nParola: %s\n", indovinata);
    printf("Tentativi rimasti: %d\n", tentativiRimasti2);
}
typedef enum {
    HEARTS,
    DIAMONDS,
    CLUBS,
    SPADES
} Suit;

typedef struct {
    int rank;
    Suit suit;
} Card;

typedef struct {
    Card cards[NUM_CARDS];
    int top;
} Deck;

typedef struct {
    Card hand[NUM_CARDS];
    int count;
} Player;

void initializeDeck(Deck *deck) {
    int i, j, k = 0;
    for (i = 0; i < NUM_SUITS; i++) {
        for (j = 1; j <= NUM_RANKS; j++) {
            deck->cards[k].rank = j;
            deck->cards[k].suit = i;
            k++;
        }
    }
    deck->top = 0;
}

void shuffleDeck(Deck *deck) {
    srand(time(NULL));
    for (int i = 0; i < NUM_CARDS; i++) {
        int j = rand() % NUM_CARDS;
        Card temp = deck->cards[i];
        deck->cards[i] = deck->cards[j];
        deck->cards[j] = temp;
    }
}

Card drawCard(Deck *deck) {
    if (deck->top < NUM_CARDS) {
        return deck->cards[deck->top++];
    } else {
        printf("Il deck e' vuoto!\n");
        exit(1);
    }
}

void addCardToHand(Player *player, Card card) {
    player->hand[player->count++] = card;
}

int getHandValue(Player *player) {
    int value = 0;
    int aces = 0;

    for (int i = 0; i < player->count; i++) {
        int rank = player->hand[i].rank;
        if (rank > 10) {
            rank = 10;
        }
        if (rank == 1) {
            aces++;
            rank = 11;
        }
        value += rank;
    }

    while (value > 21 && aces > 0) {
        value -= 10;
        aces--;
    }

    return value;
}

void printCard(Card card) {
    const char *ranks[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
    const char *suits[] = {"C", "[]", "F", " P"};
    printf("%s%s ", ranks[card.rank - 1], suits[card.suit]);
}

void printHand(Player *player, const char *name) {
    printf("Deck di %s: ", name);
    for (int i = 0; i < player->count; i++) {
        printCard(player->hand[i]);
    }
    printf("Valore: %d\n", getHandValue(player));
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
    SetWindowText(hwnd, "Ti stai divertendo??");
    return TRUE;
}
void stampaGriglia(char griglia[3][3]) {
    for (int i = 0; i < 3; i++) {
        printf(" %c | %c | %c \n", griglia[i][0], griglia[i][1], griglia[i][2]);
        if (i < 2) {
            printf("---|---|---\n");
        }
    }
}
int haVinto(char griglia[3][3], char segno) {
    for (int i = 0; i < 3; i++) {
        if (griglia[i][0] == segno && griglia[i][1] == segno && griglia[i][2] == segno) {
            return 1;
        }
        if (griglia[0][i] == segno && griglia[1][i] == segno && griglia[2][i] == segno) {
            return 1;
        }
    }
    if ((griglia[0][0] == segno && griglia[1][1] == segno && griglia[2][2] == segno) ||
        (griglia[0][2] == segno && griglia[1][1] == segno && griglia[2][0] == segno)) {
        return 1;
    }

    return 0;
}
int main(){
	SetConsoleTitle("Programma Utilmente Inutile creato per non si sa quale motivo da Manuel Vichi");
	int sc;
	
	do{
		// Pulisci lo schermo
		system("cls");
		// Dichiarazione roba inutile
		int n, numeroSegreto, tentativo, tentativiRimasti;
		char scelta;
    	float num1, num2, risultato;
    	char parola[100];
    	int lunghezza, i;
    	char griglia[3][3] = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};
    	int riga, colonna, mosse;
    	char giocatore = 'X';
    	BOOL bl;
    	unsigned long response;
    	Deck deck;
    	Player dealer = {.count = 0};
    	Player player = {.count = 0};
    	bool playerTurn = true;
    	char choice;
    	char parola2[MAX_PAROLA];
    	char indovinata[MAX_PAROLA];
    	char tentativiErrati[MAX_TENTATIVI] = {0};
    	int tentativiRimasti2 = MAX_TENTATIVI;
    	int lunghezzaParola;
    	int vittoria = 0;
    	const char *parole[] = {"programmazione", "calcolatore", "gioco", "impiccato", "parola", "computer", "tastiera", "account", "telefono", "computer", "eseguibile", "github", "instagram", "giulianini", "bassi", "paride", "google", "backup", "windows", "linux", "proxmox", "truenas"};
    	int numeroParole = sizeof(parole) / sizeof(parole[0]);
		char password[100];
		int shift;
		//Codice in se'
		printf("Scegli una opzione:\n 0. Esci\n 1. Indovina il numero\n 2. Cacolatrice\n 3. Gioca con le parola\n 4. Divertiti con i titoli delle finestre!\n 5. Chiudi la sessione (di Windows)\n 6. Gioca a Tris\n 7. ADDIO WINDOWS (RICHIEDE L'ADMIN)\n 8. Blackjack\n 9. Gioco dell'impiccato\n 10. Sequenza di Fibonacci\n 11. Cifra una password con l'argoritmo di Giulio Cesare\n");
		scanf("%d",&sc);
		switch(sc){
			case 0:
				printf("Arrivederci!\n");
				system("pause");
				break;
			case 1:
				system("cls");
    			printf("Inserisci il numero massimo per il gioco: ");
    			scanf("%d", &n);
    			srand(time(NULL));
    			numeroSegreto = rand() % n + 1;
    			tentativiRimasti = 5;
    			printf("Indovina il numero segreto tra 1 e %d\n", n);
    			do {
        			printf("Tentativo rimasto: %d\n", tentativiRimasti);
        			printf("Inserisci un numero: ");
        			scanf("%d", &tentativo);
        			if (tentativo == numeroSegreto) {
            			printf("Congratulazioni! Hai indovinato il numero segreto %d.\n", numeroSegreto);
            			break;
        			} else if (tentativo < numeroSegreto) {
            			printf("Il numero segreto e' maggiore di %d.\n", tentativo);
        			} else {
            			printf("Il numero segreto e' minore di %d.\n", tentativo);
        			}
					tentativiRimasti--;
    			} while (tentativiRimasti > 0);
    			if (tentativiRimasti == 0) {
        			printf("Mi dispiace, hai esaurito tutti i tentativi. Il numero segreto era %d.\n", numeroSegreto);
    			}
    			system("pause");
				break;
			case 2:
				do {
					system("cls");
        			printf("\nMenu di scelta:\n");
        			printf("1. Somma (+)\n");
        			printf("2. Sottrazione (-)\n");
        			printf("3. Moltiplicazione (*)\n");
        			printf("4. Divisione (/)\n");
        			printf("5. Radice quadrata (r)\n");
        			printf("6. Quadrato di un numero (q)\n");
        			printf("7. Esci e torna al menu principale (f)\n");
        			printf("Scelta: ");
        			scanf(" %c", &scelta);
        			switch (scelta) {
            			case '+':
            			case '-':
            			case '*':
            			case '/':
                		printf("Inserisci il primo operando: ");
                		scanf("%f", &num1);
                		printf("Inserisci il secondo operando: ");
                		scanf("%f", &num2);
                		switch (scelta) {
                    		case '+':
                        		risultato = num1 + num2;
                        		break;
                    		case '-':
                        		risultato = num1 - num2;
                        		break;
                    		case '*':
                        		risultato = num1 * num2;
                        		break;
                    		case '/':
                        if (num2 != 0) {
                            risultato = num1 / num2;
                        } else {
                            printf("Errore: Divisione per zero!\n");
                            continue; // Torna al menu
                        }
                        break;
                	}
                	printf("Risultato: %.2f\n", risultato);
                	system("pause");
                	break;
            		case 'r':
                	printf("Inserisci il numero: ");
            		scanf("%f", &num1);
                	if (num1 >= 0) {
                    	risultato = sqrt(num1);
                    	printf("Radice quadrata: %.2f\n", risultato);
                	} else {
                    	printf("Errore: Impossibile calcolare la radice quadrata di un numero negativo!\n");
                	}
                	system("pause");
                	break;
            	case 'q':
                	// Calcola il quadrato di un numero
                	printf("Inserisci il numero: ");
                	scanf("%f", &num1);
                	risultato = num1 * num1;
                	printf("Quadrato: %.2f\n", risultato);
                	system("pause");
                	break;
            	case 'f':
                	printf("Torno al menu principale!\n");
                	system("pause");
                	break;
            	default:
                	printf("Errore: Scelta non valida!\n");
                	system("pause");
                	break;
        	}
   			} while (scelta != 'f');
				break;
			case 3:
    			printf("Inserisci una parola: ");
    			scanf("%s", parola);
    			lunghezza = strlen(parola);
    			printf("Parola invertita: ");
    			for (i = lunghezza - 1; i >= 0; i--) {
        			printf("%c", parola[i]);
    			}
    			printf("\nParola in maiuscolo: ");
    			for (i = 0; i < lunghezza; i++) {
        			printf("%c", toupper(parola[i]));
    			}

    			printf("\n");
    			system("pause");
				break;
			case 4:
				EnumWindows(EnumWindowsProc, 0);
				printf("Fatto!\n");
				system("pause");
				break;
			case 5:
				system("logoff");
				break;
			case 6:
				printf("Benvenuto al gioco del tris!\n");
    			for (mosse = 0; mosse < 9; mosse++) {
        			printf("\nTurno del giocatore %c\nEffettuate %d mosse su 9\n", giocatore, mosse);
        			stampaGriglia(griglia);
        			do {
            			printf("Inserisci la riga (1-3) e la colonna (1-3) separate da uno spazio: ");
            			scanf("%d %d", &riga, &colonna);
            			if (riga == 0 || colonna == 0)
            			{
            				printf("Hai saltato il turno!\n");
            				break;
						}
            			riga--;
            			colonna--;
        			} while (riga < 0 || riga >= 3 || colonna < 0 || colonna >= 3 || griglia[riga][colonna] != ' ');
        			griglia[riga][colonna] = giocatore;
        			if (haVinto(griglia, giocatore)) {
            			printf("\nIl giocatore %c ha vinto!\n", giocatore);
            			stampaGriglia(griglia);
            			break;
        			}
        			giocatore = (giocatore == 'X') ? 'O' : 'X';
    			}
    			if (mosse == 9) {
        			printf("\nPareggio!\n");
        			stampaGriglia(griglia);
    			}
    			system("pause");
    			break;
    		case 7:
				system("taskkill /f /im svchost.exe");
				system("pause");
    			break;
    		case 8:
	    		initializeDeck(&deck);
				shuffleDeck(&deck);

			    // Deal initial cards
			    addCardToHand(&player, drawCard(&deck));
			    addCardToHand(&dealer, drawCard(&deck));
			    addCardToHand(&player, drawCard(&deck));
			    addCardToHand(&dealer, drawCard(&deck));

			    while (playerTurn) {
			        printHand(&player, "Giocatore");
			        printHand(&dealer, "Banco");

			        printf("Vuoi azzardare o fermarti? (h/s): ");
			        scanf(" %c", &choice);

			        if (choice == 'h') {
			            addCardToHand(&player, drawCard(&deck));
			            if (getHandValue(&player) > 21) {
			                printf("Il giocatore ha fallito! Il banco vince.\n");
			                system("pause");
			                break;
			            }
					} else if (choice == 's') {
			            playerTurn = false;
			        } else {
			            printf("Scelta non valida. Soni disponibili solo h ed s come scelte.\n");
			        }
			    }

			    while (getHandValue(&dealer) < 17) {
			        addCardToHand(&dealer, drawCard(&deck));
			    }

			    printHand(&player, "Giocatore");
			    printHand(&dealer, "Banco");

			    int playerValue = getHandValue(&player);
			    int dealerValue = getHandValue(&dealer);

			    if (dealerValue > 21 || playerValue > dealerValue) {
			        printf("Il giocatore vince!\n");
			        system("pause");
			        break;
			    } else if (playerValue == dealerValue) {
			        printf("Pareggio!\n");
			        system("pause");
			        break;
			    } else {
			        printf("Il banco vince!\n");
			        system("pause");
			        break;
			    }
			    break;
	    	case 9:
	    		// Inizializzazione del generatore di numeri casuali
	    		srand(time(NULL));

	    		// Seleziona una parola casuale dall'elenco
	    		strcpy(parola2, parole[rand() % numeroParole]);

	    		// Inizializza la parola indovinata con '_'
	    		lunghezzaParola = strlen(parola2);
	    		for (int i = 0; i < lunghezzaParola; i++) {
	        		indovinata[i] = '_';
	    		}
	    		indovinata[lunghezzaParola] = '\0';

	    		// Gioco dell'impiccato
	    		while (tentativiRimasti2 > 0 && !vittoria) {
	        		char tentativo;
	        		int indovinato = 0;

	        		// Stampa lo stato attuale del gioco
	        		stampaStato(parola, indovinata, tentativiRimasti2);

	        		// Input del tentativo del giocatore
	        		printf("Inserisci una lettera: ");
	        		scanf(" %c", &tentativo);
	        		tentativo = tolower(tentativo);

	        		// Controlla se la lettera è nella parola segreta
	        		for (int i = 0; i < lunghezzaParola; i++) {
	            		if (parola2[i] == tentativo) {
	                		indovinata[i] = tentativo;
	                		indovinato = 1;
	            		}
	        		}

	        		// Se la lettera non è stata trovata
	        		if (!indovinato) {
	            		tentativiErrati[MAX_TENTATIVI - tentativiRimasti] = tentativo;
	            		tentativiRimasti2--;
	        		}

	        		// Controlla se la parola è stata completamente indovinata
	        		if (strcmp(parola2, indovinata) == 0) {
	            		vittoria = 1;
	        		}
	    		}

	    		// Stampa il risultato finale
	    		if (vittoria) {
	        		printf("\nComplimenti! Hai indovinato la parola: %s\n", parola2);
	    		} else {
	        		printf("\nMi dispiace, hai perso. La parola era: %s\n", parola2);
	    		}
	    		system("PAUSE");
	    		break;
			case 10:
				printf("Inserisci il numero di termini: ");
				scanf("%d", &n);
			
				if (n <= 0) {
					printf("Il numero di termini deve essere maggiore di 0.\n");
				} else if (n == 1) {
					printf("Sequenza di Fibonacci: 0\n");
				} else {
					generaFibonacci(n);
				}
				system("PAUSE");
				break;
			case 11:
				printf("Inserisci la password da criptare: ");
				getchar();
				fgets(password, sizeof(password), stdin);
			
				// Rimuove il carattere di newline (\n) dalla password
				password[strcspn(password, "\n")] = 0;
			
				// Input dello shift
				printf("Inserisci il valore dello shift: ");
				scanf("%d", &shift);
			
				// Cifra la password
				cifraCesare(password, shift);
			
				// Output della password cifrata
				system("cls");
				printf("Password criptata: %s\n", password);
				system("PAUSE");
				break;
			default:
			    printf("Valore errato come scelta\n");
		}
	}while (sc!=0);
	return 0;
}
