Skip to content

Instantly share code, notes, and snippets.

@vittodevit
Created March 10, 2024 18:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vittodevit/ebc85ac89b771cd06f4ef3a5a5c58a6f to your computer and use it in GitHub Desktop.
Save vittodevit/ebc85ac89b771cd06f4ef3a5a5c58a6f to your computer and use it in GitHub Desktop.
Battaglia navale in Python
#!/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