Instantly share code, notes, and snippets.
Created
March 10, 2024 18:32
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save vittodevit/ebc85ac89b771cd06f4ef3a5a5c58a6f to your computer and use it in GitHub Desktop.
Battaglia navale in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import socket | |
import random | |
import os | |
##################### | |
# VARIABILI GLOBALI # | |
##################### | |
SERVER = ""; # 0.0.0.0 significa che è server (ascolto su tutte le interfacce) | |
PORT = 0; # porta su cui ascoltare o connettersi | |
CONTROL = 0; # 0 = gioca il server | 1 = gioca il client | |
NEXT_TURN_MESSAGE = "" # immagazzina il messaggio da mostrare al prossimo turno | |
SOCKET = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # socket UDP | |
REMOTE = None # corrispettivo a cui inviare i dati | |
MATRIX = [[0 for i in range(10)] for j in range(10)] # matrice di gioco 10x10 (0 acqua, 1 nave, 2 acqua colpita, 3 nave colpita) | |
ADV_MATRIX = [[0 for i in range(10)] for j in range(10)] # matrice di gioco 10x10 avversario | |
SSP = [4, 3, 3, 2, 2, 2, 1, 1, 1, 1] # array contenente la lunghezza delle navi da piazzare | |
SHIP_BLOCK_TOT = sum(SSP) # numero totale di blocchi nave | |
# colori per la shell | |
I_RED='\033[0;91m' | |
I_GREEN='\033[0;92m' | |
I_BLUE='\033[0;94m' | |
COLOR_OFF='\033[0m' | |
# banner ascii | |
BANNER = """ | |
______ _______ _______ _______ _______ ______ _____ _______ | |
|_____] |_____| | | |_____| | ____ | | |_____| | |
|_____] | | | | | | |_____| |_____ __|__ | | | |
__ _ _______ _ _ _______ _______ | |
| \ | |_____| \ / |_____| | |______ | |
| \_| | | \/ | | |_____ |______ | |
""" | |
################### | |
# FUNZIONI HELPER # | |
################### | |
def header(): | |
os.system('clear') | |
print(BANNER) | |
def mc_to_str(num): | |
if num == 0: | |
return " " | |
elif num == 1: | |
return I_GREEN + "■" + COLOR_OFF | |
elif num == 2: | |
return I_BLUE + "•" + COLOR_OFF | |
elif num == 3: | |
return I_RED + "X" + COLOR_OFF | |
def legenda(): | |
print("Legenda:") | |
print(" " + I_GREEN + "■" + COLOR_OFF + " = nave", end="") | |
print(" " + I_BLUE + "•" + COLOR_OFF + " = colpo in acqua", end="") | |
print(" " + I_RED + "X" + COLOR_OFF + " = nave colpita", end="\n\n") | |
def print_matrix(matrix): | |
print(" ╒═0═╤═1═╤═2═╤═3═╤═4═╤═5═╤═6═╤═7═╤═8═╤═9═╕") | |
print("0 │", end="") | |
for i in range(10): | |
print(f" {mc_to_str(matrix[0][i])} │", end="") | |
for i in range(1, 10): | |
print(f"\n ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤\n{i} │", end="") | |
for j in range(10): | |
print(f" {mc_to_str(matrix[i][j])} │", end="") | |
print("\n ╘═0═╧═1═╧═2═╧═3═╧═4═╧═5═╧═6═╧═7═╧═8═╧═9═╛") | |
print() | |
print() | |
def piazza_nave(matrix, dimensione, direzione, x, y): | |
#n.b. lancia IndexError se la nave va fuori dal campo di battaglia | |
if direzione == "v": | |
for i in range(dimensione): | |
if matrix[y+i][x] == 1: | |
raise Exception | |
else: | |
matrix[y+i][x] = 1 | |
else: | |
for i in range(dimensione): | |
if matrix[y][x+i] == 1: | |
raise Exception | |
else: | |
matrix[y][x+i] = 1 | |
return True | |
def mio_turno(): | |
if CONTROL == 0 and SERVER == "0.0.0.0": # caso server | |
return True | |
elif CONTROL == 1 and SERVER != "0.0.0.0": # caso client | |
return True | |
else: | |
return False | |
def display_ntm(): | |
global NEXT_TURN_MESSAGE | |
if NEXT_TURN_MESSAGE != "": | |
print(NEXT_TURN_MESSAGE) | |
NEXT_TURN_MESSAGE = "" | |
def send(data): | |
SOCKET.sendto(data.encode(), REMOTE) | |
def receive(): | |
data, addr = SOCKET.recvfrom(1024) | |
return data.decode() | |
def die(message): | |
print(message) | |
exit() | |
def multi_choice(question, choices): | |
while True: | |
print(question) | |
for i in range(len(choices)): | |
print(f" {i+1}. {choices[i]}") | |
choice = input("> ") | |
if choice.isdigit() and int(choice) in range(1, len(choices)+1): | |
return int(choice) # le scelte partono da 1 e non 0! | |
else: | |
print("Scelta non valida!") | |
def coord_input(controlla_avversario=False): | |
global ADV_MATRIX | |
x = -1 | |
y = -1 | |
while x not in range(10) or y not in range(10): | |
x = int(input(" ORIZONTALE (x) > ")) | |
y = int(input(" VERTICALE (y) > ")) | |
if x not in range(10) or y not in range(10): | |
print("Coordinate non valide!") | |
if controlla_avversario and (ADV_MATRIX[y][x] == 2 or ADV_MATRIX[y][x] == 3): | |
print("Hai già sparato in questa posizione!") | |
x = -1 | |
y = -1 | |
return x, y | |
################################# | |
# CONDFIGURAZIONE CLIENT/SERVER # | |
################################# | |
header() | |
match multi_choice("Vuoi hostare la partita come server o connetterti come client?", ["Hostare", "Connettersi", "Esci"]): | |
case 1: | |
header() | |
SERVER = "0.0.0.0" | |
try: | |
PORT = int(input("Inserisci la porta su cui hostare la partita: ")) | |
SOCKET.bind((SERVER, PORT)) | |
except: | |
die("Impossibile attivare il server!") | |
case 2: | |
header() | |
try: | |
SERVER = input("Inserisci l'indirizzo del server: ") | |
PORT = int(input("Inserisci la porta del server: ")) | |
except: | |
die("Porta non valida") | |
case "3": | |
die("Arrivederci!") | |
####################### | |
# CONFIGURAZIONE NAVI # | |
####################### | |
header() | |
choice = multi_choice("Configurazione del campo di battaglia", ["Manuale", "Automatica"]) | |
if choice == 1: # manuale | |
ship_index = 0; | |
for dim in SSP: | |
header() | |
print_matrix(MATRIX) | |
print(f"Inserite {ship_index} navi su 10") | |
graph = "" | |
for i in range(dim): | |
graph += "■ " | |
print(f"Posiziona nave da {dim} | {graph}") | |
new_matrix = MATRIX # copia dove poter fare casini | |
piazzata = False | |
while piazzata == False: | |
x, y = coord_input() | |
direction = input(" DIREZIONE (v/h) > ") | |
if direction != "v" and direction != "h": | |
print("Direzione non valida!") | |
continue | |
new_matrix = MATRIX # copia dove poter fare casini | |
try: | |
piazzata = piazza_nave(new_matrix, dim, direction, x, y) | |
except IndexError: | |
print("La nave va fuori i confini del campo di battaglia!") | |
except Exception: | |
print("Non puoi sovrapporre le navi!") | |
MATRIX = new_matrix # se tutto ok, aggiorna la matrice vera | |
ship_index += 1 | |
else: # automatica | |
contento = "0" | |
while contento == "0": | |
for dim in SSP: | |
piazzata = False | |
ship_index = 0 | |
new_matrix = MATRIX | |
while piazzata == False: | |
x = random.randint(0, 9) | |
y = random.randint(0, 9) | |
direction = random.choice(["v", "h"]) | |
new_matrix = MATRIX | |
try: | |
piazzata = piazza_nave(new_matrix, dim, direction, x, y) | |
except: | |
pass # semplicemente riprova al ciclo successivo | |
MATRIX = new_matrix | |
ship_index += 1 | |
header() | |
print_matrix(MATRIX) | |
contento = multi_choice("Configurazione automatica completata! \nSei contento della configurazione?", ["Si", "No"]) | |
if contento == "2": # se non contento svuota matrice e rifai da capo | |
MATRIX = [[0 for i in range(10)] for j in range(10)] | |
contento = "0" | |
################################ | |
# STABILIMENTO CONNESSIONE UDP # | |
################################ | |
header() | |
if(SERVER == "0.0.0.0"): | |
print("In attesa di un avversario...") | |
data, addr = SOCKET.recvfrom(1024) # impossibile usare i wrapper perchè non si sa chi è il mittente | |
if data.decode() == "ready": | |
print("Avversario pronto!") | |
SOCKET.sendto("ready".encode(), addr) | |
REMOTE = addr | |
else: | |
REMOTE = (SERVER, PORT) | |
print("In attesa del server...") | |
send("ready") | |
if receive() == "ready": | |
print("Server pronto!") | |
NEXT_TURN_MESSAGE = "Che il gioco abbia inizio!" | |
#################### | |
# INIZIO DEL GIOCO # | |
#################### | |
while True: | |
header() | |
legenda() | |
print(" CAMPO BATTAGLIA AVVERSARIO") | |
print_matrix(ADV_MATRIX) | |
print(" CAMPO BATTAGLIA PROPRIO") | |
print_matrix(MATRIX) | |
if sum([row.count(3) for row in ADV_MATRIX]) == 20: | |
die("Hai vinto!") | |
if sum([row.count(3) for row in MATRIX]) == 20: | |
die("Hai perso!") | |
display_ntm() | |
if mio_turno(): | |
print("È il tuo turno!") | |
x, y = coord_input() | |
send(f"{x},{y}") | |
if receive() == "hit": | |
ADV_MATRIX[y][x] = 3 | |
NEXT_TURN_MESSAGE = f"Hai colpito in ({x}, {y})!" | |
else: | |
ADV_MATRIX[y][x] = 2 | |
NEXT_TURN_MESSAGE = f"Hai sparato in ({x}, {y}) e hai mancato!" | |
else: | |
print("In attesa del turno avversario...") | |
x, y = receive().split(",") | |
x = int(x) | |
y = int(y) | |
if MATRIX[y][x] == 1: | |
MATRIX[y][x] = 3 | |
send("hit") | |
NEXT_TURN_MESSAGE = f"Sei stato colpito in ({x}, {y})!" | |
else: | |
MATRIX[y][x] = 2 | |
send("miss") | |
NEXT_TURN_MESSAGE = f"L' avversario ha sparato in ({x}, {y}) e ha mancato!" | |
# dai controllo all'avversario | |
if CONTROL == 0: | |
CONTROL = 1 | |
else: | |
CONTROL = 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment