Created
October 17, 2009 00:24
-
-
Save talklittle/212168 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### 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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### 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