Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@talklittle
Created October 17, 2009 00:24
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 talklittle/212168 to your computer and use it in GitHub Desktop.
Save talklittle/212168 to your computer and use it in GitHub Desktop.
### This module holds grid classes and engine for Python Reversi.
### Classes for text display are also here so they can make use
### of necessary globals.
### Last revised 2008-12-07
### ACP
import pygame
from pygame.locals import *
### GLOBALS ###
## Grids to hold information on state of game:
griddict = {}
gridisvalidmove = {}
gridisvalidmove = gridisvalidmove.fromkeys(griddict)
dictscores = {1: 2, 2: 2,}
messagetext = {1: "Player 1 to move", 2: "Welcome to Reversi!"}
## List to hold directions (for finding valid moves etc.)
directions = [(0, 1), (0, -1), (1, 0), (1, 1), (1, -1), (-1, 0), (-1, 1), (-1, -1)]
### CLASSES ###
class grid(pygame.sprite.Sprite):
"""Creates and updates visible main grid for the game"""
def __init__(self, screen, tilesize, dimensions):
"""Draws a grid of specified x, y coords and tilesize.
Updates list of Grid Coordinates for reference."""
pygame.sprite.Sprite.__init__(self)
self.dimensions = dimensions
self.tilesize = tilesize
self.createboard()
def createboard(self):
"""Draws the gameboard!"""
dimensions = self.dimensions
tilesize = self.tilesize
##Create a dictionary entry for each grid ref
for x in range(dimensions[0]):
for y in range(dimensions[1]):
griddict[(x, y)] = ''
##Set initial states for centre squares
griddict[(dimensions[0]/2, dimensions[1]/2)] = 1
griddict[(dimensions[0]/2-1, dimensions[1]/2)] = 2
griddict[(dimensions[0]/2-1, dimensions[1]/2-1)] = 1
griddict[(dimensions[0]/2, dimensions[1]/2-1)] = 2
def paintcell(self, screen, colour, x, y):
"""Paints a cell a given colour at screen location x, y"""
t = self.tilesize
screen.fill((colour), (x*t, y*t, t, t))
def update(self, screen):
"""Repaints cells based on the state of the game"""
## Set dimensions for grid
t = self.tilesize
d = self.dimensions
## Draw grid and paint in player cell colours. Also stores coordinates
for x in range(d[0]):
for y in range(d[1]):
if griddict[(y, x)] == 1:
self.paintcell(screen, (255, 0, 0), x, y)
elif griddict[(y, x)] == 2:
self.paintcell(screen, (0, 255, 0), x, y)
else:
self.paintcell(screen, (0, 0, 0), x, y)
pygame.draw.rect(screen, (255, 255, 255), (x*t, y*t, t, t), 1)
class playermove:
"""Handles control of moves.
This is the core game engine"""
def __init__(self, player, tilesize, dimensions):
"""Initialise variables and draw up initial dictionary of
valid moves"""
self.player = player
self.tilesize = tilesize
self.dimensions = dimensions
self.checkmoves()
self.movepassed = 0
def getcell(self, mousex, mousey):
"""Gets cell reference for position of mouse click."""
## This section works by calculating the remainder when the mouse position
## is divided by tile size. This is then subtracted from the mouse position
## to get the tile coordinates, which are then converted to a cell reference
gridplacex = mousex - (mousex % self.tilesize)
gridplacey = mousey - (mousey % self.tilesize)
self.cellref = (gridplacey/self.tilesize, gridplacex/self.tilesize)
def switchplayer(self):
"""Switches to other player (use after successful move).
Switches back and increments self.movepassed if no moves are available."""
if self.player == 1:
self.player = 2
else:
self.player = 1
# Does new player have moves?
self.checkmoves()
nomoves = 1
# If so,state this and reset moves passed to 0
for item in gridisvalidmove.items():
if list(item)[1] == 1:
nomoves = 0
# If not, switch player again
if nomoves == 1:
messagetext[2] = "Player " + str(self.player) + " can't move. Skipping."
self.movepassed += 1
if self.movepassed < 2:
self.switchplayer()
#If previous player already passed, game over.
else:
self.gameover()
else:
self.movepassed = 0
messagetext[1] = "Player " + str(self.player) + " to move."
messagetext[2] = ""
def checkmoves(self):
"""Draw up dictionary of valid moves"""
for key in griddict:
gridisvalidmove[key] = self.isvalidmove(key)
def gameover(self):
"""Determines who has won the game and sets gameover message."""
if dictscores[1] > dictscores[2]:
messagetext[1] = "Player 1 wins!"
else:
messagetext[1] = "Player 2 wins!"
messagetext[2] = "GAME OVER"
def isvalidmove(self, cell):
"""Determines whether a cell (tuple) is a valid move,
by scouting in each direction one cell at a time."""
for dir in directions:
movemaybevalid = 0
x = list(cell)
p = self.player
while True:
try:
## If cell is available
if griddict[cell] == '':
# and next cell is blank,
# dir not valid.
if griddict[x[0]+dir[0], x[1]+dir[1]] == '':
break
# If opposing player owns next
# square in dir, move may be valid
elif griddict[x[0]+dir[0], x[1]+dir[1]] != p:
movemaybevalid = 1
x[0] = x[0]+dir[0]
x[1] = x[1]+dir[1]
# If own player's square is reached
# And at least one opposing square
# was passed move is valid
elif griddict[x[0]+dir[0], x[1]+dir[1]] == p:
if movemaybevalid == 1:
return 1
else:
break
else:
break
except KeyError:
break
# If 1 hasn't been returned already,
# move isn't valid so return 0
return 0
def flipcells(self, cell):
"""For each direction, creates a list of cells
which will be flipped for a given cell.
Each cell is then assigned to the current
player in the grid dictionary. Works similarly to isvalidmove()"""
flipped = []
p = self.player
for dir in directions:
x = list(cell)
while True:
try:
if griddict[x[0]+dir[0], x[1]+dir[1]] == '':
del flipped[:]
break
elif griddict[x[0]+dir[0], x[1]+dir[1]] != p:
flipped.append((x[0]+dir[0], x[1]+dir[1]))
x[0] = x[0]+dir[0]
x[1] = x[1]+dir[1]
elif griddict[x[0]+dir[0], x[1]+dir[1]] == p:
if len(flipped) > 0:
for item in flipped:
griddict[item] = p
del flipped[:]
else:
break
# If we hit the edge of the grid,
# we cannot flip in this direction
except KeyError:
del flipped[:]
break
def domove(self, mouseclick):
"""Carries out move -- CALL THIS FOR MB EVENT
Mouseclick is a 2-tuple ."""
self.mousex, self.mousey = mouseclick
self.getcell(self.mousex, self.mousey) # Get cell ref for mouse click location
# Stop clicking outside of the grid from producing invalid cell ref.
if griddict.has_key(self.cellref):
# Check validity of move
if self.isvalidmove(self.cellref) == 1:
# Ensure cell is free
if griddict[self.cellref] == '':
# Carry out move switch player and update scores.
griddict[self.cellref] = self.player
self.flipcells(self.cellref)
self.switchplayer()
self.getscores()
def getscores(self):
"""Counts up total score for a player, from griddict"""
for player in range(2):
score = 0
for key in griddict:
if griddict[key] == player+1:
score += 1
dictscores[player+1] = score
### TEXT-DISPLAY CLASSES ###
class scoredisplay(pygame.sprite.Sprite):
def __init__(self, player, yloc):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.SysFont(None, 35)
self.player = player
self.scoretext()
self.rect = self.image.get_rect()
self.rect.topleft = (400, yloc)
def scoretext(self):
text = "Player " + str(self.player) + ": " + str(dictscores[self.player])
if self.player == 1:
self.image = self.font.render(text, True, (255, 0, 0))
else:
self.image = self.font.render(text, True, (0, 255, 0))
def update(self):
self.scoretext()
class text(pygame.sprite.Sprite):
def __init__(self, xloc, yloc, textsize, colour, text):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.SysFont(None, textsize)
self.image = self.font.render(text, True, colour)
self.rect = self.image.get_rect()
self.rect.topleft = (xloc, yloc)
def update(self):
None
class message(pygame.sprite.Sprite):
def __init__(self, xloc, yloc, messageno):
pygame.sprite.Sprite.__init__(self)
self.font = pygame.font.SysFont(None, 22)
self.messageno = messageno
self.update()
self.rect = self.image.get_rect()
self.rect.topleft = (xloc, yloc)
def update(self):
self.messagetext = messagetext[self.messageno]
self.image = self.font.render(self.messagetext, True, (0, 0, 0))
### PYTHON REVERSI - Based on the classic boardgame "Reversi"
### Last Revision: 2008-12-07
### ACP
##Import necessary modules etc.
import pygame
import gridcells
from pygame.locals import *
from sys import exit
pygame.init()
## Setup window and background
windowres = (640, 384)
screen = pygame.display.set_mode(windowres)
pygame.display.set_caption("Reversi; An Adventure in Grids - ACP")
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((125, 125, 60))
## Declare initial variables
mousex = mousey = 0
gridplacex = gridplacey = 0
## Create grid
tilesize = 48
dimensions = (8, 8)
grid = gridcells.grid(screen, tilesize, dimensions)
gridgroup = pygame.sprite.Group(grid)
player = gridcells.playermove(1, tilesize, dimensions)
## Create text
p1score = gridcells.scoredisplay(1, 100)
p2score = gridcells.scoredisplay(2, 125)
scoregroup = pygame.sprite.Group(p1score, p2score)
resettext = gridcells.text(500, 360, 30, (180, 180, 0), "(r)eset")
quittext = gridcells.text(580, 360, 30, (180, 180, 0), "(q)uit")
titletext = gridcells.text(420, 30, 60, (200, 200, 200), "REVERSI")
message = gridcells.message(400, 200, 1)
message2 = gridcells.message(400, 180, 2)
textgroup = pygame.sprite.Group(resettext, quittext, message, message2, titletext)
## Main runtime loop
clock = pygame.time.Clock()
dim = grid.dimensions
til = grid.tilesize
while True:
## Quick framerate not needed - low for efficiency.
clock.tick(15)
# Quit if x clicked.
for event in pygame.event.get():
if event.type == QUIT:
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouseclick = event.pos
player.domove(mouseclick)
# Act on keypresses.
keypress = pygame.key.get_pressed()
if keypress[K_q]:
exit()
elif keypress[K_r]:
player = gridcells.playermove(1, tilesize, dimensions)
grid = gridcells.grid(screen, tilesize, dimensions)
scoregroup = pygame.sprite.Group(p1score, p2score)
gridcells.messagetext = {1:"Player 1 to move.", 2: "Welcome to Reversi!"}
for key in gridcells.dictscores:
gridcells.dictscores[key] = 2
# Build display.
screen.blit(background, (0, 0))
gridgroup.update(screen)
scoregroup.update()
scoregroup.draw(screen)
textgroup.update()
textgroup.draw(screen)
pygame.display.flip()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment