Cours du 4 mai

This commit is contained in:
Adrien Bourmault 2023-05-10 10:09:36 +02:00
parent d359ffe469
commit c28bd609e5
No known key found for this signature in database
GPG Key ID: 6EB408FE0ACEC664
4 changed files with 426 additions and 320 deletions

244
game.py Normal file
View File

@ -0,0 +1,244 @@
#!/usr/bin/env python3
import random, time
## Gestion de partie
def créer_salle_random():
"""
Créer une salle aléatoire
@params void
@return une salle, tuple de taille 4
"""
res0 = True if random.random() * 100 > 50 else False
res1 = True if random.random() * 100 > 50 else False
res2 = True if random.random() * 100 > 50 else False
res3 = True if random.random() * 100 > 50 else False
return (res0, res1, res2, res3)
def créer_dragon(pos):
"""
Créer un dragon dans la salle @pos
@params pos, un tuple
@return un dragon, dictionnaire
"""
niveau = 0
while niveau == 0:
niveau = int(random.random() * 20)
for dragon in dragons:
if dragon["niveau"] == niveau:
niveau = 0
break
return { 'position' : pos, 'niveau' : niveau }
def peupler_donjon(donjon, dragons):
"""
Créer l'état initial du donjon au début du jeu
@params void
@return void
"""
donjon.clear()
dragons.clear()
for i in range(TAILLE_DONJON):
ligne = []
for j in range(TAILLE_DONJON):
ligne.append(créer_salle_random())
if random.random() * 100 > 75: # 25% de chance
dragons.append(créer_dragon((i,j)))
donjon.append(ligne)
def pivoter_donjon(donjon, position):
"""
Pivote la salle pointée par @position dans @donjon
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle
@return void
"""
x = position[0]
y = position[1]
donjon[x][y] = tuple([donjon[x][y][-1]] + list(donjon[x][y][:-1]))
def connecte(donjon, pos0, pos1):
"""
Vérifie que les salles pointées par @pos0 et @pos1 dans @donjon
sont adjacentes et connectées
@params donjon, une liste contenant des salles
pos0, un tuple identifiant une salle
pos1, un tuple identifiant une salle
@return booléen
"""
x0 = pos0[0]
y0 = pos0[1]
x1 = pos1[0]
y1 = pos1[1]
# On vérifie les limites
if x0 < 0 or y0 < 0 or x1 < 0 or y1 < 0:
return False
if x0 >= len(donjon) or y0 >= len(donjon) or x1 >= len(donjon) or y1 >= len(donjon):
return False
# Calcul des distances
axe0 = x0 - x1
axe1 = y0 - y1
distance = abs(axe0) + abs(axe1)
# Vérifier l'adjacence
if distance > 1:
return False
# Chercher point de connexion
if axe1 == 0:
if axe0 <= -1:
# le pôle sud de pos1 touche le pôle nord de pos0
if donjon[x1][y1][S] and donjon[x0][y0][N]:
return True
elif axe0 >= 1:
# le pôle sud de pos0 touche le pôle nord de pos1
if donjon[x0][y0][S] and donjon[x1][y1][N]:
return True
else:
if axe1 <= -1:
# le pôle est de pos1 touche le pôle ouest de pos0
if donjon[x1][y1][E] and donjon[x0][y0][O]:
return True
elif axe1 >= 1:
# le pôle est de pos0 touche le pôle ouest de pos1
if donjon[x0][y0][E] and donjon[x1][y1][O]:
return True
return False
def calcul_chemin(donjon, position, dragons, visite):
"""
Support récursif pour intention
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle (dans laquelle l'aventurier
se trouve)
dragons, une liste de dragons
@return booléen
"""
résultats = []
# Déjà visité
if position in visite:
return None
else:
visite.add(position)
# Cas de base
for dragon in dragons:
if position == dragon["position"]:
return ([position], dragon["niveau"])
# Test récursif des potentielles connexions
x, y = position
if connecte(donjon, position, (x+1,y)):
résultats.append(calcul_chemin(donjon, (x+1,y), dragons, visite))
if connecte(donjon, position, (x-1,y)):
résultats.append(calcul_chemin(donjon, (x-1,y), dragons, visite))
if connecte(donjon, position, (x,y+1)):
résultats.append(calcul_chemin(donjon, (x,y+1), dragons, visite))
if connecte(donjon, position, (x,y-1)):
résultats.append(calcul_chemin(donjon, (x,y-1), dragons, visite))
# Aucun couple dans résultats
if résultats == [None] * len(résultats):
return None
else:
niveau = 0
candidat = (0,0)
for couple in résultats:
if couple is None:
continue
if couple[1] > niveau:
niveau = couple[1]
candidat = (couple[0], couple[1])
return ([position] + candidat[0], candidat[1])
def intention(donjon, position, dragons):
"""
Calcule récursivement le chemin à parcourir jusqu'à un dragon du plus haut
niveau accessible
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle (dans laquelle l'aventurier
se trouve)
dragons, une liste de dragons
@return liste, chemin à parcourir
"""
visite = set()
return calcul_chemin(donjon, position, dragons, visite)
def rencontre(aventurier, dragons):
"""
Vérifie si l'@aventurier est à la même position qu'un dragon de @dragons et
agit en conséquence
@params aventurier, dictionnaire représentant un aventurier
dragons, liste de dragons (dictionnaires)
@return void
"""
versus = False
ennemi = None
for dragon in dragons:
if aventurier["position"] == dragon["position"]:
versus = True
ennemi = dragon
# Un dragon sauvage apparaît !
if versus:
if ennemi["niveau"] <= aventurier["niveau"]:
# Victoire
dragons.remove(ennemi)
aventurier["niveau"] = aventurier["niveau"] + 1
else:
# Décès
aventurier["vivant"] = False
def appliquer_chemin(aventurier, dragons, chemin):
"""
déplace l'aventurier
@return rien
"""
([(2, 1), (2, 0)], 16)
position = chemin[0][0]
chemin[0].remove(position)
aventurier["position"] = position
rencontre(aventurier, dragons)
def fin_partie(aventurier, dragons):
"""
@return 1 si la partie est gagnée (tous les dragons ont été tués),
-1 si la partie est perdue (laventurier a été tué),
0 si la partie continue.
"""
if len(dragons) == 0:
return 1
elif not aventurier["vivant"]:
return -1
else:
return 0

3
graphics.py Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env python3
# Doc FLTK : https://antoinemeyer.frama.io/fltk/

81
maps.py Normal file
View File

@ -0,0 +1,81 @@
#!/usr/bin/env python3
import random, time
## Gestion des maps
def créer_salle(forme_salle):
"""
Créer une salle aléatoire (N,E,S,O)
@params void
@return une salle, tuple de taille 4
"""
correspondance = {
"" : (True,)*4,
"" : (False, False, False, True),
"" : (False, True, False, False),
"" : (False, False, True, False),
"" : (True, False, False, False),
"" : (False, True, True, False),
"" : (False, False, True, True),
"" : (True, False, False, True),
"" : (True, True, False, False),
"" : (True, False, True, False),
"" : (False, True, False, True),
"" : (False, True, True, True),
"" : (True, True, False, True),
"" : (True, True, True, False),
"" : (True, False, True, True)
}
return correspondance[forme_salle]
def charger(fichier, donjon, dragons, aventurier):
"""
Charge un fichier et peuple la structure donjon
@params fichier, chemin d'accès à un fichier
@return 1 ou None
"""
donjon.clear()
dragons.clear()
# Lecture fichier brut
contenu = ""
with open(fichier, 'r') as fichier:
contenu = fichier.read()
try:
# Séparation entre carte et coordonnées des personnages
donjon_map = contenu[:contenu.find("A")-1].split("\n")
donjon_declaration = contenu[contenu.find("A"):].split("\n")
# Création du donjon
for i in range(len(donjon_map[0])):
ligne = []
for j in range(len(donjon_map)):
ligne.append(créer_salle(donjon_map[i][j]))
donjon.append(ligne)
# Création des personnages
for declaration in donjon_declaration:
# Déclaration de l'aventurier
if "A" in declaration:
cible, x, y = declaration.split(" ")
aventurier["position"] = (x,y)
aventurier["niveau"] = 1
# Déclaration d'un dragon
elif "D" in declaration:
cible, x, y, niveau = declaration.split(" ")
dragons.append({ 'position' : (x,y), 'niveau' : niveau })
return 1
except Exception as e:
print("Erreur : {}".format(e))
return None

View File

@ -9,11 +9,14 @@
# - Intention : cible le dragon le plus fort accessible (orgueil)
#
# Doc FLTK : https://antoinemeyer.frama.io/fltk/
import random, fltk
import random, time, fltk, os
import maps
import game
## VARIABLES DE CONFIGURATION
TAILLE_DONJON = 6
LARGEUR_FENETRE = 800
HAUTEUR_FENETRE = 400
## Variables globales
@ -30,340 +33,115 @@ aventurier = {
'vivant': True
}
## Gestion de partie
def créer_salle_random():
## Fonctions
def selection_menu():
"""
Créer une salle aléatoire
Home selection menu
@params void
@return une salle, tuple de taille 4
"""
res0 = True if random.random() * 100 > 50 else False
res1 = True if random.random() * 100 > 50 else False
res2 = True if random.random() * 100 > 50 else False
res3 = True if random.random() * 100 > 50 else False
return (res0, res1, res2, res3)
def créer_dragon(pos):
@return path, chemin d'accès à un fichier de map
"""
Créer un dragon dans la salle @pos
@params pos, un tuple
@return un dragon, dictionnaire
"""
niveau = 0
while niveau == 0:
niveau = int(random.random() * 20)
for dragon in dragons:
if dragon["niveau"] == niveau:
niveau = 0
break
return { 'position' : pos, 'niveau' : niveau }
list_maps = os.listdir("maps")
fltk.cree_fenetre(LARGEUR_FENETRE, HAUTEUR_FENETRE)
fltk.texte(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/8,
"Bienvenue dans Wall is You !",
couleur="black",
taille=40,
ancrage='center')
fltk.texte(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/4,
"Vous allez pouvoir sélectionner un donjon auquel jouer"
" dans la liste ci-dessous."
" Cliquez sur le donjon de votre choix pour y jouer.",
couleur="black",
taille=10,
ancrage='center')
def peupler_donjon():
"""
Créer l'état initial du donjon au début du jeu
@params void
@return void
"""
global donjon
global dragons
fltk.texte(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/3,
"Tapez Echap pour quitter le jeu",
couleur="green",
taille=10,
ancrage='center')
donjon.clear()
dragons.clear()
if len(list_maps) == 0:
fltk.texte(LARGEUR_FENETRE/2, HAUTEUR_FENETRE/2,
"Aucun donjon jouable installé.",
couleur="red",
taille=30,
ancrage='center')
else:
x1 = LARGEUR_FENETRE/40
x2 = HAUTEUR_FENETRE/2.22
y1 = HAUTEUR_FENETRE/2.22
y2 = LARGEUR_FENETRE/3
for i in range(len(list_maps)):
fltk.rectangle(x1, y1, x2, y2, remplissage="white")
fltk.texte(x1+(x2-x1)/2,
y1+(y2-y1)/2,
list_maps[i].replace(".txt", ""),
couleur="blue",
taille=20,
ancrage='center')
x1 += LARGEUR_FENETRE/4
x2 += LARGEUR_FENETRE/4
if max(x1, x2) > LARGEUR_FENETRE:
x1 = LARGEUR_FENETRE/40
x2 = HAUTEUR_FENETRE/2.22
y1 += HAUTEUR_FENETRE/3.5
y2 += HAUTEUR_FENETRE/3.5
for i in range(TAILLE_DONJON):
ligne = []
for j in range(TAILLE_DONJON):
ligne.append(créer_salle_random())
while True:
event = fltk.attend_ev()
if "Quitte" in fltk.type_ev(event):
fltk.ferme_fenetre()
return None
if "Touche" in fltk.type_ev(event) and "Escape" in fltk.touche(event):
fltk.ferme_fenetre()
return None
if "ClicGauche" in fltk.type_ev(event):
# XXX à améliorer
x = fltk.abscisse(event)
y = fltk.ordonnee(event)
if random.random() * 100 > 75: # 25% de chance
dragons.append(créer_dragon((i,j)))
donjon.append(ligne)
def pivoter_donjon(donjon, position):
"""
Pivote la salle pointée par @position dans @donjon
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle
@return void
"""
x = position[0]
y = position[1]
donjon[x][y] = tuple([donjon[x][y][-1]] + list(donjon[x][y][:-1]))
def connecte(donjon, pos0, pos1):
"""
Vérifie que les salles pointées par @pos0 et @pos1 dans @donjon
sont adjacentes et connectées
@params donjon, une liste contenant des salles
pos0, un tuple identifiant une salle
pos1, un tuple identifiant une salle
@return booléen
"""
x0 = pos0[0]
y0 = pos0[1]
x1 = pos1[0]
y1 = pos1[1]
# On vérifie les limites
if x0 < 0 or y0 < 0 or x1 < 0 or y1 < 0:
return False
if x0 >= len(donjon) or y0 >= len(donjon) or x1 >= len(donjon) or y1 >= len(donjon):
return False
# Calcul des distances
axe0 = x0 - x1
axe1 = y0 - y1
distance = abs(axe0) + abs(axe1)
# Vérifier l'adjacence
if distance > 1:
return False
# Chercher point de connexion
if axe1 == 0:
if axe0 <= -1:
# le pôle sud de pos1 touche le pôle nord de pos0
if donjon[x1][y1][S] and donjon[x0][y0][N]:
return True
elif axe0 >= 1:
# le pôle sud de pos0 touche le pôle nord de pos1
if donjon[x0][y0][S] and donjon[x1][y1][N]:
return True
else:
if axe1 <= -1:
# le pôle est de pos1 touche le pôle ouest de pos0
if donjon[x1][y1][E] and donjon[x0][y0][O]:
return True
elif axe1 >= 1:
# le pôle est de pos0 touche le pôle ouest de pos1
if donjon[x0][y0][E] and donjon[x1][y1][O]:
return True
return False
def calcul_chemin(donjon, position, dragons, visite):
"""
Support récursif pour intention
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle (dans laquelle l'aventurier
se trouve)
dragons, une liste de dragons
@return booléen
"""
résultats = []
# Déjà visité
if position in visite:
return None
else:
visite.add(position)
# Cas de base
for dragon in dragons:
if position == dragon["position"]:
return ([position], dragon["niveau"])
# Test récursif des potentielles connexions
x, y = position
if connecte(donjon, position, (x+1,y)):
résultats.append(calcul_chemin(donjon, (x+1,y), dragons, visite))
if connecte(donjon, position, (x-1,y)):
résultats.append(calcul_chemin(donjon, (x-1,y), dragons, visite))
if connecte(donjon, position, (x,y+1)):
résultats.append(calcul_chemin(donjon, (x,y+1), dragons, visite))
if connecte(donjon, position, (x,y-1)):
résultats.append(calcul_chemin(donjon, (x,y-1), dragons, visite))
# Aucun couple dans résultats
if résultats == [None] * len(résultats):
return None
else:
niveau = 0
candidat = (0,0)
for couple in résultats:
if couple is None:
x_i = LARGEUR_FENETRE/40
y_i = HAUTEUR_FENETRE/2.22
x_n = int((x - x_i) / (LARGEUR_FENETRE/4))
y_n = int((y - y_i) / (HAUTEUR_FENETRE/3.5))
if x_n+y_n*4 < 0 or x_n+y_n*4 >= len(list_maps):
continue
if couple[1] > niveau:
niveau = couple[1]
candidat = (couple[0], couple[1])
return ([position] + candidat[0], candidat[1])
def intention(donjon, position, dragons):
"""
Calcule récursivement le chemin à parcourir jusqu'à un dragon du plus haut
niveau accessible
@params donjon, une liste contenant des salles
position, un tuple identifiant une salle (dans laquelle l'aventurier
se trouve)
dragons, une liste de dragons
@return liste, chemin à parcourir
"""
fltk.ferme_fenetre()
return "./maps/" + list_maps[x_n+y_n*4]
visite = set()
return calcul_chemin(donjon, position, dragons, visite)
fltk.ferme_fenetre()
return "./maps/map1.txt"
def rencontre(aventurier, dragons):
def run_game():
"""
Vérifie si l'@aventurier est à la même position qu'un dragon de @dragons et
agit en conséquence
@params aventurier, dictionnaire représentant un aventurier
dragons, liste de dragons (dictionnaires)
Running game
@params void
@return void
"""
versus = False
ennemi = None
for dragon in dragons:
if aventurier["position"] == dragon["position"]:
versus = True
ennemi = dragon
# Un dragon sauvage apparaît !
if versus:
if ennemi["niveau"] <= aventurier["niveau"]:
# Victoire
dragons.remove(ennemi)
aventurier["niveau"] = aventurier["niveau"] + 1
else:
# Décès
aventurier["vivant"] = False
def appliquer_chemin(aventurier, dragons, chemin):
"""
déplace l'aventurier
@return rien
"""
([(2, 1), (2, 0)], 16)
position = chemin[0][0]
chemin[0].remove(position)
aventurier["position"] = position
rencontre(aventurier, dragons)
def fin_partie(aventurier, dragons):
"""
@return 1 si la partie est gagnée (tous les dragons ont été tués),
-1 si la partie est perdue (laventurier a été tué),
0 si la partie continue.
"""
if len(dragons) == 0:
return 1
elif not aventurier["vivant"]:
return -1
else:
return 0
## Gestion des maps
def créer_salle(forme_salle):
"""
Créer une salle aléatoire (N,E,S,O)
@params void
@return une salle, tuple de taille 4
"""
correspondance = {
"" : (True,)*4,
"" : (False, False, False, True),
"" : (False, True, False, False),
"" : (False, False, True, False),
"" : (True, False, False, False),
"" : (False, True, True, False),
"" : (False, False, True, True),
"" : (True, False, False, True),
"" : (True, True, False, False),
"" : (True, False, True, False),
"" : (False, True, False, True),
"" : (False, True, True, True),
"" : (True, True, False, True),
"" : (True, True, True, False),
"" : (True, False, True, True)
}
return correspondance[forme_salle]
def charger(fichier):
"""
Charge un fichier et peuple la structure donjon
@params fichier, chemin d'accès à un fichier
@return 1 ou None
"""
global donjon
global dragons
donjon.clear()
dragons.clear()
# Lecture fichier brut
contenu = ""
with open(fichier, 'r') as fichier:
contenu = fichier.read()
try:
# Séparation entre carte et coordonnées des personnages
donjon_map = contenu[:contenu.find("A")-1].split("\n")
donjon_declaration = contenu[contenu.find("A"):].split("\n")
# Création du donjon
for i in range(len(donjon_map[0])):
ligne = []
for j in range(len(donjon_map)):
ligne.append(créer_salle(donjon_map[i][j]))
donjon.append(ligne)
# Création des personnages
for declaration in donjon_declaration:
# Déclaration de l'aventurier
if "A" in declaration:
cible, x, y = declaration.split(" ")
aventurier["position"] = (x,y)
aventurier["niveau"] = 1
# Déclaration d'un dragon
elif "D" in declaration:
cible, x, y, niveau = declaration.split(" ")
dragons.append({ 'position' : (x,y), 'niveau' : niveau })
return 1
except Exception as e:
print("Erreur : {}".format(e))
return None
## Fonctions graphiques
## Fonction principale
pass
def main():
cree_fenetre(400, 300)
ferme_fenetre()
while True:
map_choice = selection_menu()
if not map_choice:
break
else:
print("chargement de {}".format(map_choice))
if maps.charger(map_choice, donjon, dragons, aventurier):
run_game()
else:
return 1
return 0
main()