Oui, merci je pensais que draw.rect allait me remplir ma surface mais j'ai lu trop vite et j'ai enchainé avec draw.lines, mais là c'est bien mieux.
Donc voici mon code final, j'ai un peu honte de la dernière étape de mon code, c'est long, surtout par rapport au tien josmiley :
#!/usr/bin/env python
from random import choice
import pygame
from pygame.locals import *
WIN_TITLE = "Samegame"
TILE_W = 30
TILE_H = 30
WIDTH, HEIGHT = 12, 6
WIN_W = WIDTH * TILE_W
WIN_H = HEIGHT * TILE_H
COLORS = [(182, 97, 73), \
(219, 168, 102), \
(76, 123, 169), \
(151, 161, 145), \
]
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
class Tile:
def __init__(self, color, dead=False):
self.color = color
self.dead = dead
class Grid:
def __init__(self):
self.grid = []
self.tile_w = TILE_W
self.tile_h = TILE_H
self.mouse_tile = (0, 0)
self.hl_tiles = []
self.visited = []
self.mask = pygame.image.load('mask.png').convert_alpha()
def populate(self, width=TILE_W, height=TILE_H):
self.grid = []
self.grid = [[Tile(choice(COLORS)) for x in range(width)] for y in range(height)]
def display(self, win):
for y, row in enumerate(self.grid):
for x, cell in enumerate(row):
surf_tile = pygame.Surface((self.tile_w, self.tile_h))
surf_tile.fill(cell.color)
if cell.color != BLACK:
surf_tile.blit(self.mask, (0,0))
if (x,y) in self.hl_tiles and len(self.hl_tiles) > 1 :
pygame.draw.rect(surf_tile, WHITE, ( 0, 0, self.tile_w-2, self.tile_h-2 ), 2)
win.blit(surf_tile, (x * self.tile_w, y * self.tile_h))
def onMouseHover(self, coord):
mouse_tile = (coord[0] / self.tile_w, coord[1] / self.tile_h)
self.mouse_tile = mouse_tile
self.hl_tiles = self.highlight(mouse_tile) + [self.mouse_tile]
self.visited = []
def highlight(self, start):
self.visited.append(start)
pos = start
hl_tiles = []
close_tiles = self.__getCloseTiles(start)
for x, y in close_tiles:
if self.__getTileColor( start ) == self.__getTileColor( (x, y) ) and (x, y) not in self.visited and self.__getTileColor(start) != BLACK:
hl_tiles.append( (x, y) )
hl_tiles += self.highlight( (x, y) )
return hl_tiles
def delete(self):
if len(self.hl_tiles) < 2:
return
# set highlighted tiles color to black
# and count the number of black tiles per col
l = [0 for x in range(WIDTH)]
for el in self.hl_tiles:
x, y = el
self.grid[y][x].color = BLACK
l[x] += 1
# move tiles down when empty tiles
for col in list(set(x[0] for x in self.hl_tiles)):
y = HEIGHT - 1
num = l[col]
self.__moveDownTiles(col, num)
# move left when empty cols
numCols = self.__countEmptyCols()
for c in range(numCols):
for x in range(WIDTH):
if self.__isEmptyCol(x):
self.__delCol(x)
self.__addCol()
def __moveDownTiles(self, col, num):
for i in range(num):
for y in range(HEIGHT - 1, -1, -1):
if self.grid[y][col].color == BLACK:
if y > 0:
self.grid[y][col].color = self.grid[y-1][col].color
self.grid[y-1][col].color = BLACK
def __addCol(self):
for y in range(HEIGHT):
self.grid[y].append(Tile(BLACK, True))
def __delCol(self, col):
for y in range(HEIGHT):
del(self.grid[y][col])
def __isEmptyCol(self, col):
count = 0
for y in range(HEIGHT):
if self.grid[y][col].color == BLACK and not self.grid[y][col].dead:
count += 1
if count - 1 == HEIGHT - 1: return True
else: return False
def __countEmptyCols(self):
count = 0
for x in range(WIDTH):
if self.__isEmptyCol(x):
count += 1
return count
def __getCloseTiles(self, pos):
x, y = pos
close_tiles = []
if x - 1 >= 0:
close_tiles.append( (x - 1, y) )
if x + 1 < WIDTH:
close_tiles.append( (x + 1, y) )
if y - 1 >= 0:
close_tiles.append( (x, y - 1) )
if y + 1 < HEIGHT:
close_tiles.append( (x, y + 1) )
return close_tiles
def __getTileColor(self, id):
x, y = id
return self.grid[y][x].color
class Game:
def __init__(self):
pygame.init()
pygame.font.init()
self.font = pygame.font.Font(pygame.font.get_default_font(), 25)
self.screen = pygame.display.set_mode(( WIN_W, WIN_H ))
self.grid = Grid()
self.grid.populate(WIDTH, HEIGHT)
self.score = 0
self.caption = lambda: "["+WIN_TITLE+"] Score : "+str(self.score)
self.onLoop = True
self.gameover = False
def run(self):
while self.isGameOver(): self.grid.populate(WIDTH, HEIGHT)
while self.onLoop:
pygame.time.Clock().tick(30)
for event in pygame.event.get():
if event.type == QUIT:
self.onLoop = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
self.onLoop = False
if event.type == MOUSEMOTION:
self.grid.onMouseHover(pygame.mouse.get_pos())
if event.type == MOUSEBUTTONDOWN:
self.score += (len(self.grid.hl_tiles) - 1)**2
self.grid.delete()
self.grid.onMouseHover(pygame.mouse.get_pos())
self.gameover = self.isGameOver()
self.grid.display(self.screen)
pygame.display.flip()
pygame.display.set_caption(self.caption())
if self.gameover:
self.onLoop = False
self.displayScore()
def displayScore(self):
msg = self.font.render("Final score: "+str(self.score), True, WHITE)
rmsg = msg.get_rect()
rmsg.center = self.screen.get_rect().center
self.screen.blit(msg, rmsg)
pygame.display.flip()
while pygame.event.wait().type != any((QUIT, KEYDOWN, MOUSEBUTTONDOWN)): pass
def isGameOver(self):
adj_tiles = []
for x in range(WIDTH):
for y in range(HEIGHT):
pos = (x, y)
adj_tiles = self.grid.highlight(pos)
self.grid.visited = []
if len(adj_tiles) > 0:
return False
return True
samegame = Game()
samegame.run()
J'ai pas cherché à donné un bonus si le joueur arrive à vider le tableau, pareil pour l'image je t'ai pris la tienne josmiley. J'ai fait pas mal de tests et priori le jeu est complètement fonctionnel avec toutes les features demandés dans l'énoncé.
ouais, ça le fait et j'aime bien les couleurs pastels, bravo!
je me suis permis de modifier un peu.
pour chaque tile tu recrées une surface que tu colories, sur laquelle tu blit et que tu blit ensuite sur win.
là, on travaille directement sur win ...
def display(self, win):
for y, row in enumerate(self.grid):
for x, cell in enumerate(row):
win.fill(cell.color,(x * self.tile_w, y * self.tile_h, self.tile_w, self.tile_h))
if cell.color != BLACK:
win.blit(self.mask,(x * self.tile_w, y * self.tile_h))
if (x,y) in self.hl_tiles and len(self.hl_tiles) > 1 :
pygame.draw.rect(win, WHITE, (x * self.tile_w, y * self.tile_h , self.tile_w-2, self.tile_h-2 ), 2)
Est-ce que tu pourrais me dire quelles sont les notions à connaitre en python pour aborder cet exercice (ce projet)?
Comme ça je peux les rajouter dans le tableau de synthèse des exercices.
J'ai tenté de faire la partie 1, ça a l'air de fonctionner.
Dites moi ce que je pourrais faire pour plus programmer 'python'.
Est-ce que ma fonction 'fill_case' est correcte ? j'ai essayé de faire un truc, ça a l'air de fonctionner...
# -*- coding: UTF-8 -*-
from random import randint
import pygame
from pygame.locals import *
## Constantes
SZ_CASE = 30
TAB_W = 40
TAB_H = 30
SCR_W = TAB_W * SZ_CASE
SCR_H = TAB_H * SZ_CASE
## Variables
col = [(0xD8, 0xD8, 0x00),
(0x50, 0xD2, 0x50),
(0xFD, 0x80, 0x30),
(0x5C, 0x74, 0xD3),
(0xE9, 0xE9, 0xE9)]
## Fonctions
def col_rand():
return col[randint(0, 4)]
def fill_case():
return [[col_rand() for i in xrange(TAB_W)] for j in xrange(TAB_H)]
def draw_screen(screen, tab):
screen.fill((0, 0, 0))
for i in xrange(TAB_H):
for j in xrange(TAB_W):
screen.fill(tab[i][j], (j * SZ_CASE + 1, i * SZ_CASE + 1, SZ_CASE - 2, SZ_CASE - 2))
def main():
pygame.init()
screen = pygame.display.set_mode((SCR_W, SCR_H))
tab = fill_case()
draw_screen(screen, tab)
pygame.display.flip()
done = 0
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = 1
main()
J'ai décidé moi aussi de me lancer dans cet exo. Je suis donc en train d'apprendre pygame en parallèle.
Voici ma version pour la partie 1 :
import pygame
from pygame.locals import *
import random
Case_size = 30
Tab_width, Tab_height = 20, 15
class Case(object):
_cases_colors = ['red','yellow','cyan','green','blue']
def __init__(self):
self.color = random.choice(Case._cases_colors)
def available_colors():
return Case._cases_colors
def display(screen, mat):
# initialise les surfaces dans un dictionnaire
srf = { colorname: pygame.Surface((Case_size, Case_size)) for colorname in Case.available_colors() }
for colorname in srf:
srf[colorname].fill(pygame.Color(colorname))
# blitte les surfaces sur l'ecran. commence depuis le bas
for x,col in enumerate(mat):
h = len(col)
for y,case in enumerate(col):
pos = x * Case_size, (h - (1+y)) * Case_size
print(pos[0], pos[1])
screen.blit(srf[case.color], pos)
pygame.display.flip()
# initialise aléatoirement un tableau 2D
Mat = [[Case() for i in range(Tab_height)] for j in range(Tab_width)]
pygame.init()
Screen = pygame.display.set_mode((Case_size * Tab_width, Case_size * Tab_height))
display(Screen, Mat)
while int(input()):
pass
Au passage, si quelqu'un sait comment télécharger la doc de pygame, ce serait sympa de donner un lien, parce que c'est assez casse-pieds de devoir se connecter pour lire la doc, et je n'ai pas trouvé d'autre solution. Merci.
_______________________
Citation : Pouet_forever
J'ai tenté de faire la partie 1, ça a l'air de fonctionner.
Ah, tiens, bienvenue au club !
Citation : Pouet_forever
Dites moi ce que je pourrais faire pour plus programmer 'python'.
Tout faire pour qu'un codeur C ne puisse pas comprendre ton code.
Plus sérieusement et en général (c.a.d pas vis à vis de ton code que je n'ai pas trop regardé), AMHA, utiliser les outils et paradigmes à ta disposition : fonctions built-ins (comme reverse, enumerate, zip, etc.), dictionnaires, compréhensions (tu t'en sers déjà ), générateurs, iterateurs, decorateurs (parfois), et en général éviter une approche trop "C" (ex. utiliser des index à la place de enumerate, utiliser une liste à la place d'un set dans certains cas).
Enfin bon, c'est l'avis de quelqu'un qui débute et qui se pose les mêmes questions...
Tout faire pour qu'un codeur C ne puisse pas comprendre ton code.
Aïe, je vais ptete changer de langage alors !
Je vais essayer de suivre ce que t'as dit, mais bon il y a des trucs que je connais pas encore et d'autres où je sais pas trop comment l'appliquer.
Ah bon ? Aucun problème chez moi (python 3.2).
C'est légal, ce que je fais, ou on doit faire comme toi ?
De toutes façons, je crois que je vais virer cette classe, son utilisation telle quelle est totalement artificielle.
EDIT :
Bon, avant d'aller me coucher , voici une version "jouable".
2e partie (sauf highlighting) : fait
3e partie : effacement des groupes réalisé
Mon code n'est absolument plus orienté objet, je ne sais pas si c'est bien ou pas. (en tous cas, mon approche orientée performance m’empêche de coder objet trop naïvement, et faire les choses comme il faut me demanderait actuellement un surplus d'efforts non négligeable)
import pygame
from pygame.locals import *
import random
from collections import deque
Case_size = 30
Tab_width, Tab_height = 20, 15
Screen_width, Screen_height = 1 + Case_size * Tab_width, 1 + Case_size * Tab_height
Cases_colors = ['red','yellow','cyan','green','blue']
Cases_srf = {}
def init_srf():
global Cases_srf
# initialise les surfaces dans un dictionnaire
Cases_srf = { colorname: pygame.Surface((Case_size - 1, Case_size - 1)) for colorname in Cases_colors }
for colorname in Cases_srf:
Cases_srf[colorname].fill(pygame.Color(colorname))
def display(screen, mat):
screen.fill(pygame.Color('black'))
# blitte les surfaces sur l'ecran. commence depuis le bas
for x,col in enumerate(mat):
for y,color in enumerate(col):
pos = x * Case_size + 1, (Tab_height - (y + 1)) * Case_size + 1
screen.blit(Cases_srf[color], pos)
pygame.display.flip()
# suppression des colonnes vides
def del_empty_cols(mat):
n = 0
for col in mat:
if len(col) == 0:
del mat[n]
else:
n += 1
def suppr_group(mat, x, y):
if not (len(mat) > x and len(mat[x]) > y):
return 0
counter = 1
color = mat[x][y]
del mat[x][y]
fifo = deque([(x,y)])
while len(fifo) != 0:
x,y = fifo.popleft()
for i,j in ((-1,0),(1,0),(0,-1),(0,0)): # hack : le dernier est à zero car on supprime un élément
_x,_y = x + i, y + j
if _x >= 0 and _x < len(mat) and _y >= 0 and _y < len(mat[_x]) and mat[_x][_y] == color:
del mat[_x][_y]
counter += 1
fifo.append((_x,_y))
del_empty_cols(mat)
return counter
if __name__ == "__main__":
# initialise aléatoirement un tableau 2D
mat = [[random.choice(Cases_colors) for i in range(Tab_height)] for j in range(Tab_width)]
pygame.init()
screen = pygame.display.set_mode((Screen_width, Screen_height))
init_srf()
draw = True
while True:
if draw:
display(screen, mat)
draw = False
event = pygame.event.wait()
if event.type == QUIT:
exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
x,y = (event.pos[0] - 1) // Case_size, Tab_height - 1 - (event.pos[1] - 1) // Case_size
# print(x,y)
suppr_group(mat, x, y)
draw = True
elif event.type == MOUSEMOTION:
pass
soit une variable 'Zone', liste de toutes coordonnées des cases de même couleur en contact entre elles(de bord à bord); la case de référence étant, évidement, celle pointée par la souris.
- Coder une fonction 'memes_cases' qui tiens à jour cette liste et qui 'hightlight' la zone obtenue lorsque 'Zone' contient au moins 2 coordonnées.
sous-entend qu'un groupe de cases éliminable contient au moins 2 cases.
dans ton code je peux éliminer des cases seules.
soit une variable 'Zone', liste de toutes coordonnées des cases de même couleur en contact entre elles(de bord à bord); la case de référence étant, évidement, celle pointée par la souris.
- Coder une fonction 'memes_cases' qui tiens à jour cette liste et qui 'hightlight' la zone obtenue lorsque 'Zone' contient au moins 2 coordonnées.
sous-entend qu'un groupe de cases éliminable contient au moins 2 cases.
dans ton code je peux éliminer des cases seules.
Oui, je m'en suis rendu compte aussi (j'ai déja joué à ce jeu ).
Sinon, mon algo était faux, j'ai du le modifier...
Voici mon code final (remplit pratiquement toutes les reccomandations) :
import pygame
from pygame.locals import *
import random
from collections import deque, defaultdict
# variables globales
Case_size = 30
Tab_width, Tab_height = 20, 15
Screen_width, Screen_height = 1 + Case_size * Tab_width, 1 + Case_size * Tab_height
Cases_colors = ['red','yellow','cyan','green','blue']
Cases_srf = {}
H_srf = None
# initialise les surfaces à blitter
def init_surfaces():
global Cases_srf, H_srf
# initialise les surfaces dans un dictionnaire
Cases_srf = { colorname: pygame.Surface((Case_size - 1, Case_size - 1)) for colorname in Cases_colors }
for colorname in Cases_srf:
Cases_srf[colorname].fill(pygame.Color(colorname))
# prepare une surface spéciale pour le highlighting
H_srf = pygame.Surface((Case_size - 1, Case_size - 1))
H_srf.fill(pygame.Color('white'))
pygame.draw.rect(H_srf, pygame.Color('black'), pygame.Rect(2,2,Case_size-5,Case_size-5) )
H_srf.set_colorkey((0,0,0))
# affichage
def display(screen, mat, paint_region = None):
screen.fill(pygame.Color('black'))
# blitte les surfaces sur l'ecran. commence depuis le bas
for x,col in enumerate(mat):
for y,color in enumerate(col):
pos = x * Case_size + 1, (Tab_height - (y + 1)) * Case_size + 1
screen.blit(Cases_srf[color], pos)
if paint_region != None:
for x,y in paint_region:
pos = x * Case_size + 1, (Tab_height - (y + 1)) * Case_size + 1
screen.blit(H_srf, pos)
pygame.display.flip()
# suppression des colonnes vides
def del_empty_cols(mat):
n = 0
for k in range(len(mat)):
if mat[k-n] == []:
del mat[k-n]
n += 1
# suppression d'une region
def suppr_region(mat, region):
d = defaultdict(list)
for x,y in region:
d[x].append(y)
for x,lst in d.items():
lst.sort()
n = 0
for y in lst:
del mat[x][y-n]
n += 1
del_empty_cols(mat)
return len(region)
# comptage et enregistrement des regions
def count_regions(mat):
registered_cases = {}
for X,col in enumerate(mat):
for Y,color in enumerate(col):
if (X,Y) not in registered_cases:
region = []
registered_cases[(X,Y)] = region
fifo = deque([(X,Y)])
while len(fifo) != 0:
x,y = fifo.popleft()
region.append((x,y))
for i,j in ((-1,0),(1,0),(0,-1),(0,1)):
_x,_y = x + i, y + j
if (_x >= 0 and _x < len(mat) and _y >= 0 and _y < len(mat[_x])
and (_x,_y) not in registered_cases and mat[_x][_y] == color):
registered_cases[(_x,_y)] = region
fifo.append((_x,_y))
return registered_cases
# teste s'il reste des regions à supprimer
def continuer_jeu(regions):
return max({len(reg) for reg in regions.values()}) > 1
# main
if __name__ == "__main__":
# initialise aléatoirement un tableau 2D
mat = [[random.choice(Cases_colors) for i in range(Tab_height)] for j in range(Tab_width)]
regions = count_regions(mat)
pygame.init()
screen = pygame.display.set_mode((Screen_width, Screen_height))
init_surfaces()
score = 0
display(screen, mat)
while continuer_jeu(regions):
event = pygame.event.wait()
if event.type == QUIT:
exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
x,y = (event.pos[0] - 1) // Case_size, Tab_height - 1 - (event.pos[1] - 1) // Case_size
if (x,y) in regions and len(regions[(x,y)]) > 1:
n = suppr_region(mat, regions[(x,y)])
score += (n-1) ** 2
print(n, ' elements supprimes, score : ', score)
regions = count_regions(mat)
display(screen, mat)
elif event.type == MOUSEMOTION:
x,y = (event.pos[0] - 1) // Case_size, Tab_height - 1 - (event.pos[1] - 1) // Case_size
if (x,y) in regions:
display(screen, mat, regions[(x,y)] if len(regions[(x,y)]) > 1 else None)
print('Fin de la partie,\n votre score est de ', score, ' points')
screenshot :
Quelques explications sur ma démarche :
- Concernant la suppression de régions, tout se passe directement dans le tableau2d contenant les cases. En fait, chaque sous-liste représente une pile d'éléments, ce qui correspond bien à la gravité dans le jeu : lorsqu'on supprime un élément, ceux du dessus descendent. Si une pile est vide, on la supprime du tableau.
- Concernant le highlighting, voici comment je procède : je calcule une seule fois à chaque modification du tableau toutes les régions et les associer avec chaque cases, ensuite il suffit de récupérer à chaque mouvement de souris directement la région voulue et le mettre en surbrillance. Ca m'a semblé nettement plus efficace que refaire le parcours en profondeur à chaque déplacement de souris.
- Je n'ai finalement pas utilisé de POO.
J'ai encore raccourci en remplaçant cette portion du code :
# suppression des colonnes vides
def del_empty_cols(mat):
n = 0
for k in range(len(mat)):
if mat[k-n] == []:
del mat[k-n]
n += 1
# suppression d'une region
def suppr_region(mat, region):
d = defaultdict(list)
for x,y in region:
d[x].append(y)
for x,lst in d.items():
lst.sort()
n = 0
for y in lst:
del mat[x][y-n]
n += 1
del_empty_cols(mat)
return len(region)
par ce code plus court (ça devrait te plaire ) :
# suppression d'une region
def suppr_region(mat, region):
d = defaultdict(set)
for x,y in region:
d[x].append(y)
for x in d.keys():
mat[x][:] = [color for y,color in enumerate(mat[x]) if y not in d[x]]
# ensuite, suppression des colonnes vides
mat[:] = [pile for pile in mat if pile != []]
return len(region)
haaaaa, d'où la question sur l'autre post
héhé, toi tu vas devenir un byte-cruncher
Bien vu.
Mais il ne s'agissait pas seulement de gagner des lignes, c’était surtout que j'avais fait plutôt un sale bricolage...
edit [15/08/2011] :
Version complète (encore légèrement modifiée, j'ai aussi viré la fonction continuer_jeu() qui ne servait à rien) :
import pygame
from pygame.locals import *
import random
from collections import deque, defaultdict
# variables globales
Case_size = 30
Tab_width, Tab_height = 20, 15
Screen_width, Screen_height = 1 + Case_size * Tab_width, 1 + Case_size * Tab_height
Cases_colors = ['red','yellow','cyan','green','blue']
Cases_srf = {}
H_srf = None
# initialise les surfaces à blitter
def init_surfaces():
global Cases_srf, H_srf
# initialise les surfaces dans un dictionnaire
Cases_srf = { colorname: pygame.Surface((Case_size - 1, Case_size - 1)) for colorname in Cases_colors }
for colorname in Cases_srf:
Cases_srf[colorname].fill(pygame.Color(colorname))
# prepare une surface spéciale pour le highlighting
H_srf = pygame.Surface((Case_size - 1, Case_size - 1))
H_srf.fill(pygame.Color('white'))
pygame.draw.rect(H_srf, pygame.Color('black'), pygame.Rect(2,2,Case_size-5,Case_size-5) )
H_srf.set_colorkey((0,0,0))
# affichage
def display(screen, mat, paint_region = None):
screen.fill(pygame.Color('black'))
# blitte les surfaces sur l'ecran. commence depuis le bas
for x,pile in enumerate(mat):
for y,color in enumerate(pile):
pos = x * Case_size + 1, (Tab_height - (y + 1)) * Case_size + 1
screen.blit(Cases_srf[color], pos)
# met la region en surbrillance
if paint_region != None:
for x,y in paint_region:
pos = x * Case_size + 1, (Tab_height - (y + 1)) * Case_size + 1
screen.blit(H_srf, pos)
pygame.display.flip()
# suppression d'une region
def suppr_region(mat, region):
for x,pile in enumerate(mat):
mat[x] = [color for y,color in enumerate(pile) if (x,y) not in region]
# ensuite, suppression des colonnes vides
mat[:] = [pile for pile in mat if pile != []]
return len(region)
# comptage et enregistrement des régions
def count_regions(mat):
registered_cases = {}
for X,pile in enumerate(mat):
for Y,color in enumerate(pile):
if (X,Y) not in registered_cases:
region = {(X,Y)}
fifo = deque([(X,Y)])
while len(fifo) != 0:
x,y = fifo.popleft()
region.add((x,y))
for i,j in ((-1,0),(1,0),(0,-1),(0,1)):
_x,_y = x + i, y + j
if (_x >= 0 and _x < len(mat) and _y >= 0 and _y < len(mat[_x])
and (_x,_y) not in registered_cases and mat[_x][_y] == color):
fifo.append((_x,_y))
registered_cases[_x,_y] = region
return registered_cases
# main
if __name__ == '__main__':
# initialise aléatoirement un tableau 2D
mat = [[random.choice(Cases_colors) for i in range(Tab_height)] for j in range(Tab_width)]
regions = count_regions(mat)
pygame.init()
screen = pygame.display.set_mode((Screen_width, Screen_height))
init_surfaces()
score = 0
display(screen, mat)
while len(regions) != 0:
event = pygame.event.wait()
if event.type == QUIT:
exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
x,y = (event.pos[0] - 1) // Case_size, Tab_height - 1 - (event.pos[1] - 1) // Case_size
if (x,y) in regions:
n = suppr_region(mat, regions[x,y])
score += (n-1) ** 2
print(n, ' elements supprimes, score : ', score)
regions = count_regions(mat)
display(screen, mat)
elif event.type == MOUSEMOTION:
x,y = (event.pos[0] - 1) // Case_size, Tab_height - 1 - (event.pos[1] - 1) // Case_size
display(screen, mat, regions[x,y] if (x,y) in regions else None)
print('Fin de la partie,\n votre score est de ', score, ' points')
j'peux pas laisser passer ça ...
c'est illisible, ça pourrait être plus court mais serait plus lent à l'affichage; c'est un compromis ...
je me suis même permis une petite fantaisie ...
from pygame import*;import random as r;R,E,d,z,s,m=range,enumerate,display,[],0,mouse;S=d.set_mode((600,500)).fill
A=[[r.choice((2631,420,4095,4025,1064))**2 for y in R(25)]for x in R(30)] # creation du tableau
while event.wait().type!=QUIT: # temps qu'on ne quitte pas
X,Y=m.get_pos();X,Y=X/20,24-Y/20 # position dans le tableau
if not(X,Y)in z: # si on pointe un groupe different de cases
z=[(X,Y)]if A[X][Y]else[] # initialise la recherche en profondeur
[z.append((a,b))for x,y in z for a,b in(x-1,y),(x,y-1),(x+1,y),(x,y+1)if(0<=a<30)&(0<=b<25)and(A[a][b]==A[X][Y])&((a,b)not in z)] # la recherche elle-meme
[S((len(z)>1)&((x,y)in z)and-1 or c,(x*20,480-y*20,18,18))for x,l in E(A)for y,c in E(l)];d.flip() # (re)dessine le tableau
if m.get_pressed()[0]&(len(z)>1): # si clic sur une zone
#uncomment for anim#[d.update([S(0,Rect(x*20,480-y*20,18,18).inflate(-e,-e))for x,y in z])for e in R(18,-4,-2)if time.wait(50)]
for x,y in sorted(z,reverse=1):A[x].pop(y);A[x]+=[0] # supression des cases cliquees
A.sort(None,any,1);s+=(len(z)-1)**2;z=[]# supression des colonnes vides;calcule du score;force le redrawing du tableau
d.set_caption((not any([j==i[e]for i in A+zip(*A)for e,j in E(i[1:])if j])and"c'est fini, "or"")+"score = "+str(s)) # affichage du score/score final
Bonjour tout le monde.
Voici mon code source (qui fonctionne) pour la première partie de cet exercice.
Je pense que tout est bien expliqué, et que n'importe quelle personne pourrait le comprendre. Une code source d'un débutant pour des débutants .
#Nom du fichier: |main.py
#Crée le: |06 Septembre 2011
#Dernière modification le: |06 Septembre 2011
#Par: |Realmagma
#Rôle du fichier: |Gère le bon fonctionnement d'une partie.
#--------------------------|
#--------------------------|
from random import choice
from sys import exit
import pygame
from pygame.locals import *
FRAME = 30
TAILLE_BLOC = 30
NB_BLOC_MAX_COLONNE = 20
NB_BLOC_MAX_LIGNE = 20
HAUTEUR_ECRAN = TAILLE_BLOC * NB_BLOC_MAX_COLONNE
LARGEUR_ECRAN = TAILLE_BLOC * NB_BLOC_MAX_LIGNE
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Principale> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Principale():
"""Classe gérant la fenêtre principale du jeu."""
def __init__(self, parent = None):
#Initialisation de la variable /parent/ de cette classe
#Invocation de la méthode *_initialisation_pygame*
#On instancie un objet /i_jeu/ de la classe <Jeu>
#
self.parent = parent
self._initialisation_pygame()
self.i_jeu = Jeu(self)
def _initialisation_pygame(self):
"""'''''''''''''''''''''''''''''''''''''''''''
- Initialise pygame.
- Créer une fenêtre en suivant les constantes.
- Initialise le titre de la fenêtre.
'''''''''''''''''''''''''''''''''''''''''''"""
#(1)(2)(3)
pygame.init()
self.screen = pygame.display.set_mode((LARGEUR_ECRAN, HAUTEUR_ECRAN))
pygame.display.set_caption("'Jeu surprise' par Josmiley.")
def nouvelle_partie(self):
"""''''''''''''''''''''''''
- Exécute la méthode *nouvelle_partie* de l'objet /i_jeu/.
''''''''''''''''''''''''"""
self.i_jeu.nouvelle_partie()
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Jeu> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Jeu(pygame.sprite.Sprite):
"""Classe <Jeu> héritant de <pygame.sprite.Sprite>."""
def __init__(self, parent):
pygame.sprite.Sprite.__init__(self)
self.parent = parent
self._horloge = pygame.time.Clock()
self.l_matrice = []
self.couleur = [(255,0,0), (0,255,0), (0,0,255),\
(255,255,0),(0,255,255), (255,0,255)]
#Correspond a une espacement de x pixels entre chaque bloc
self._espacement = 2
def nouvelle_partie(self):
"""''''''''''''''''''''''''''''''''''''''''''''''''
- Remet toutes les variables à leur état d'origine.
- On appelle la méthode *_mainloop*.
''''''''''''''''''''''''''''''''''''''''''''''''"""
#Ici on initialise les variables
#Là on appelle la méthode *_mainloop*
self._mainloop()
def creer_remplire_matrice(self):
"""''''''''''''''''''''''''''''''''''''''''''''
- Transforme /l_matrice/ en une matrice 2D.
- Instancie <Case(couleur)> pour chaque membre.
- L'instantation d'une couleur est aléatoire.
''''''''''''''''''''''''''''''''''''''''''''"""
for colonne in range(NB_BLOC_MAX_COLONNE):
self.l_matrice.append([Case(choice(self.couleur)) for colonne in range(NB_BLOC_MAX_LIGNE)])
def _afficher(self):
"""''''''''''''''''''''''''''''''''''
- Affiche le contenu de la matrice 2D.
'''''''''''''''''''''''''''''''''''"""
#Efface l'écran
self.parent.screen.fill(0)
for col in range(NB_BLOC_MAX_COLONNE):
for ligne in range(NB_BLOC_MAX_LIGNE):
self.parent.screen.fill(self.l_matrice[col][ligne].couleur, \
(col*TAILLE_BLOC, ligne*TAILLE_BLOC, TAILLE_BLOC-self._espacement, TAILLE_BLOC-self._espacement))
#On rafraîchit le tout
pygame.display.flip()
def _mainloop(self):
"""'''''''''''''''''''''''''''''''''''''
- Boucle principale du jeu en lui même.
- Gère les évènements clavier et souris.
'''''''''''''''''''''''''''''''''''''"""
continuer = True
##ESSAI
self.creer_remplire_matrice()
self._afficher()
##FIN ESSAI
while continuer:
self._horloge.tick(FRAME)
for event in pygame.event.get():
#Si on clique sur la croix, on quitte.
if event.type == pygame.QUIT:
pygame.quit()
return
#Gestion de la souris
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
#Si c'est un clique-GAUCHE
if pygame.mouse.get_pressed() == (1, 0, 0):
print("Clique gauche: {0};{1} soit {2};{3}".format(\
mouse_x, mouse_y, \
mouse_x//TAILLE_BLOC, mouse_y//TAILLE_BLOC))
#Si c'est un clique-DROIT
elif pygame.mouse.get_pressed() == (0, 0, 1):
print("Clique droit:{0};{1} soit {2};{3}".format(\
mouse_x, mouse_y, \
mouse_x//TAILLE_BLOC, mouse_y//TAILLE_BLOC))
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Case> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Case():
"""Classe <Case> représentant une cellule dans un tableau"""
def __init__(self, couleur):
"""''''''''''''''''''''''''''
- /couleur/ est de type "rgb"
''''''''''''''''''''''''''"""
self.couleur = couleur
if __name__ == "__main__":
p = Principale()
p.nouvelle_partie()
exit(0)
Voici mon code pour la partie n°2. Le hightlight fonctionne correctement.
J'ai commencé à coder la partie n°3 de cet exercice depuis des heures et voici ce que j'ai obtenu: Des bugs...
Ils sont assez bizard, voyez par vous-même.
Comment y remédier ?
Des suggestions seront les bienvenues. En attendant je vous redonne mon code-source (ayant bien évidemment changé )
Merci d'avance.
#Nom du fichier: |main.py
#Crée le: |06 Septembre 2011
#Dernière modification le: |07 Septembre 2011
#Par: |Realmagma
#Rôle du fichier: |Gère le bon fonctionnement d'une partie.
#--------------------------|
#--------------------------|
from random import choice
from sys import exit
import pygame
from pygame.locals import *
FRAME = 30
TAILLE_BLOC = 30
NB_BLOC_MAX_COLONNE = 20
NB_BLOC_MAX_LIGNE = 20
HAUTEUR_ECRAN = TAILLE_BLOC * NB_BLOC_MAX_COLONNE
LARGEUR_ECRAN = TAILLE_BLOC * NB_BLOC_MAX_LIGNE
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Principale> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Principale():
"""Classe gérant la fenêtre principale du jeu."""
def __init__(self, parent = None):
#Initialisation de la variable /parent/ de cette classe
#Invocation de la méthode *_initialisation_pygame*
#On instancie un objet /i_jeu/ de la classe <Jeu>
#
self.parent = parent
self._initialisation_pygame()
self.i_jeu = Jeu(self)
def _initialisation_pygame(self):
"""'''''''''''''''''''''''''''''''''''''''''''
- Initialise pygame.
- Créer une fenêtre en suivant les constantes.
- Initialise le titre de la fenêtre.
'''''''''''''''''''''''''''''''''''''''''''"""
pygame.init()
self.screen = pygame.display.set_mode((LARGEUR_ECRAN, HAUTEUR_ECRAN))
pygame.display.set_caption("'Jeu surprise' par Josmiley.")
def nouvelle_partie(self):
"""''''''''''''''''''''''''
- Exécute la méthode *nouvelle_partie* de l'objet /i_jeu/.
''''''''''''''''''''''''"""
self.i_jeu.nouvelle_partie()
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Jeu> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Jeu(pygame.sprite.Sprite):
"""Classe <Jeu> héritant de <pygame.sprite.Sprite>."""
def __init__(self, parent):
pygame.sprite.Sprite.__init__(self)
self.parent = parent
self._horloge = pygame.time.Clock()
self.l_matrice = []
self.couleur = [(255,0,0),(0,255,0), (0,0,255), (255,255,0),\
(0,255,255)]
#Correspond a une espacement de x pixels entre chaque bloc
self._espacement = 2
#Couleur de référence de la case pointée.
self.couleurAct = None
self.l_zone = []
def nouvelle_partie(self):
"""''''''''''''''''''''''''''''''''''''''''''''''''
- Remet toutes les variables à leur état d'origine.
- On appelle la méthode *_mainloop*.
''''''''''''''''''''''''''''''''''''''''''''''''"""
#Ici on initialise les variables
#Là on appelle la méthode *_mainloop*
self._mainloop()
def creer_remplire_matrice(self):
"""''''''''''''''''''''''''''''''''''''''''''''
- Transforme /l_matrice/ en une matrice 2D.
- Instancie <Case(couleur)> pour chaque membre.
- L'instantation d'une couleur est aléatoire.
''''''''''''''''''''''''''''''''''''''''''''"""
for colonne in range(NB_BLOC_MAX_COLONNE):
self.l_matrice.append([Case(choice(self.couleur)) for colonne in range(NB_BLOC_MAX_LIGNE)])
def _afficher(self):
"""''''''''''''''''''''''''''''''''''
- Affiche le contenu de la matrice 2D.
'''''''''''''''''''''''''''''''''''"""
#Efface l'écran
self.parent.screen.fill(0)
for col in range(NB_BLOC_MAX_COLONNE):
for ligne in range(NB_BLOC_MAX_LIGNE):
self.parent.screen.fill(self.l_matrice[col][ligne].couleur, \
(col*TAILLE_BLOC, ligne*TAILLE_BLOC, TAILLE_BLOC-self._espacement, TAILLE_BLOC-self._espacement))
for i in self.l_zone:
pygame.draw.rect(self.parent.screen, (255,255,255), ((i[0]*TAILLE_BLOC, i[1]*TAILLE_BLOC),(TAILLE_BLOC-self._espacement,TAILLE_BLOC-self._espacement)),self._espacement)
#On rafraîchit le tout
pygame.display.flip()
def _mainloop(self):
"""'''''''''''''''''''''''''''''''''''''
- Boucle principale du jeu en lui même.
- Gère les évènements clavier et souris.
'''''''''''''''''''''''''''''''''''''"""
continuer = True
self.creer_remplire_matrice()
pygame.mouse.set_pos(300,300)
while continuer:
self._horloge.tick(FRAME)
event = pygame.event.wait()
#On récupère la position de la souris
#La couleurAct devient la celle de la case pointée
mouse_x, mouse_y = pygame.mouse.get_pos()
self.couleurAct = self.l_matrice[mouse_x//TAILLE_BLOC][mouse_y//TAILLE_BLOC].couleur
if self.couleurAct == (0,0,0): self.couleurAct = None
#Si on clique sur la croix, on quitte.
if event.type == pygame.QUIT:
pygame.quit()
return
#Déplacement de la souris
elif event.type == pygame.MOUSEMOTION:
#On remet à zéro /l_zone/
#On trouve le hightlight à chaque déplacement de la souris
self.l_zone = []
self._hightlight(mouse_x//TAILLE_BLOC, mouse_y//TAILLE_BLOC)
#Clique gauche
elif event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed() == (1, 0, 0):
#self._fillBlack()
self._descendreBloc()
#On affiche quoi qu'il arrive
self._afficher()
def _hightlight(self, col, ligne):
"""''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
- (1) Dans les 8 cases qui entourent la case actuelle.
- (2) Si certaines sont de la même couleur, elle sont hightlightés.
- (3) Récursion sur cette case si les indices n'ontpas été ajouté a
/l_zone/.
- (4) Et que ce n'est pas une case en diagonale.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"""
for ii in range(max(0, col-1), min(col+2, NB_BLOC_MAX_COLONNE)):
for jj in range(max(0, ligne-1), min(ligne+2, NB_BLOC_MAX_LIGNE)):
if self.l_matrice[ii][jj].couleur == self.couleurAct and (ii, jj) not in self.l_zone:
if not (ii,jj) in ((col-1,ligne-1), (col-1,ligne+1), (col+1,ligne-1), (col+1,ligne+1)):
self.l_zone.append((ii, jj))
self._hightlight(ii, jj)
def _fillBlack(self):
"""'''''''''''''''''''''''''''''''''''''''''''''
- Remplit la zone hightlitée en noir pour essai.
- Méthode à supprimer si problème résolu.
'''''''''''''''''''''''''''''''''''''''''''''"""
for i in self.l_zone:
self.l_matrice[i[0]][i[1]].couleur = (0,0,0)
def _descendreBloc(self):
"""'''''''''''''''''''''''''''''''''''''''''''''''''
- L'idée est de supprimer les indexs de la matrice
qui permettent de faire descendre la colonne.
- On rajoute alors une case noire en haut de la pile
pour créer l'effet que la colonne descend.
'''''''''''''''''''''''''''''''''''''''''''''''''"""
for i in self.l_zone:
del(self.l_matrice[i[1]][i[0]])
self.l_matrice[i[1]].insert(0, Case((0,0,0)))
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
#-*-*- <Les Classes> || Début de <Case> -*-*-#
#-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*#
class Case():
"""Classe <Case> représentant une cellule dans un tableau"""
def __init__(self, couleur):
"""''''''''''''''''''''''''''
- /couleur/ est de type "rgb"
''''''''''''''''''''''''''"""
self.couleur = couleur
if __name__ == "__main__":
p = Principale()
p.nouvelle_partie()
exit(0)
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.