Reduced the usage of magic numbers in the code, it's more verbose now but a little easier to read. Introduced position and velocity to each marble, instead of calculating them in __draw__ on the fly.

This commit is contained in:
2014-06-03 17:28:13 -07:00
parent d35e90e3fe
commit 53b231a6b8

View File

@@ -37,11 +37,21 @@ class Game:
COLOR_BLACK = (0, 0, 0, 255) COLOR_BLACK = (0, 0, 0, 255)
SCREEN_WIDTH = 800 SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600 SCREEN_HEIGHT = 600
STATE_FALLING = 0
STATE_NONE = 1 STATE_NONE = 0
STATE_FALLING = 1
STATE_SELECTED = 2 STATE_SELECTED = 2
STATE_DEAD = 3 STATE_DEAD = 3
M_IDX_MOVES = 0
M_IDX_TYPE = 1
M_IDX_STATE = 2
M_IDX_POS = 3
M_IDX_VEL = 4
P_IDX_X = 0
P_IDX_Y = 1
def __init__(self): def __init__(self):
pygame.init() pygame.init()
self.__display__ = pygame.display.set_mode((Game.SCREEN_WIDTH, Game.SCREEN_HEIGHT)) self.__display__ = pygame.display.set_mode((Game.SCREEN_WIDTH, Game.SCREEN_HEIGHT))
@@ -54,7 +64,7 @@ class Game:
self.__moves__ = 0 self.__moves__ = 0
self.__maxMarbleMoves__ = 4 self.__maxMarbleMoves__ = 4
self.__selectedMarble__ = [-1, -1] self.__setSelectedMarble__([-1, -1])
self.__selectionRect__ = None self.__selectionRect__ = None
self.__selectionSurface__ = pygame.Surface( self.__selectionSurface__ = pygame.Surface(
(Game.MARBLE_WIDTH, Game.MARBLE_HEIGHT), (Game.MARBLE_WIDTH, Game.MARBLE_HEIGHT),
@@ -75,37 +85,47 @@ class Game:
def __setMap__(self, maparray): def __setMap__(self, maparray):
self.__curMap__ = [] self.__curMap__ = []
for row in maparray:
mrow = []
self.__curMap__.append(mrow)
for col in row:
mrow.append([self.__maxMarbleMoves__, col, Game.STATE_NONE, 0])
self.__curMapRect__ = pygame.Rect( self.__curMapRect__ = pygame.Rect(
((Game.SCREEN_WIDTH - (Game.MARBLE_WIDTH * len(self.__curMap__[0])))/2), ((Game.SCREEN_WIDTH - (Game.MARBLE_WIDTH * len(maparray[0])))/2),
((Game.SCREEN_HEIGHT - (Game.MARBLE_HEIGHT * len(self.__curMap__)))/2), ((Game.SCREEN_HEIGHT - (Game.MARBLE_HEIGHT * len(maparray)))/2),
(Game.MARBLE_WIDTH * len(self.__curMap__[0])), (Game.MARBLE_WIDTH * len(maparray[0])),
(Game.MARBLE_HEIGHT * len(self.__curMap__)) (Game.MARBLE_HEIGHT * len(maparray))
) )
x = self.__curMapRect__.left
y = self.__curMapRect__.top
for row in maparray:
x = self.__curMapRect__.left
mrow = []
self.__curMap__.append(mrow)
for col in row:
mrow.append(
[self.__maxMarbleMoves__,
col,
Game.STATE_NONE,
[x, y],
[0, 0]])
x += Game.MARBLE_WIDTH
y += Game.MARBLE_HEIGHT
def __update__(self):
return
def __draw__(self): def __draw__(self):
self.__display__.fill(Game.COLOR_BLACK) self.__display__.fill(Game.COLOR_BLACK)
self.__blitTarget__.fill(Game.COLOR_MAGICPINK) self.__blitTarget__.fill(Game.COLOR_MAGICPINK)
if not self.__curMap__: if not self.__curMap__:
return return
x = self.__curMapRect__.left
y = self.__curMapRect__.top
for row in self.__curMap__: for row in self.__curMap__:
x = self.__curMapRect__.left
for col in row: for col in row:
if col[1]: if col[Game.M_IDX_TYPE]:
self.__blitTarget__.blit(self.__marbles__[col[1]], (x, y)) x = col[Game.M_IDX_POS][Game.P_IDX_X]
text = self.__gameFont__.render("{}".format(col[0]), 1, Game.COLOR_WHITE) y = col[Game.M_IDX_POS][Game.P_IDX_Y]
self.__blitTarget__.blit(self.__marbles__[col[Game.M_IDX_TYPE]], (x, y))
text = self.__gameFont__.render("{}".format(col[Game.M_IDX_MOVES]), 1, Game.COLOR_WHITE)
textpos = text.get_rect(right = x + (Game.MARBLE_WIDTH), textpos = text.get_rect(right = x + (Game.MARBLE_WIDTH),
top = y) top = y)
self.__blitTarget__.blit(text, textpos) self.__blitTarget__.blit(text, textpos)
x += Game.MARBLE_WIDTH
y += Game.MARBLE_HEIGHT
if self.__selectionRect__ : if self.__selectionRect__ :
self.__blitTarget__.blit( self.__blitTarget__.blit(
self.__selectionSurface__, self.__selectionSurface__,
@@ -116,8 +136,8 @@ class Game:
def __canSelectMarble__(self, x, y): def __canSelectMarble__(self, x, y):
if self.__selectedMarble__ == [-1, -1]: if self.__selectedMarble__ == [-1, -1]:
return True return True
curx = self.__selectedMarble__[0] curx = self.__selectedMarble__[Game.P_IDX_X]
cury = self.__selectedMarble__[1] cury = self.__selectedMarble__[Game.P_IDX_Y]
selectable = [ selectable = [
[curx, cury - 1], # --S-- [curx, cury - 1], # --S--
[curx - 1, cury], # -SX-- [curx - 1, cury], # -SX--
@@ -126,58 +146,130 @@ class Game:
] ]
if [x, y] not in selectable: if [x, y] not in selectable:
return False return False
#if self.__curMap__[y][x] != self.__curMap__[cury][curx] : if self.__curMap__[y][x][Game.M_IDX_STATE] != Game.STATE_NONE:
# print "Neighbor at ({}, {}) is type {} while I am {}".format(x, y, self.__curMap__[cury][curx], self.__curMap__[y][x]) return False
# return False
return True return True
def __flipMarbles__(self, m1, m2): def __flipMarbles__(self, m1, m2):
if self.__selectedMarble__ == [-1, -1]: if self.__selectedMarble__ == [-1, -1]:
return return
# Skip empty (black) marbles # Skip empty (black) marbles
if ( ( self.__curMap__[m1[1]][m1[0]][0] == 0 ) or if ( ( self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) or
( self.__curMap__[m2[1]][m2[0]][0] == 0 ) ): ( self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) ):
return return
tmp = self.__curMap__[m1[1]][m1[0]] # Swap marbles
self.__curMap__[m1[1]][m1[0]] = self.__curMap__[m2[1]][m2[0]] tmp = self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]]
self.__curMap__[m2[1]][m2[0]] = tmp self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]] = self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]]
self.__curMap__[m1[1]][m1[0]][0] -= 1 self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]] = tmp
self.__curMap__[m2[1]][m2[0]][0] -= 1
# Swap positions of the marbles
tmp = self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_POS]
self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_POS] = self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_POS]
self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_POS] = tmp
# Decrement movecount remaining on both marbles
self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1
self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1
self.__setSelectedMarble__(m2)
def __setMarbleState__(self, x, y, state): def __setMarbleState__(self, x, y, state):
self.__curMap__[y][x][2] = state self.__curMap__[y][x][2] = state
def __mouseClicked__(self, event): def __setSelectedMarble__(self, pos):
mouse_x = event.pos[0] self.__selectedMarble__ = pos
mouse_y = event.pos[1] if pos == [-1, -1]:
marble_x = ( (mouse_x - self.__curMapRect__.left) / Game.MARBLE_WIDTH)
marble_y = ( (mouse_y - self.__curMapRect__.top) / Game.MARBLE_HEIGHT)
if ( ( not self.__curMapRect__.collidepoint((mouse_x, mouse_y))) or
(self.__curMap__[marble_y][marble_x][1] == 0 ) ):
if self.__curMap__[self.__selectedMarble__[1]][self.__selectedMarble__[0]][2] == Game.STATE_SELECTED :
self.__curMap__[self.__selectedMarble__[1]][self.__selectedMarble__[0]][2] = Game.STATE_NONE
self.__selectedMarble__ = [-1, -1]
self.__selectionRect__ = None self.__selectionRect__ = None
return return
if self.__curMap__[marble_y][marble_x][1] == 0: self.__selectionRect__ = pygame.Rect(
(self.__curMapRect__.left + (pos[Game.P_IDX_X] * Game.MARBLE_WIDTH)),
(self.__curMapRect__.top + (pos[Game.P_IDX_Y] * Game.MARBLE_HEIGHT)),
Game.MARBLE_WIDTH,
Game.MARBLE_HEIGHT)
self.__setMarbleState__(pos[Game.P_IDX_X], pos[Game.P_IDX_Y], Game.STATE_SELECTED)
def __mouseClicked__(self, event):
mouse_x = event.pos[Game.P_IDX_X]
mouse_y = event.pos[Game.P_IDX_Y]
marble_x = ( (mouse_x - self.__curMapRect__.left) / Game.MARBLE_WIDTH)
marble_y = ( (mouse_y - self.__curMapRect__.top) / Game.MARBLE_HEIGHT)
if ( ( not self.__curMapRect__.collidepoint((mouse_x, mouse_y))) or
(self.__curMap__[marble_y][marble_x][Game.M_IDX_TYPE] == 0 ) ):
if self.__curMap__[self.__selectedMarble__[Game.P_IDX_Y]][self.__selectedMarble__[Game.P_IDX_X]][2] == Game.STATE_SELECTED :
self.__curMap__[self.__selectedMarble__[Game.P_IDX_Y]][self.__selectedMarble__[Game.P_IDX_X]][2] = Game.STATE_NONE
self.__setSelectedMarble__([-1, -1])
self.__selectionRect__ = None
return
if self.__curMap__[marble_y][marble_x][Game.M_IDX_TYPE] == 0:
return False return False
if event.button == 1: if event.button == 1:
self.__selectedMarble__ = [marble_x, marble_y] self.__setSelectedMarble__([marble_x, marble_y])
self.__selectionRect__ = pygame.Rect(
(self.__curMapRect__.left + (marble_x * Game.MARBLE_WIDTH)),
(self.__curMapRect__.top + (marble_y * Game.MARBLE_HEIGHT)),
Game.MARBLE_WIDTH,
Game.MARBLE_HEIGHT)
self.__setMarbleState__(marble_x, marble_y, Game.STATE_SELECTED)
elif event.button in [2, 3]: elif event.button in [2, 3]:
if not self.__canSelectMarble__(marble_x, marble_y): if not self.__canSelectMarble__(marble_x, marble_y):
return return
self.__flipMarbles__(self.__selectedMarble__, [marble_x, marble_y]) self.__flipMarbles__(self.__selectedMarble__, [marble_x, marble_y])
#self.__setGroupState__()
return return
def __setGroupState__(self):
groups = {
0: [],
1: [],
2: [],
3: [],
4: []
}
groups_of_3 = [
[],
[],
[],
[]
]
x = 0
y = 0
curMatchMarble = 0
prevy = 0
group = None
for row in self.__curMap__:
x = 0
for col in row:
if col[Game.M_IDX_TYPE] != 0:
candidates = [
[x, y - 1], # --C--
[x - 1, y], # -CX--
[x + 1, y], # --XC-
[x, y + 1] # --C--
]
for c in candidates:
if self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]][Game.M_IDX_TYPE] == col[Game.M_IDX_TYPE]:
if ( (prevy != y and curMatchMarble != col[Game.M_IDX_TYPE]) or
(prevy != y) ):
curMatchMarble = col[Game.M_IDX_TYPE]
group = None
for group in groups[curMatchMarble]:
if ( ( [c[Game.P_IDX_Y], c[Game.P_IDX_X]] in group ) or
( self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]] in group ) ):
break
if not group:
group = [[c[Game.P_IDX_Y], c[Game.P_IDX_X]]]
groups[curMatchMarble].append(group)
group.append([self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]]])
x += 1
prevy = y
y += 1
# Go through all the matches, and make sets of all the marbles in groups > 3
for marble, group in groups.iteritems():
for grp in group:
if len(grp) > 2:
groups_of_3[marble] += grp
for group in groups_of_3:
for pair in set(group):
self.__curMap__[pair[Game.P_IDX_Y]][pair[Game.P_IDX_X]][2] = Game.STATE_FALLING
def run(self): def run(self):
while True: while True:
self.__update__()
self.__draw__() self.__draw__()
for event in pygame.event.get(): for event in pygame.event.get():