This commit is contained in:
Karl 2016-12-06 20:53:25 +00:00
parent a82fa4faf4
commit 7a819537da
78 changed files with 9481 additions and 0 deletions

BIN
python_games/4row_arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
python_games/4row_black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
python_games/4row_board.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
python_games/4row_red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
python_games/4row_tie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
python_games/Rock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
python_games/Selector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
python_games/Star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
python_games/Tree_Short.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
python_games/Tree_Tall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
python_games/Tree_Ugly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
python_games/badswap.wav Normal file

Binary file not shown.

BIN
python_games/beep1.ogg Normal file

Binary file not shown.

BIN
python_games/beep2.ogg Normal file

Binary file not shown.

BIN
python_games/beep3.ogg Normal file

Binary file not shown.

BIN
python_games/beep4.ogg Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Hello Pygame World!')
while True: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

BIN
python_games/boy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
python_games/cat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,47 @@
import pygame, sys
from pygame.locals import *
pygame.init()
FPS = 30 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
catImg = pygame.image.load('cat.png')
catx = 10
caty = 10
direction = 'right'
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
if direction == 'right':
catx += 5
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += 5
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= 5
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= 5
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(catImg, (catx, caty))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)

BIN
python_games/catgirl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

41
python_games/drawing.py Normal file
View File

@ -0,0 +1,41 @@
import pygame, sys
from pygame.locals import *
pygame.init()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Drawing')
# set up the colors
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
# draw on the surface object
DISPLAYSURF.fill(WHITE)
pygame.draw.polygon(DISPLAYSURF, GREEN, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))
pygame.draw.line(DISPLAYSURF, BLUE, (60, 60), (120, 60), 4)
pygame.draw.line(DISPLAYSURF, BLUE, (120, 60), (60, 120))
pygame.draw.line(DISPLAYSURF, BLUE, (60, 120), (120, 120), 4)
pygame.draw.circle(DISPLAYSURF, BLUE, (300, 50), 20, 0)
pygame.draw.ellipse(DISPLAYSURF, RED, (300, 200, 40, 80), 1)
pygame.draw.rect(DISPLAYSURF, RED, (200, 150, 100, 50))
pixObj = pygame.PixelArray(DISPLAYSURF)
pixObj[380][280] = BLACK
pixObj[382][282] = BLACK
pixObj[384][284] = BLACK
pixObj[386][286] = BLACK
pixObj[388][288] = BLACK
del pixObj
# run the game loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()

518
python_games/flippy.py Normal file
View File

@ -0,0 +1,518 @@
# Flippy (an Othello or Reversi clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
# Based on the "reversi.py" code that originally appeared in "Invent
# Your Own Computer Games with Python", chapter 15:
# http://inventwithpython.com/chapter15.html
import random, sys, pygame, time, copy
from pygame.locals import *
FPS = 10 # frames per second to update the screen
WINDOWWIDTH = 640 # width of the program's window, in pixels
WINDOWHEIGHT = 480 # height in pixels
SPACESIZE = 50 # width & height of each space on the board, in pixels
BOARDWIDTH = 8 # how many columns of spaces on the game board
BOARDHEIGHT = 8 # how many rows of spaces on the game board
WHITE_TILE = 'WHITE_TILE' # an arbitrary but unique value
BLACK_TILE = 'BLACK_TILE' # an arbitrary but unique value
EMPTY_SPACE = 'EMPTY_SPACE' # an arbitrary but unique value
HINT_TILE = 'HINT_TILE' # an arbitrary but unique value
ANIMATIONSPEED = 25 # integer from 1 to 100, higher is faster animation
# Amount of space on the left & right side (XMARGIN) or above and below
# (YMARGIN) the game board, in pixels.
XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * SPACESIZE)) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * SPACESIZE)) / 2)
# R G B
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 155, 0)
BRIGHTBLUE = ( 0, 50, 255)
BROWN = (174, 94, 0)
TEXTBGCOLOR1 = BRIGHTBLUE
TEXTBGCOLOR2 = GREEN
GRIDLINECOLOR = BLACK
TEXTCOLOR = WHITE
HINTCOLOR = BROWN
def main():
global MAINCLOCK, DISPLAYSURF, FONT, BIGFONT, BGIMAGE
pygame.init()
MAINCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Flippy')
FONT = pygame.font.Font('freesansbold.ttf', 16)
BIGFONT = pygame.font.Font('freesansbold.ttf', 32)
# Set up the background image.
boardImage = pygame.image.load('flippyboard.png')
# Use smoothscale() to stretch the board image to fit the entire board:
boardImage = pygame.transform.smoothscale(boardImage, (BOARDWIDTH * SPACESIZE, BOARDHEIGHT * SPACESIZE))
boardImageRect = boardImage.get_rect()
boardImageRect.topleft = (XMARGIN, YMARGIN)
BGIMAGE = pygame.image.load('flippybackground.png')
# Use smoothscale() to stretch the background image to fit the entire window:
BGIMAGE = pygame.transform.smoothscale(BGIMAGE, (WINDOWWIDTH, WINDOWHEIGHT))
BGIMAGE.blit(boardImage, boardImageRect)
# Run the main game.
while True:
if runGame() == False:
break
def runGame():
# Plays a single game of reversi each time this function is called.
# Reset the board and game.
mainBoard = getNewBoard()
resetBoard(mainBoard)
showHints = False
turn = random.choice(['computer', 'player'])
# Draw the starting board and ask the player what color they want.
drawBoard(mainBoard)
playerTile, computerTile = enterPlayerTile()
# Make the Surface and Rect objects for the "New Game" and "Hints" buttons
newGameSurf = FONT.render('New Game', True, TEXTCOLOR, TEXTBGCOLOR2)
newGameRect = newGameSurf.get_rect()
newGameRect.topright = (WINDOWWIDTH - 8, 10)
hintsSurf = FONT.render('Hints', True, TEXTCOLOR, TEXTBGCOLOR2)
hintsRect = hintsSurf.get_rect()
hintsRect.topright = (WINDOWWIDTH - 8, 40)
while True: # main game loop
# Keep looping for player and computer's turns.
if turn == 'player':
# Player's turn:
if getValidMoves(mainBoard, playerTile) == []:
# If it's the player's turn but they
# can't move, then end the game.
break
movexy = None
while movexy == None:
# Keep looping until the player clicks on a valid space.
# Determine which board data structure to use for display.
if showHints:
boardToDraw = getBoardWithValidMoves(mainBoard, playerTile)
else:
boardToDraw = mainBoard
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
# Handle mouse click events
mousex, mousey = event.pos
if newGameRect.collidepoint( (mousex, mousey) ):
# Start a new game
return True
elif hintsRect.collidepoint( (mousex, mousey) ):
# Toggle hints mode
showHints = not showHints
# movexy is set to a two-item tuple XY coordinate, or None value
movexy = getSpaceClicked(mousex, mousey)
if movexy != None and not isValidMove(mainBoard, playerTile, movexy[0], movexy[1]):
movexy = None
# Draw the game board.
drawBoard(boardToDraw)
drawInfo(boardToDraw, playerTile, computerTile, turn)
# Draw the "New Game" and "Hints" buttons.
DISPLAYSURF.blit(newGameSurf, newGameRect)
DISPLAYSURF.blit(hintsSurf, hintsRect)
MAINCLOCK.tick(FPS)
pygame.display.update()
# Make the move and end the turn.
makeMove(mainBoard, playerTile, movexy[0], movexy[1], True)
if getValidMoves(mainBoard, computerTile) != []:
# Only set for the computer's turn if it can make a move.
turn = 'computer'
else:
# Computer's turn:
if getValidMoves(mainBoard, computerTile) == []:
# If it was set to be the computer's turn but
# they can't move, then end the game.
break
# Draw the board.
drawBoard(mainBoard)
drawInfo(mainBoard, playerTile, computerTile, turn)
# Draw the "New Game" and "Hints" buttons.
DISPLAYSURF.blit(newGameSurf, newGameRect)
DISPLAYSURF.blit(hintsSurf, hintsRect)
# Make it look like the computer is thinking by pausing a bit.
pauseUntil = time.time() + random.randint(5, 15) * 0.1
while time.time() < pauseUntil:
pygame.display.update()
# Make the move and end the turn.
x, y = getComputerMove(mainBoard, computerTile)
makeMove(mainBoard, computerTile, x, y, True)
if getValidMoves(mainBoard, playerTile) != []:
# Only set for the player's turn if they can make a move.
turn = 'player'
# Display the final score.
drawBoard(mainBoard)
scores = getScoreOfBoard(mainBoard)
# Determine the text of the message to display.
if scores[playerTile] > scores[computerTile]:
text = 'You beat the computer by %s points! Congratulations!' % \
(scores[playerTile] - scores[computerTile])
elif scores[playerTile] < scores[computerTile]:
text = 'You lost. The computer beat you by %s points.' % \
(scores[computerTile] - scores[playerTile])
else:
text = 'The game was a tie!'
textSurf = FONT.render(text, True, TEXTCOLOR, TEXTBGCOLOR1)
textRect = textSurf.get_rect()
textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(textSurf, textRect)
# Display the "Play again?" text with Yes and No buttons.
text2Surf = BIGFONT.render('Play again?', True, TEXTCOLOR, TEXTBGCOLOR1)
text2Rect = text2Surf.get_rect()
text2Rect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 50)
# Make "Yes" button.
yesSurf = BIGFONT.render('Yes', True, TEXTCOLOR, TEXTBGCOLOR1)
yesRect = yesSurf.get_rect()
yesRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 90)
# Make "No" button.
noSurf = BIGFONT.render('No', True, TEXTCOLOR, TEXTBGCOLOR1)
noRect = noSurf.get_rect()
noRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 90)
while True:
# Process events until the user clicks on Yes or No.
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
if yesRect.collidepoint( (mousex, mousey) ):
return True
elif noRect.collidepoint( (mousex, mousey) ):
return False
DISPLAYSURF.blit(textSurf, textRect)
DISPLAYSURF.blit(text2Surf, text2Rect)
DISPLAYSURF.blit(yesSurf, yesRect)
DISPLAYSURF.blit(noSurf, noRect)
pygame.display.update()
MAINCLOCK.tick(FPS)
def translateBoardToPixelCoord(x, y):
return XMARGIN + x * SPACESIZE + int(SPACESIZE / 2), YMARGIN + y * SPACESIZE + int(SPACESIZE / 2)
def animateTileChange(tilesToFlip, tileColor, additionalTile):
# Draw the additional tile that was just laid down. (Otherwise we'd
# have to completely redraw the board & the board info.)
if tileColor == WHITE_TILE:
additionalTileColor = WHITE
else:
additionalTileColor = BLACK
additionalTileX, additionalTileY = translateBoardToPixelCoord(additionalTile[0], additionalTile[1])
pygame.draw.circle(DISPLAYSURF, additionalTileColor, (additionalTileX, additionalTileY), int(SPACESIZE / 2) - 4)
pygame.display.update()
for rgbValues in range(0, 255, int(ANIMATIONSPEED * 2.55)):
if rgbValues > 255:
rgbValues = 255
elif rgbValues < 0:
rgbValues = 0
if tileColor == WHITE_TILE:
color = tuple([rgbValues] * 3) # rgbValues goes from 0 to 255
elif tileColor == BLACK_TILE:
color = tuple([255 - rgbValues] * 3) # rgbValues goes from 255 to 0
for x, y in tilesToFlip:
centerx, centery = translateBoardToPixelCoord(x, y)
pygame.draw.circle(DISPLAYSURF, color, (centerx, centery), int(SPACESIZE / 2) - 4)
pygame.display.update()
MAINCLOCK.tick(FPS)
checkForQuit()
def drawBoard(board):
# Draw background of board.
DISPLAYSURF.blit(BGIMAGE, BGIMAGE.get_rect())
# Draw grid lines of the board.
for x in range(BOARDWIDTH + 1):
# Draw the horizontal lines.
startx = (x * SPACESIZE) + XMARGIN
starty = YMARGIN
endx = (x * SPACESIZE) + XMARGIN
endy = YMARGIN + (BOARDHEIGHT * SPACESIZE)
pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy))
for y in range(BOARDHEIGHT + 1):
# Draw the vertical lines.
startx = XMARGIN
starty = (y * SPACESIZE) + YMARGIN
endx = XMARGIN + (BOARDWIDTH * SPACESIZE)
endy = (y * SPACESIZE) + YMARGIN
pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy))
# Draw the black & white tiles or hint spots.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
centerx, centery = translateBoardToPixelCoord(x, y)
if board[x][y] == WHITE_TILE or board[x][y] == BLACK_TILE:
if board[x][y] == WHITE_TILE:
tileColor = WHITE
else:
tileColor = BLACK
pygame.draw.circle(DISPLAYSURF, tileColor, (centerx, centery), int(SPACESIZE / 2) - 4)
if board[x][y] == HINT_TILE:
pygame.draw.rect(DISPLAYSURF, HINTCOLOR, (centerx - 4, centery - 4, 8, 8))
def getSpaceClicked(mousex, mousey):
# Return a tuple of two integers of the board space coordinates where
# the mouse was clicked. (Or returns None not in any space.)
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if mousex > x * SPACESIZE + XMARGIN and \
mousex < (x + 1) * SPACESIZE + XMARGIN and \
mousey > y * SPACESIZE + YMARGIN and \
mousey < (y + 1) * SPACESIZE + YMARGIN:
return (x, y)
return None
def drawInfo(board, playerTile, computerTile, turn):
# Draws scores and whose turn it is at the bottom of the screen.
scores = getScoreOfBoard(board)
scoreSurf = FONT.render("Player Score: %s Computer Score: %s %s's Turn" % (str(scores[playerTile]), str(scores[computerTile]), turn.title()), True, TEXTCOLOR)
scoreRect = scoreSurf.get_rect()
scoreRect.bottomleft = (10, WINDOWHEIGHT - 5)
DISPLAYSURF.blit(scoreSurf, scoreRect)
def resetBoard(board):
# Blanks out the board it is passed, and sets up starting tiles.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
board[x][y] = EMPTY_SPACE
# Add starting pieces to the center
board[3][3] = WHITE_TILE
board[3][4] = BLACK_TILE
board[4][3] = BLACK_TILE
board[4][4] = WHITE_TILE
def getNewBoard():
# Creates a brand new, empty board data structure.
board = []
for i in range(BOARDWIDTH):
board.append([EMPTY_SPACE] * BOARDHEIGHT)
return board
def isValidMove(board, tile, xstart, ystart):
# Returns False if the player's move is invalid. If it is a valid
# move, returns a list of spaces of the captured pieces.
if board[xstart][ystart] != EMPTY_SPACE or not isOnBoard(xstart, ystart):
return False
board[xstart][ystart] = tile # temporarily set the tile on the board.
if tile == WHITE_TILE:
otherTile = BLACK_TILE
else:
otherTile = WHITE_TILE
tilesToFlip = []
# check each of the eight directions:
for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]:
x, y = xstart, ystart
x += xdirection
y += ydirection
if isOnBoard(x, y) and board[x][y] == otherTile:
# The piece belongs to the other player next to our piece.
x += xdirection
y += ydirection
if not isOnBoard(x, y):
continue
while board[x][y] == otherTile:
x += xdirection
y += ydirection
if not isOnBoard(x, y):
break # break out of while loop, continue in for loop
if not isOnBoard(x, y):
continue
if board[x][y] == tile:
# There are pieces to flip over. Go in the reverse
# direction until we reach the original space, noting all
# the tiles along the way.
while True:
x -= xdirection
y -= ydirection
if x == xstart and y == ystart:
break
tilesToFlip.append([x, y])
board[xstart][ystart] = EMPTY_SPACE # make space empty
if len(tilesToFlip) == 0: # If no tiles flipped, this move is invalid
return False
return tilesToFlip
def isOnBoard(x, y):
# Returns True if the coordinates are located on the board.
return x >= 0 and x < BOARDWIDTH and y >= 0 and y < BOARDHEIGHT
def getBoardWithValidMoves(board, tile):
# Returns a new board with hint markings.
dupeBoard = copy.deepcopy(board)
for x, y in getValidMoves(dupeBoard, tile):
dupeBoard[x][y] = HINT_TILE
return dupeBoard
def getValidMoves(board, tile):
# Returns a list of (x,y) tuples of all valid moves.
validMoves = []
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if isValidMove(board, tile, x, y) != False:
validMoves.append((x, y))
return validMoves
def getScoreOfBoard(board):
# Determine the score by counting the tiles.
xscore = 0
oscore = 0
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == WHITE_TILE:
xscore += 1
if board[x][y] == BLACK_TILE:
oscore += 1
return {WHITE_TILE:xscore, BLACK_TILE:oscore}
def enterPlayerTile():
# Draws the text and handles the mouse click events for letting
# the player choose which color they want to be. Returns
# [WHITE_TILE, BLACK_TILE] if the player chooses to be White,
# [BLACK_TILE, WHITE_TILE] if Black.
# Create the text.
textSurf = FONT.render('Do you want to be white or black?', True, TEXTCOLOR, TEXTBGCOLOR1)
textRect = textSurf.get_rect()
textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
xSurf = BIGFONT.render('White', True, TEXTCOLOR, TEXTBGCOLOR1)
xRect = xSurf.get_rect()
xRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 40)
oSurf = BIGFONT.render('Black', True, TEXTCOLOR, TEXTBGCOLOR1)
oRect = oSurf.get_rect()
oRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 40)
while True:
# Keep looping until the player has clicked on a color.
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
if xRect.collidepoint( (mousex, mousey) ):
return [WHITE_TILE, BLACK_TILE]
elif oRect.collidepoint( (mousex, mousey) ):
return [BLACK_TILE, WHITE_TILE]
# Draw the screen.
DISPLAYSURF.blit(textSurf, textRect)
DISPLAYSURF.blit(xSurf, xRect)
DISPLAYSURF.blit(oSurf, oRect)
pygame.display.update()
MAINCLOCK.tick(FPS)
def makeMove(board, tile, xstart, ystart, realMove=False):
# Place the tile on the board at xstart, ystart, and flip tiles
# Returns False if this is an invalid move, True if it is valid.
tilesToFlip = isValidMove(board, tile, xstart, ystart)
if tilesToFlip == False:
return False
board[xstart][ystart] = tile
if realMove:
animateTileChange(tilesToFlip, tile, (xstart, ystart))
for x, y in tilesToFlip:
board[x][y] = tile
return True
def isOnCorner(x, y):
# Returns True if the position is in one of the four corners.
return (x == 0 and y == 0) or \
(x == BOARDWIDTH and y == 0) or \
(x == 0 and y == BOARDHEIGHT) or \
(x == BOARDWIDTH and y == BOARDHEIGHT)
def getComputerMove(board, computerTile):
# Given a board and the computer's tile, determine where to
# move and return that move as a [x, y] list.
possibleMoves = getValidMoves(board, computerTile)
# randomize the order of the possible moves
random.shuffle(possibleMoves)
# always go for a corner if available.
for x, y in possibleMoves:
if isOnCorner(x, y):
return [x, y]
# Go through all possible moves and remember the best scoring move
bestScore = -1
for x, y in possibleMoves:
dupeBoard = copy.deepcopy(board)
makeMove(dupeBoard, computerTile, x, y)
score = getScoreOfBoard(dupeBoard)[computerTile]
if score > bestScore:
bestMove = [x, y]
bestScore = score
return bestMove
def checkForQuit():
for event in pygame.event.get((QUIT, KEYUP)): # event handling loop
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

363
python_games/fourinarow.py Normal file
View File

@ -0,0 +1,363 @@
# Four-In-A-Row (a Connect Four clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, copy, sys, pygame
from pygame.locals import *
BOARDWIDTH = 7 # how many spaces wide the board is
BOARDHEIGHT = 6 # how many spaces tall the board is
assert BOARDWIDTH >= 4 and BOARDHEIGHT >= 4, 'Board must be at least 4x4.'
DIFFICULTY = 2 # how many moves to look ahead. (>2 is usually too much)
SPACESIZE = 50 # size of the tokens and individual board spaces in pixels
FPS = 30 # frames per second to update the screen
WINDOWWIDTH = 640 # width of the program's window, in pixels
WINDOWHEIGHT = 480 # height in pixels
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * SPACESIZE) / 2)
YMARGIN = int((WINDOWHEIGHT - BOARDHEIGHT * SPACESIZE) / 2)
BRIGHTBLUE = (0, 50, 255)
WHITE = (255, 255, 255)
BGCOLOR = BRIGHTBLUE
TEXTCOLOR = WHITE
RED = 'red'
BLACK = 'black'
EMPTY = None
HUMAN = 'human'
COMPUTER = 'computer'
def main():
global FPSCLOCK, DISPLAYSURF, REDPILERECT, BLACKPILERECT, REDTOKENIMG
global BLACKTOKENIMG, BOARDIMG, ARROWIMG, ARROWRECT, HUMANWINNERIMG
global COMPUTERWINNERIMG, WINNERRECT, TIEWINNERIMG
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Four in a Row')
REDPILERECT = pygame.Rect(int(SPACESIZE / 2), WINDOWHEIGHT - int(3 * SPACESIZE / 2), SPACESIZE, SPACESIZE)
BLACKPILERECT = pygame.Rect(WINDOWWIDTH - int(3 * SPACESIZE / 2), WINDOWHEIGHT - int(3 * SPACESIZE / 2), SPACESIZE, SPACESIZE)
REDTOKENIMG = pygame.image.load('4row_red.png')
REDTOKENIMG = pygame.transform.smoothscale(REDTOKENIMG, (SPACESIZE, SPACESIZE))
BLACKTOKENIMG = pygame.image.load('4row_black.png')
BLACKTOKENIMG = pygame.transform.smoothscale(BLACKTOKENIMG, (SPACESIZE, SPACESIZE))
BOARDIMG = pygame.image.load('4row_board.png')
BOARDIMG = pygame.transform.smoothscale(BOARDIMG, (SPACESIZE, SPACESIZE))
HUMANWINNERIMG = pygame.image.load('4row_humanwinner.png')
COMPUTERWINNERIMG = pygame.image.load('4row_computerwinner.png')
TIEWINNERIMG = pygame.image.load('4row_tie.png')
WINNERRECT = HUMANWINNERIMG.get_rect()
WINNERRECT.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
ARROWIMG = pygame.image.load('4row_arrow.png')
ARROWRECT = ARROWIMG.get_rect()
ARROWRECT.left = REDPILERECT.right + 10
ARROWRECT.centery = REDPILERECT.centery
isFirstGame = True
while True:
runGame(isFirstGame)
isFirstGame = False
def runGame(isFirstGame):
if isFirstGame:
# Let the computer go first on the first game, so the player
# can see how the tokens are dragged from the token piles.
turn = COMPUTER
showHelp = True
else:
# Randomly choose who goes first.
if random.randint(0, 1) == 0:
turn = COMPUTER
else:
turn = HUMAN
showHelp = False
# Set up a blank board data structure.
mainBoard = getNewBoard()
while True: # main game loop
if turn == HUMAN:
# Human player's turn.
getHumanMove(mainBoard, showHelp)
if showHelp:
# turn off help arrow after the first move
showHelp = False
if isWinner(mainBoard, RED):
winnerImg = HUMANWINNERIMG
break
turn = COMPUTER # switch to other player's turn
else:
# Computer player's turn.
column = getComputerMove(mainBoard)
animateComputerMoving(mainBoard, column)
makeMove(mainBoard, BLACK, column)
if isWinner(mainBoard, BLACK):
winnerImg = COMPUTERWINNERIMG
break
turn = HUMAN # switch to other player's turn
if isBoardFull(mainBoard):
# A completely filled board means it's a tie.
winnerImg = TIEWINNERIMG
break
while True:
# Keep looping until player clicks the mouse or quits.
drawBoard(mainBoard)
DISPLAYSURF.blit(winnerImg, WINNERRECT)
pygame.display.update()
FPSCLOCK.tick()
for event in pygame.event.get(): # event handling loop
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP:
return
def makeMove(board, player, column):
lowest = getLowestEmptySpace(board, column)
if lowest != -1:
board[column][lowest] = player
def drawBoard(board, extraToken=None):
DISPLAYSURF.fill(BGCOLOR)
# draw tokens
spaceRect = pygame.Rect(0, 0, SPACESIZE, SPACESIZE)
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
spaceRect.topleft = (XMARGIN + (x * SPACESIZE), YMARGIN + (y * SPACESIZE))
if board[x][y] == RED:
DISPLAYSURF.blit(REDTOKENIMG, spaceRect)
elif board[x][y] == BLACK:
DISPLAYSURF.blit(BLACKTOKENIMG, spaceRect)
# draw the extra token
if extraToken != None:
if extraToken['color'] == RED:
DISPLAYSURF.blit(REDTOKENIMG, (extraToken['x'], extraToken['y'], SPACESIZE, SPACESIZE))
elif extraToken['color'] == BLACK:
DISPLAYSURF.blit(BLACKTOKENIMG, (extraToken['x'], extraToken['y'], SPACESIZE, SPACESIZE))
# draw board over the tokens
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
spaceRect.topleft = (XMARGIN + (x * SPACESIZE), YMARGIN + (y * SPACESIZE))
DISPLAYSURF.blit(BOARDIMG, spaceRect)
# draw the red and black tokens off to the side
DISPLAYSURF.blit(REDTOKENIMG, REDPILERECT) # red on the left
DISPLAYSURF.blit(BLACKTOKENIMG, BLACKPILERECT) # black on the right
def getNewBoard():
board = []
for x in range(BOARDWIDTH):
board.append([EMPTY] * BOARDHEIGHT)
return board
def getHumanMove(board, isFirstMove):
draggingToken = False
tokenx, tokeny = None, None
while True:
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and not draggingToken and REDPILERECT.collidepoint(event.pos):
# start of dragging on red token pile.
draggingToken = True
tokenx, tokeny = event.pos
elif event.type == MOUSEMOTION and draggingToken:
# update the position of the red token being dragged
tokenx, tokeny = event.pos
elif event.type == MOUSEBUTTONUP and draggingToken:
# let go of the token being dragged
if tokeny < YMARGIN and tokenx > XMARGIN and tokenx < WINDOWWIDTH - XMARGIN:
# let go at the top of the screen.
column = int((tokenx - XMARGIN) / SPACESIZE)
if isValidMove(board, column):
animateDroppingToken(board, column, RED)
board[column][getLowestEmptySpace(board, column)] = RED
drawBoard(board)
pygame.display.update()
return
tokenx, tokeny = None, None
draggingToken = False
if tokenx != None and tokeny != None:
drawBoard(board, {'x':tokenx - int(SPACESIZE / 2), 'y':tokeny - int(SPACESIZE / 2), 'color':RED})
else:
drawBoard(board)
if isFirstMove:
# Show the help arrow for the player's first move.
DISPLAYSURF.blit(ARROWIMG, ARROWRECT)
pygame.display.update()
FPSCLOCK.tick()
def animateDroppingToken(board, column, color):
x = XMARGIN + column * SPACESIZE
y = YMARGIN - SPACESIZE
dropSpeed = 1.0
lowestEmptySpace = getLowestEmptySpace(board, column)
while True:
y += int(dropSpeed)
dropSpeed += 0.5
if int((y - YMARGIN) / SPACESIZE) >= lowestEmptySpace:
return
drawBoard(board, {'x':x, 'y':y, 'color':color})
pygame.display.update()
FPSCLOCK.tick()
def animateComputerMoving(board, column):
x = BLACKPILERECT.left
y = BLACKPILERECT.top
speed = 1.0
# moving the black tile up
while y > (YMARGIN - SPACESIZE):
y -= int(speed)
speed += 0.5
drawBoard(board, {'x':x, 'y':y, 'color':BLACK})
pygame.display.update()
FPSCLOCK.tick()
# moving the black tile over
y = YMARGIN - SPACESIZE
speed = 1.0
while x > (XMARGIN + column * SPACESIZE):
x -= int(speed)
speed += 0.5
drawBoard(board, {'x':x, 'y':y, 'color':BLACK})
pygame.display.update()
FPSCLOCK.tick()
# dropping the black tile
animateDroppingToken(board, column, BLACK)
def getComputerMove(board):
potentialMoves = getPotentialMoves(board, BLACK, DIFFICULTY)
# get the best fitness from the potential moves
bestMoveFitness = -1
for i in range(BOARDWIDTH):
if potentialMoves[i] > bestMoveFitness and isValidMove(board, i):
bestMoveFitness = potentialMoves[i]
# find all potential moves that have this best fitness
bestMoves = []
for i in range(len(potentialMoves)):
if potentialMoves[i] == bestMoveFitness and isValidMove(board, i):
bestMoves.append(i)
return random.choice(bestMoves)
def getPotentialMoves(board, tile, lookAhead):
if lookAhead == 0 or isBoardFull(board):
return [0] * BOARDWIDTH
if tile == RED:
enemyTile = BLACK
else:
enemyTile = RED
# Figure out the best move to make.
potentialMoves = [0] * BOARDWIDTH
for firstMove in range(BOARDWIDTH):
dupeBoard = copy.deepcopy(board)
if not isValidMove(dupeBoard, firstMove):
continue
makeMove(dupeBoard, tile, firstMove)
if isWinner(dupeBoard, tile):
# a winning move automatically gets a perfect fitness
potentialMoves[firstMove] = 1
break # don't bother calculating other moves
else:
# do other player's counter moves and determine best one
if isBoardFull(dupeBoard):
potentialMoves[firstMove] = 0
else:
for counterMove in range(BOARDWIDTH):
dupeBoard2 = copy.deepcopy(dupeBoard)
if not isValidMove(dupeBoard2, counterMove):
continue
makeMove(dupeBoard2, enemyTile, counterMove)
if isWinner(dupeBoard2, enemyTile):
# a losing move automatically gets the worst fitness
potentialMoves[firstMove] = -1
break
else:
# do the recursive call to getPotentialMoves()
results = getPotentialMoves(dupeBoard2, tile, lookAhead - 1)
potentialMoves[firstMove] += (sum(results) / BOARDWIDTH) / BOARDWIDTH
return potentialMoves
def getLowestEmptySpace(board, column):
# Return the row number of the lowest empty row in the given column.
for y in range(BOARDHEIGHT-1, -1, -1):
if board[column][y] == EMPTY:
return y
return -1
def isValidMove(board, column):
# Returns True if there is an empty space in the given column.
# Otherwise returns False.
if column < 0 or column >= (BOARDWIDTH) or board[column][0] != EMPTY:
return False
return True
def isBoardFull(board):
# Returns True if there are no empty spaces anywhere on the board.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == EMPTY:
return False
return True
def isWinner(board, tile):
# check horizontal spaces
for x in range(BOARDWIDTH - 3):
for y in range(BOARDHEIGHT):
if board[x][y] == tile and board[x+1][y] == tile and board[x+2][y] == tile and board[x+3][y] == tile:
return True
# check vertical spaces
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT - 3):
if board[x][y] == tile and board[x][y+1] == tile and board[x][y+2] == tile and board[x][y+3] == tile:
return True
# check / diagonal spaces
for x in range(BOARDWIDTH - 3):
for y in range(3, BOARDHEIGHT):
if board[x][y] == tile and board[x+1][y-1] == tile and board[x+2][y-2] == tile and board[x+3][y-3] == tile:
return True
# check \ diagonal spaces
for x in range(BOARDWIDTH - 3):
for y in range(BOARDHEIGHT - 3):
if board[x][y] == tile and board[x+1][y+1] == tile and board[x+2][y+2] == tile and board[x+3][y+3] == tile:
return True
return False
if __name__ == '__main__':
main()

BIN
python_games/gameicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
python_games/gem1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
python_games/gem2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
python_games/gem3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
python_games/gem4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
python_games/gem5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
python_games/gem6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
python_games/gem7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

549
python_games/gemgem.py Normal file
View File

@ -0,0 +1,549 @@
# Gemgem (a Bejeweled clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
"""
This program has "gem data structures", which are basically dictionaries
with the following keys:
'x' and 'y' - The location of the gem on the board. 0,0 is the top left.
There is also a ROWABOVEBOARD row that 'y' can be set to,
to indicate that it is above the board.
'direction' - one of the four constant variables UP, DOWN, LEFT, RIGHT.
This is the direction the gem is moving.
'imageNum' - The integer index into GEMIMAGES to denote which image
this gem uses.
"""
import random, time, pygame, sys, copy
from pygame.locals import *
FPS = 30 # frames per second to update the screen
WINDOWWIDTH = 600 # width of the program's window, in pixels
WINDOWHEIGHT = 600 # height in pixels
BOARDWIDTH = 8 # how many columns in the board
BOARDHEIGHT = 8 # how many rows in the board
GEMIMAGESIZE = 64 # width & height of each space in pixels
# NUMGEMIMAGES is the number of gem types. You will need .png image
# files named gem0.png, gem1.png, etc. up to gem(N-1).png.
NUMGEMIMAGES = 7
assert NUMGEMIMAGES >= 5 # game needs at least 5 types of gems to work
# NUMMATCHSOUNDS is the number of different sounds to choose from when
# a match is made. The .wav files are named match0.wav, match1.wav, etc.
NUMMATCHSOUNDS = 6
MOVERATE = 25 # 1 to 100, larger num means faster animations
DEDUCTSPEED = 0.8 # reduces score by 1 point every DEDUCTSPEED seconds.
# R G B
PURPLE = (255, 0, 255)
LIGHTBLUE = (170, 190, 255)
BLUE = ( 0, 0, 255)
RED = (255, 100, 100)
BLACK = ( 0, 0, 0)
BROWN = ( 85, 65, 0)
HIGHLIGHTCOLOR = PURPLE # color of the selected gem's border
BGCOLOR = LIGHTBLUE # background color on the screen
GRIDCOLOR = BLUE # color of the game board
GAMEOVERCOLOR = RED # color of the "Game over" text.
GAMEOVERBGCOLOR = BLACK # background color of the "Game over" text.
SCORECOLOR = BROWN # color of the text for the player's score
# The amount of space to the sides of the board to the edge of the window
# is used several times, so calculate it once here and store in variables.
XMARGIN = int((WINDOWWIDTH - GEMIMAGESIZE * BOARDWIDTH) / 2)
YMARGIN = int((WINDOWHEIGHT - GEMIMAGESIZE * BOARDHEIGHT) / 2)
# constants for direction values
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
EMPTY_SPACE = -1 # an arbitrary, nonpositive value
ROWABOVEBOARD = 'row above board' # an arbitrary, noninteger value
def main():
global FPSCLOCK, DISPLAYSURF, GEMIMAGES, GAMESOUNDS, BASICFONT, BOARDRECTS
# Initial set up.
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Gemgem')
BASICFONT = pygame.font.Font('freesansbold.ttf', 36)
# Load the images
GEMIMAGES = []
for i in range(1, NUMGEMIMAGES+1):
gemImage = pygame.image.load('gem%s.png' % i)
if gemImage.get_size() != (GEMIMAGESIZE, GEMIMAGESIZE):
gemImage = pygame.transform.smoothscale(gemImage, (GEMIMAGESIZE, GEMIMAGESIZE))
GEMIMAGES.append(gemImage)
# Load the sounds.
GAMESOUNDS = {}
GAMESOUNDS['bad swap'] = pygame.mixer.Sound('badswap.wav')
GAMESOUNDS['match'] = []
for i in range(NUMMATCHSOUNDS):
GAMESOUNDS['match'].append(pygame.mixer.Sound('match%s.wav' % i))
# Create pygame.Rect objects for each board space to
# do board-coordinate-to-pixel-coordinate conversions.
BOARDRECTS = []
for x in range(BOARDWIDTH):
BOARDRECTS.append([])
for y in range(BOARDHEIGHT):
r = pygame.Rect((XMARGIN + (x * GEMIMAGESIZE),
YMARGIN + (y * GEMIMAGESIZE),
GEMIMAGESIZE,
GEMIMAGESIZE))
BOARDRECTS[x].append(r)
while True:
runGame()
def runGame():
# Plays through a single game. When the game is over, this function returns.
# initalize the board
gameBoard = getBlankBoard()
score = 0
fillBoardAndAnimate(gameBoard, [], score) # Drop the initial gems.
# initialize variables for the start of a new game
firstSelectedGem = None
lastMouseDownX = None
lastMouseDownY = None
gameIsOver = False
lastScoreDeduction = time.time()
clickContinueTextSurf = None
while True: # main game loop
clickedSpace = None
for event in pygame.event.get(): # event handling loop
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == KEYUP and event.key == K_BACKSPACE:
return # start a new game
elif event.type == MOUSEBUTTONUP:
if gameIsOver:
return # after games ends, click to start a new game
if event.pos == (lastMouseDownX, lastMouseDownY):
# This event is a mouse click, not the end of a mouse drag.
clickedSpace = checkForGemClick(event.pos)
else:
# this is the end of a mouse drag
firstSelectedGem = checkForGemClick((lastMouseDownX, lastMouseDownY))
clickedSpace = checkForGemClick(event.pos)
if not firstSelectedGem or not clickedSpace:
# if not part of a valid drag, deselect both
firstSelectedGem = None
clickedSpace = None
elif event.type == MOUSEBUTTONDOWN:
# this is the start of a mouse click or mouse drag
lastMouseDownX, lastMouseDownY = event.pos
if clickedSpace and not firstSelectedGem:
# This was the first gem clicked on.
firstSelectedGem = clickedSpace
elif clickedSpace and firstSelectedGem:
# Two gems have been clicked on and selected. Swap the gems.
firstSwappingGem, secondSwappingGem = getSwappingGems(gameBoard, firstSelectedGem, clickedSpace)
if firstSwappingGem == None and secondSwappingGem == None:
# If both are None, then the gems were not adjacent
firstSelectedGem = None # deselect the first gem
continue
# Show the swap animation on the screen.
boardCopy = getBoardCopyMinusGems(gameBoard, (firstSwappingGem, secondSwappingGem))
animateMovingGems(boardCopy, [firstSwappingGem, secondSwappingGem], [], score)
# Swap the gems in the board data structure.
gameBoard[firstSwappingGem['x']][firstSwappingGem['y']] = secondSwappingGem['imageNum']
gameBoard[secondSwappingGem['x']][secondSwappingGem['y']] = firstSwappingGem['imageNum']
# See if this is a matching move.
matchedGems = findMatchingGems(gameBoard)
if matchedGems == []:
# Was not a matching move; swap the gems back
GAMESOUNDS['bad swap'].play()
animateMovingGems(boardCopy, [firstSwappingGem, secondSwappingGem], [], score)
gameBoard[firstSwappingGem['x']][firstSwappingGem['y']] = firstSwappingGem['imageNum']
gameBoard[secondSwappingGem['x']][secondSwappingGem['y']] = secondSwappingGem['imageNum']
else:
# This was a matching move.
scoreAdd = 0
while matchedGems != []:
# Remove matched gems, then pull down the board.
# points is a list of dicts that tells fillBoardAndAnimate()
# where on the screen to display text to show how many
# points the player got. points is a list because if
# the playergets multiple matches, then multiple points text should appear.
points = []
for gemSet in matchedGems:
scoreAdd += (10 + (len(gemSet) - 3) * 10)
for gem in gemSet:
gameBoard[gem[0]][gem[1]] = EMPTY_SPACE
points.append({'points': scoreAdd,
'x': gem[0] * GEMIMAGESIZE + XMARGIN,
'y': gem[1] * GEMIMAGESIZE + YMARGIN})
random.choice(GAMESOUNDS['match']).play()
score += scoreAdd
# Drop the new gems.
fillBoardAndAnimate(gameBoard, points, score)
# Check if there are any new matches.
matchedGems = findMatchingGems(gameBoard)
firstSelectedGem = None
if not canMakeMove(gameBoard):
gameIsOver = True
# Draw the board.
DISPLAYSURF.fill(BGCOLOR)
drawBoard(gameBoard)
if firstSelectedGem != None:
highlightSpace(firstSelectedGem['x'], firstSelectedGem['y'])
if gameIsOver:
if clickContinueTextSurf == None:
# Only render the text once. In future iterations, just
# use the Surface object already in clickContinueTextSurf
clickContinueTextSurf = BASICFONT.render('Final Score: %s (Click to continue)' % (score), 1, GAMEOVERCOLOR, GAMEOVERBGCOLOR)
clickContinueTextRect = clickContinueTextSurf.get_rect()
clickContinueTextRect.center = int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)
DISPLAYSURF.blit(clickContinueTextSurf, clickContinueTextRect)
elif score > 0 and time.time() - lastScoreDeduction > DEDUCTSPEED:
# score drops over time
score -= 1
lastScoreDeduction = time.time()
drawScore(score)
pygame.display.update()
FPSCLOCK.tick(FPS)
def getSwappingGems(board, firstXY, secondXY):
# If the gems at the (X, Y) coordinates of the two gems are adjacent,
# then their 'direction' keys are set to the appropriate direction
# value to be swapped with each other.
# Otherwise, (None, None) is returned.
firstGem = {'imageNum': board[firstXY['x']][firstXY['y']],
'x': firstXY['x'],
'y': firstXY['y']}
secondGem = {'imageNum': board[secondXY['x']][secondXY['y']],
'x': secondXY['x'],
'y': secondXY['y']}
highlightedGem = None
if firstGem['x'] == secondGem['x'] + 1 and firstGem['y'] == secondGem['y']:
firstGem['direction'] = LEFT
secondGem['direction'] = RIGHT
elif firstGem['x'] == secondGem['x'] - 1 and firstGem['y'] == secondGem['y']:
firstGem['direction'] = RIGHT
secondGem['direction'] = LEFT
elif firstGem['y'] == secondGem['y'] + 1 and firstGem['x'] == secondGem['x']:
firstGem['direction'] = UP
secondGem['direction'] = DOWN
elif firstGem['y'] == secondGem['y'] - 1 and firstGem['x'] == secondGem['x']:
firstGem['direction'] = DOWN
secondGem['direction'] = UP
else:
# These gems are not adjacent and can't be swapped.
return None, None
return firstGem, secondGem
def getBlankBoard():
# Create and return a blank board data structure.
board = []
for x in range(BOARDWIDTH):
board.append([EMPTY_SPACE] * BOARDHEIGHT)
return board
def canMakeMove(board):
# Return True if the board is in a state where a matching
# move can be made on it. Otherwise return False.
# The patterns in oneOffPatterns represent gems that are configured
# in a way where it only takes one move to make a triplet.
oneOffPatterns = (((0,1), (1,0), (2,0)),
((0,1), (1,1), (2,0)),
((0,0), (1,1), (2,0)),
((0,1), (1,0), (2,1)),
((0,0), (1,0), (2,1)),
((0,0), (1,1), (2,1)),
((0,0), (0,2), (0,3)),
((0,0), (0,1), (0,3)))
# The x and y variables iterate over each space on the board.
# If we use + to represent the currently iterated space on the
# board, then this pattern: ((0,1), (1,0), (2,0))refers to identical
# gems being set up like this:
#
# +A
# B
# C
#
# That is, gem A is offset from the + by (0,1), gem B is offset
# by (1,0), and gem C is offset by (2,0). In this case, gem A can
# be swapped to the left to form a vertical three-in-a-row triplet.
#
# There are eight possible ways for the gems to be one move
# away from forming a triple, hence oneOffPattern has 8 patterns.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
for pat in oneOffPatterns:
# check each possible pattern of "match in next move" to
# see if a possible move can be made.
if (getGemAt(board, x+pat[0][0], y+pat[0][1]) == \
getGemAt(board, x+pat[1][0], y+pat[1][1]) == \
getGemAt(board, x+pat[2][0], y+pat[2][1]) != None) or \
(getGemAt(board, x+pat[0][1], y+pat[0][0]) == \
getGemAt(board, x+pat[1][1], y+pat[1][0]) == \
getGemAt(board, x+pat[2][1], y+pat[2][0]) != None):
return True # return True the first time you find a pattern
return False
def drawMovingGem(gem, progress):
# Draw a gem sliding in the direction that its 'direction' key
# indicates. The progress parameter is a number from 0 (just
# starting) to 100 (slide complete).
movex = 0
movey = 0
progress *= 0.01
if gem['direction'] == UP:
movey = -int(progress * GEMIMAGESIZE)
elif gem['direction'] == DOWN:
movey = int(progress * GEMIMAGESIZE)
elif gem['direction'] == RIGHT:
movex = int(progress * GEMIMAGESIZE)
elif gem['direction'] == LEFT:
movex = -int(progress * GEMIMAGESIZE)
basex = gem['x']
basey = gem['y']
if basey == ROWABOVEBOARD:
basey = -1
pixelx = XMARGIN + (basex * GEMIMAGESIZE)
pixely = YMARGIN + (basey * GEMIMAGESIZE)
r = pygame.Rect( (pixelx + movex, pixely + movey, GEMIMAGESIZE, GEMIMAGESIZE) )
DISPLAYSURF.blit(GEMIMAGES[gem['imageNum']], r)
def pullDownAllGems(board):
# pulls down gems on the board to the bottom to fill in any gaps
for x in range(BOARDWIDTH):
gemsInColumn = []
for y in range(BOARDHEIGHT):
if board[x][y] != EMPTY_SPACE:
gemsInColumn.append(board[x][y])
board[x] = ([EMPTY_SPACE] * (BOARDHEIGHT - len(gemsInColumn))) + gemsInColumn
def getGemAt(board, x, y):
if x < 0 or y < 0 or x >= BOARDWIDTH or y >= BOARDHEIGHT:
return None
else:
return board[x][y]
def getDropSlots(board):
# Creates a "drop slot" for each column and fills the slot with a
# number of gems that that column is lacking. This function assumes
# that the gems have been gravity dropped already.
boardCopy = copy.deepcopy(board)
pullDownAllGems(boardCopy)
dropSlots = []
for i in range(BOARDWIDTH):
dropSlots.append([])
# count the number of empty spaces in each column on the board
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT-1, -1, -1): # start from bottom, going up
if boardCopy[x][y] == EMPTY_SPACE:
possibleGems = list(range(len(GEMIMAGES)))
for offsetX, offsetY in ((0, -1), (1, 0), (0, 1), (-1, 0)):
# Narrow down the possible gems we should put in the
# blank space so we don't end up putting an two of
# the same gems next to each other when they drop.
neighborGem = getGemAt(boardCopy, x + offsetX, y + offsetY)
if neighborGem != None and neighborGem in possibleGems:
possibleGems.remove(neighborGem)
newGem = random.choice(possibleGems)
boardCopy[x][y] = newGem
dropSlots[x].append(newGem)
return dropSlots
def findMatchingGems(board):
gemsToRemove = [] # a list of lists of gems in matching triplets that should be removed
boardCopy = copy.deepcopy(board)
# loop through each space, checking for 3 adjacent identical gems
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
# look for horizontal matches
if getGemAt(boardCopy, x, y) == getGemAt(boardCopy, x + 1, y) == getGemAt(boardCopy, x + 2, y) and getGemAt(boardCopy, x, y) != EMPTY_SPACE:
targetGem = boardCopy[x][y]
offset = 0
removeSet = []
while getGemAt(boardCopy, x + offset, y) == targetGem:
# keep checking if there's more than 3 gems in a row
removeSet.append((x + offset, y))
boardCopy[x + offset][y] = EMPTY_SPACE
offset += 1
gemsToRemove.append(removeSet)
# look for vertical matches
if getGemAt(boardCopy, x, y) == getGemAt(boardCopy, x, y + 1) == getGemAt(boardCopy, x, y + 2) and getGemAt(boardCopy, x, y) != EMPTY_SPACE:
targetGem = boardCopy[x][y]
offset = 0
removeSet = []
while getGemAt(boardCopy, x, y + offset) == targetGem:
# keep checking, in case there's more than 3 gems in a row
removeSet.append((x, y + offset))
boardCopy[x][y + offset] = EMPTY_SPACE
offset += 1
gemsToRemove.append(removeSet)
return gemsToRemove
def highlightSpace(x, y):
pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, BOARDRECTS[x][y], 4)
def getDroppingGems(board):
# Find all the gems that have an empty space below them
boardCopy = copy.deepcopy(board)
droppingGems = []
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT - 2, -1, -1):
if boardCopy[x][y + 1] == EMPTY_SPACE and boardCopy[x][y] != EMPTY_SPACE:
# This space drops if not empty but the space below it is
droppingGems.append( {'imageNum': boardCopy[x][y], 'x': x, 'y': y, 'direction': DOWN} )
boardCopy[x][y] = EMPTY_SPACE
return droppingGems
def animateMovingGems(board, gems, pointsText, score):
# pointsText is a dictionary with keys 'x', 'y', and 'points'
progress = 0 # progress at 0 represents beginning, 100 means finished.
while progress < 100: # animation loop
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
for gem in gems: # Draw each gem.
drawMovingGem(gem, progress)
drawScore(score)
for pointText in pointsText:
pointsSurf = BASICFONT.render(str(pointText['points']), 1, SCORECOLOR)
pointsRect = pointsSurf.get_rect()
pointsRect.center = (pointText['x'], pointText['y'])
DISPLAYSURF.blit(pointsSurf, pointsRect)
pygame.display.update()
FPSCLOCK.tick(FPS)
progress += MOVERATE # progress the animation a little bit more for the next frame
def moveGems(board, movingGems):
# movingGems is a list of dicts with keys x, y, direction, imageNum
for gem in movingGems:
if gem['y'] != ROWABOVEBOARD:
board[gem['x']][gem['y']] = EMPTY_SPACE
movex = 0
movey = 0
if gem['direction'] == LEFT:
movex = -1
elif gem['direction'] == RIGHT:
movex = 1
elif gem['direction'] == DOWN:
movey = 1
elif gem['direction'] == UP:
movey = -1
board[gem['x'] + movex][gem['y'] + movey] = gem['imageNum']
else:
# gem is located above the board (where new gems come from)
board[gem['x']][0] = gem['imageNum'] # move to top row
def fillBoardAndAnimate(board, points, score):
dropSlots = getDropSlots(board)
while dropSlots != [[]] * BOARDWIDTH:
# do the dropping animation as long as there are more gems to drop
movingGems = getDroppingGems(board)
for x in range(len(dropSlots)):
if len(dropSlots[x]) != 0:
# cause the lowest gem in each slot to begin moving in the DOWN direction
movingGems.append({'imageNum': dropSlots[x][0], 'x': x, 'y': ROWABOVEBOARD, 'direction': DOWN})
boardCopy = getBoardCopyMinusGems(board, movingGems)
animateMovingGems(boardCopy, movingGems, points, score)
moveGems(board, movingGems)
# Make the next row of gems from the drop slots
# the lowest by deleting the previous lowest gems.
for x in range(len(dropSlots)):
if len(dropSlots[x]) == 0:
continue
board[x][0] = dropSlots[x][0]
del dropSlots[x][0]
def checkForGemClick(pos):
# See if the mouse click was on the board
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if BOARDRECTS[x][y].collidepoint(pos[0], pos[1]):
return {'x': x, 'y': y}
return None # Click was not on the board.
def drawBoard(board):
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
pygame.draw.rect(DISPLAYSURF, GRIDCOLOR, BOARDRECTS[x][y], 1)
gemToDraw = board[x][y]
if gemToDraw != EMPTY_SPACE:
DISPLAYSURF.blit(GEMIMAGES[gemToDraw], BOARDRECTS[x][y])
def getBoardCopyMinusGems(board, gems):
# Creates and returns a copy of the passed board data structure,
# with the gems in the "gems" list removed from it.
#
# Gems is a list of dicts, with keys x, y, direction, imageNum
boardCopy = copy.deepcopy(board)
# Remove some of the gems from this board data structure copy.
for gem in gems:
if gem['y'] != ROWABOVEBOARD:
boardCopy[gem['x']][gem['y']] = EMPTY_SPACE
return boardCopy
def drawScore(score):
scoreImg = BASICFONT.render(str(score), 1, SCORECOLOR)
scoreRect = scoreImg.get_rect()
scoreRect.bottomleft = (10, WINDOWHEIGHT - 6)
DISPLAYSURF.blit(scoreImg, scoreRect)
if __name__ == '__main__':
main()

BIN
python_games/grass1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
python_games/grass2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
python_games/grass3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
python_games/grass4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
python_games/horngirl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

445
python_games/inkspill.py Normal file
View File

@ -0,0 +1,445 @@
# Ink Spill (a Flood It clone)
# http://inventwithpython.com/pygame
# By Al Sweigart al@inventwithpython.com
# Released under a "Simplified BSD" license
import random, sys, webbrowser, copy, pygame
from pygame.locals import *
# There are different box sizes, number of boxes, and
# life depending on the "board size" setting selected.
SMALLBOXSIZE = 60 # size is in pixels
MEDIUMBOXSIZE = 20
LARGEBOXSIZE = 11
SMALLBOARDSIZE = 6 # size is in boxes
MEDIUMBOARDSIZE = 17
LARGEBOARDSIZE = 30
SMALLMAXLIFE = 10 # number of turns
MEDIUMMAXLIFE = 30
LARGEMAXLIFE = 64
FPS = 30
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
boxSize = MEDIUMBOXSIZE
PALETTEGAPSIZE = 10
PALETTESIZE = 45
EASY = 0 # arbitrary but unique value
MEDIUM = 1 # arbitrary but unique value
HARD = 2 # arbitrary but unique value
difficulty = MEDIUM # game starts in "medium" mode
maxLife = MEDIUMMAXLIFE
boardWidth = MEDIUMBOARDSIZE
boardHeight = MEDIUMBOARDSIZE
# R G B
WHITE = (255, 255, 255)
DARKGRAY = ( 70, 70, 70)
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
PURPLE = (255, 0, 255)
# The first color in each scheme is the background color, the next six are the palette colors.
COLORSCHEMES = (((150, 200, 255), RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE),
((0, 155, 104), (97, 215, 164), (228, 0, 69), (0, 125, 50), (204, 246, 0), (148, 0, 45), (241, 109, 149)),
((195, 179, 0), (255, 239, 115), (255, 226, 0), (147, 3, 167), (24, 38, 176), (166, 147, 0), (197, 97, 211)),
((85, 0, 0), (155, 39, 102), (0, 201, 13), (255, 118, 0), (206, 0, 113), (0, 130, 9), (255, 180, 115)),
((191, 159, 64), (183, 182, 208), (4, 31, 183), (167, 184, 45), (122, 128, 212), (37, 204, 7), (88, 155, 213)),
((200, 33, 205), (116, 252, 185), (68, 56, 56), (52, 238, 83), (23, 149, 195), (222, 157, 227), (212, 86, 185)))
for i in range(len(COLORSCHEMES)):
assert len(COLORSCHEMES[i]) == 7, 'Color scheme %s does not have exactly 7 colors.' % (i)
bgColor = COLORSCHEMES[0][0]
paletteColors = COLORSCHEMES[0][1:]
def main():
global FPSCLOCK, DISPLAYSURF, LOGOIMAGE, SPOTIMAGE, SETTINGSIMAGE, SETTINGSBUTTONIMAGE, RESETBUTTONIMAGE
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
# Load images
LOGOIMAGE = pygame.image.load('inkspilllogo.png')
SPOTIMAGE = pygame.image.load('inkspillspot.png')
SETTINGSIMAGE = pygame.image.load('inkspillsettings.png')
SETTINGSBUTTONIMAGE = pygame.image.load('inkspillsettingsbutton.png')
RESETBUTTONIMAGE = pygame.image.load('inkspillresetbutton.png')
pygame.display.set_caption('Ink Spill')
mousex = 0
mousey = 0
mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)
life = maxLife
lastPaletteClicked = None
while True: # main game loop
paletteClicked = None
resetGame = False
# Draw the screen.
DISPLAYSURF.fill(bgColor)
drawLogoAndButtons()
drawBoard(mainBoard)
drawLifeMeter(life)
drawPalettes()
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
if pygame.Rect(WINDOWWIDTH - SETTINGSBUTTONIMAGE.get_width(),
WINDOWHEIGHT - SETTINGSBUTTONIMAGE.get_height(),
SETTINGSBUTTONIMAGE.get_width(),
SETTINGSBUTTONIMAGE.get_height()).collidepoint(mousex, mousey):
resetGame = showSettingsScreen() # clicked on Settings button
elif pygame.Rect(WINDOWWIDTH - RESETBUTTONIMAGE.get_width(),
WINDOWHEIGHT - SETTINGSBUTTONIMAGE.get_height() - RESETBUTTONIMAGE.get_height(),
RESETBUTTONIMAGE.get_width(),
RESETBUTTONIMAGE.get_height()).collidepoint(mousex, mousey):
resetGame = True # clicked on Reset button
else:
# check if a palette button was clicked
paletteClicked = getColorOfPaletteAt(mousex, mousey)
elif event.type == KEYDOWN:
# support up to 9 palette keys
try:
key = int(event.unicode)
except:
key = None
if key != None and key > 0 and key <= len(paletteColors):
paletteClicked = key - 1
if paletteClicked != None and paletteClicked != lastPaletteClicked:
# a palette button was clicked that is different from the
# last palette button clicked (this check prevents the player
# from accidentally clicking the same palette twice)
lastPaletteClicked = paletteClicked
floodAnimation(mainBoard, paletteClicked)
life -= 1
resetGame = False
if hasWon(mainBoard):
for i in range(4): # flash border 4 times
flashBorderAnimation(WHITE, mainBoard)
resetGame = True
pygame.time.wait(2000) # pause so the player can bask in victory
elif life == 0:
# life is zero, so player has lost
drawLifeMeter(0)
pygame.display.update()
pygame.time.wait(400)
for i in range(4):
flashBorderAnimation(BLACK, mainBoard)
resetGame = True
pygame.time.wait(2000) # pause so the player can suffer in their defeat
if resetGame:
# start a new game
mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)
life = maxLife
lastPaletteClicked = None
pygame.display.update()
FPSCLOCK.tick(FPS)
def checkForQuit():
# Terminates the program if there are any QUIT or escape key events.
for event in pygame.event.get(QUIT): # get all the QUIT events
pygame.quit() # terminate if any QUIT events are present
sys.exit()
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
pygame.quit() # terminate if the KEYUP event was for the Esc key
sys.exit()
pygame.event.post(event) # put the other KEYUP event objects back
def hasWon(board):
# if the entire board is the same color, player has won
for x in range(boardWidth):
for y in range(boardHeight):
if board[x][y] != board[0][0]:
return False # found a different color, player has not won
return True
def showSettingsScreen():
global difficulty, boxSize, boardWidth, boardHeight, maxLife, paletteColors, bgColor
# The pixel coordinates in this function were obtained by loading
# the inkspillsettings.png image into a graphics editor and reading
# the pixel coordinates from there. Handy trick.
origDifficulty = difficulty
origBoxSize = boxSize
screenNeedsRedraw = True
while True:
if screenNeedsRedraw:
DISPLAYSURF.fill(bgColor)
DISPLAYSURF.blit(SETTINGSIMAGE, (0,0))
# place the ink spot marker next to the selected difficulty
if difficulty == EASY:
DISPLAYSURF.blit(SPOTIMAGE, (30, 4))
if difficulty == MEDIUM:
DISPLAYSURF.blit(SPOTIMAGE, (8, 41))
if difficulty == HARD:
DISPLAYSURF.blit(SPOTIMAGE, (30, 76))
# place the ink spot marker next to the selected size
if boxSize == SMALLBOXSIZE:
DISPLAYSURF.blit(SPOTIMAGE, (22, 150))
if boxSize == MEDIUMBOXSIZE:
DISPLAYSURF.blit(SPOTIMAGE, (11, 185))
if boxSize == LARGEBOXSIZE:
DISPLAYSURF.blit(SPOTIMAGE, (24, 220))
for i in range(len(COLORSCHEMES)):
drawColorSchemeBoxes(500, i * 60 + 30, i)
pygame.display.update()
screenNeedsRedraw = False # by default, don't redraw the screen
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYUP:
if event.key == K_ESCAPE:
# Esc key on settings screen goes back to game
return not (origDifficulty == difficulty and origBoxSize == boxSize)
elif event.type == MOUSEBUTTONUP:
screenNeedsRedraw = True # screen should be redrawn
mousex, mousey = event.pos # syntactic sugar
# check for clicks on the difficulty buttons
if pygame.Rect(74, 16, 111, 30).collidepoint(mousex, mousey):
difficulty = EASY
elif pygame.Rect(53, 50, 104, 29).collidepoint(mousex, mousey):
difficulty = MEDIUM
elif pygame.Rect(72, 85, 65, 31).collidepoint(mousex, mousey):
difficulty = HARD
# check for clicks on the size buttons
elif pygame.Rect(63, 156, 84, 31).collidepoint(mousex, mousey):
# small board size setting:
boxSize = SMALLBOXSIZE
boardWidth = SMALLBOARDSIZE
boardHeight = SMALLBOARDSIZE
maxLife = SMALLMAXLIFE
elif pygame.Rect(52, 192, 106,32).collidepoint(mousex, mousey):
# medium board size setting:
boxSize = MEDIUMBOXSIZE
boardWidth = MEDIUMBOARDSIZE
boardHeight = MEDIUMBOARDSIZE
maxLife = MEDIUMMAXLIFE
elif pygame.Rect(67, 228, 58, 37).collidepoint(mousex, mousey):
# large board size setting:
boxSize = LARGEBOXSIZE
boardWidth = LARGEBOARDSIZE
boardHeight = LARGEBOARDSIZE
maxLife = LARGEMAXLIFE
elif pygame.Rect(14, 299, 371, 97).collidepoint(mousex, mousey):
# clicked on the "learn programming" ad
webbrowser.open('http://inventwithpython.com') # opens a web browser
elif pygame.Rect(178, 418, 215, 34).collidepoint(mousex, mousey):
# clicked on the "back to game" button
return not (origDifficulty == difficulty and origBoxSize == boxSize)
for i in range(len(COLORSCHEMES)):
# clicked on a color scheme button
if pygame.Rect(500, 30 + i * 60, MEDIUMBOXSIZE * 3, MEDIUMBOXSIZE * 2).collidepoint(mousex, mousey):
bgColor = COLORSCHEMES[i][0]
paletteColors = COLORSCHEMES[i][1:]
def drawColorSchemeBoxes(x, y, schemeNum):
# Draws the color scheme boxes that appear on the "Settings" screen.
for boxy in range(2):
for boxx in range(3):
pygame.draw.rect(DISPLAYSURF, COLORSCHEMES[schemeNum][3 * boxy + boxx + 1], (x + MEDIUMBOXSIZE * boxx, y + MEDIUMBOXSIZE * boxy, MEDIUMBOXSIZE, MEDIUMBOXSIZE))
if paletteColors == COLORSCHEMES[schemeNum][1:]:
# put the ink spot next to the selected color scheme
DISPLAYSURF.blit(SPOTIMAGE, (x - 50, y))
def flashBorderAnimation(color, board, animationSpeed=30):
origSurf = DISPLAYSURF.copy()
flashSurf = pygame.Surface(DISPLAYSURF.get_size())
flashSurf = flashSurf.convert_alpha()
for start, end, step in ((0, 256, 1), (255, 0, -1)):
# the first iteration on the outer loop will set the inner loop
# to have transparency go from 0 to 255, the second iteration will
# have it go from 255 to 0. This is the "flash".
for transparency in range(start, end, animationSpeed * step):
DISPLAYSURF.blit(origSurf, (0, 0))
r, g, b = color
flashSurf.fill((r, g, b, transparency))
DISPLAYSURF.blit(flashSurf, (0, 0))
drawBoard(board) # draw board ON TOP OF the transparency layer
pygame.display.update()
FPSCLOCK.tick(FPS)
DISPLAYSURF.blit(origSurf, (0, 0)) # redraw the original surface
def floodAnimation(board, paletteClicked, animationSpeed=25):
origBoard = copy.deepcopy(board)
floodFill(board, board[0][0], paletteClicked, 0, 0)
for transparency in range(0, 255, animationSpeed):
# The "new" board slowly become opaque over the original board.
drawBoard(origBoard)
drawBoard(board, transparency)
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateRandomBoard(width, height, difficulty=MEDIUM):
# Creates a board data structure with random colors for each box.
board = []
for x in range(width):
column = []
for y in range(height):
column.append(random.randint(0, len(paletteColors) - 1))
board.append(column)
# Make board easier by setting some boxes to same color as a neighbor.
# Determine how many boxes to change.
if difficulty == EASY:
if boxSize == SMALLBOXSIZE:
boxesToChange = 100
else:
boxesToChange = 1500
elif difficulty == MEDIUM:
if boxSize == SMALLBOXSIZE:
boxesToChange = 5
else:
boxesToChange = 200
else:
boxesToChange = 0
# Change neighbor's colors:
for i in range(boxesToChange):
# Randomly choose a box whose color to copy
x = random.randint(1, width-2)
y = random.randint(1, height-2)
# Randomly choose neighbors to change.
direction = random.randint(0, 3)
if direction == 0: # change left and up neighbor
board[x-1][y] == board[x][y]
board[x][y-1] == board[x][y]
elif direction == 1: # change right and down neighbor
board[x+1][y] == board[x][y]
board[x][y+1] == board[x][y]
elif direction == 2: # change right and up neighbor
board[x][y-1] == board[x][y]
board[x+1][y] == board[x][y]
else: # change left and down neighbor
board[x][y+1] == board[x][y]
board[x-1][y] == board[x][y]
return board
def drawLogoAndButtons():
# draw the Ink Spill logo and Settings and Reset buttons.
DISPLAYSURF.blit(LOGOIMAGE, (WINDOWWIDTH - LOGOIMAGE.get_width(), 0))
DISPLAYSURF.blit(SETTINGSBUTTONIMAGE, (WINDOWWIDTH - SETTINGSBUTTONIMAGE.get_width(), WINDOWHEIGHT - SETTINGSBUTTONIMAGE.get_height()))
DISPLAYSURF.blit(RESETBUTTONIMAGE, (WINDOWWIDTH - RESETBUTTONIMAGE.get_width(), WINDOWHEIGHT - SETTINGSBUTTONIMAGE.get_height() - RESETBUTTONIMAGE.get_height()))
def drawBoard(board, transparency=255):
# The colored squares are drawn to a temporary surface which is then
# drawn to the DISPLAYSURF surface. This is done so we can draw the
# squares with transparency on top of DISPLAYSURF as it currently is.
tempSurf = pygame.Surface(DISPLAYSURF.get_size())
tempSurf = tempSurf.convert_alpha()
tempSurf.fill((0, 0, 0, 0))
for x in range(boardWidth):
for y in range(boardHeight):
left, top = leftTopPixelCoordOfBox(x, y)
r, g, b = paletteColors[board[x][y]]
pygame.draw.rect(tempSurf, (r, g, b, transparency), (left, top, boxSize, boxSize))
left, top = leftTopPixelCoordOfBox(0, 0)
pygame.draw.rect(tempSurf, BLACK, (left-1, top-1, boxSize * boardWidth + 1, boxSize * boardHeight + 1), 1)
DISPLAYSURF.blit(tempSurf, (0, 0))
def drawPalettes():
# Draws the six color palettes at the bottom of the screen.
numColors = len(paletteColors)
xmargin = int((WINDOWWIDTH - ((PALETTESIZE * numColors) + (PALETTEGAPSIZE * (numColors - 1)))) / 2)
for i in range(numColors):
left = xmargin + (i * PALETTESIZE) + (i * PALETTEGAPSIZE)
top = WINDOWHEIGHT - PALETTESIZE - 10
pygame.draw.rect(DISPLAYSURF, paletteColors[i], (left, top, PALETTESIZE, PALETTESIZE))
pygame.draw.rect(DISPLAYSURF, bgColor, (left + 2, top + 2, PALETTESIZE - 4, PALETTESIZE - 4), 2)
def drawLifeMeter(currentLife):
lifeBoxSize = int((WINDOWHEIGHT - 40) / maxLife)
# Draw background color of life meter.
pygame.draw.rect(DISPLAYSURF, bgColor, (20, 20, 20, 20 + (maxLife * lifeBoxSize)))
for i in range(maxLife):
if currentLife >= (maxLife - i): # draw a solid red box
pygame.draw.rect(DISPLAYSURF, RED, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize))
pygame.draw.rect(DISPLAYSURF, WHITE, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize), 1) # draw white outline
def getColorOfPaletteAt(x, y):
# Returns the index of the color in paletteColors that the x and y parameters
# are over. Returns None if x and y are not over any palette.
numColors = len(paletteColors)
xmargin = int((WINDOWWIDTH - ((PALETTESIZE * numColors) + (PALETTEGAPSIZE * (numColors - 1)))) / 2)
top = WINDOWHEIGHT - PALETTESIZE - 10
for i in range(numColors):
# Find out if the mouse click is inside any of the palettes.
left = xmargin + (i * PALETTESIZE) + (i * PALETTEGAPSIZE)
r = pygame.Rect(left, top, PALETTESIZE, PALETTESIZE)
if r.collidepoint(x, y):
return i
return None # no palette exists at these x, y coordinates
def floodFill(board, oldColor, newColor, x, y):
# This is the flood fill algorithm.
if oldColor == newColor or board[x][y] != oldColor:
return
board[x][y] = newColor # change the color of the current box
# Make the recursive call for any neighboring boxes:
if x > 0:
floodFill(board, oldColor, newColor, x - 1, y) # on box to the left
if x < boardWidth - 1:
floodFill(board, oldColor, newColor, x + 1, y) # on box to the right
if y > 0:
floodFill(board, oldColor, newColor, x, y - 1) # on box to up
if y < boardHeight - 1:
floodFill(board, oldColor, newColor, x, y + 1) # on box to down
def leftTopPixelCoordOfBox(boxx, boxy):
# Returns the x and y of the left-topmost pixel of the xth & yth box.
xmargin = int((WINDOWWIDTH - (boardWidth * boxSize)) / 2)
ymargin = int((WINDOWHEIGHT - (boardHeight * boxSize)) / 2)
return (boxx * boxSize + xmargin, boxy * boxSize + ymargin)
if __name__ == '__main__':
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

58
python_games/launcher.sh Normal file
View File

@ -0,0 +1,58 @@
#!/bin/sh
# Thanks to KenT for contributions
RET=0
SOUND=$(zenity --list --width=350 --height=250 --radiolist \
--title="Choose the Audio Output" \
--column "Select" --column="Output" TRUE "Leave as is" FALSE "Auto" FALSE "Force Headphones" FALSE "Force HDMI" )
RET=$?
echo $SOUND
if [ "$SOUND" = "Leave as is" ]; then
echo "Leave as is"
elif [ "$SOUND" = "Auto" ]; then
amixer -c 0 cset numid=3 0
echo "Auto set"
elif [ "$SOUND" = "Force Headphones" ]; then
amixer -c 0 cset numid=3 1
echo "Headphones set"
elif [ "$SOUND" = "Force HDMI" ]; then
amixer -c 0 cset numid=3 2
echo "HDMI set"
else
echo "cancel"
fi
while [ $RET -eq 0 ]; do
GAME=$(zenity --width=350 --height=700 --list \
--title="Choose the Python game to launch" \
--text="Games by Al Sweigart. Manual at inventwithpython.com/pygame" \
--column="Script name" --column="Description" \
flippy "A game like reversi" \
fourinarow "Get four in a row" \
gemgem "A tile matching puzzle" \
inkspill "Flood the screen with pixels" \
memorypuzzle "Test your memory" \
pentomino "5 block Tetris" \
simulate "Repeat the pattern" \
slidepuzzle "Traditional slide puzzle" \
squirrel "Eat the smaller squirrels" \
starpusher "Sokoban" \
tetromino "Tetris-like game" \
tetrominoforidiots "Tetris for Idiots" \
wormy "Snake-like game" \
website "inventwithpython.com")
RET=$?
echo $RET
if [ "$RET" -eq 0 ]
then
if [ "$GAME" = "website" ]
then
sensible-browser "http://inventwithpython.com/pygame"
else
if [ "$GAME" != "" ]; then
cd /home/pi/python_games
python $GAME.py
fi
fi
fi
done

BIN
python_games/match0.wav Normal file

Binary file not shown.

BIN
python_games/match1.wav Normal file

Binary file not shown.

BIN
python_games/match2.wav Normal file

Binary file not shown.

BIN
python_games/match3.wav Normal file

Binary file not shown.

BIN
python_games/match4.wav Normal file

Binary file not shown.

BIN
python_games/match5.wav Normal file

Binary file not shown.

View File

@ -0,0 +1,292 @@
# Memory Puzzle
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, pygame, sys
from pygame.locals import *
FPS = 30 # frames per second, the general speed of the program
WINDOWWIDTH = 640 # size of window's width in pixels
WINDOWHEIGHT = 480 # size of windows' height in pixels
REVEALSPEED = 8 # speed boxes' sliding reveals and covers
BOXSIZE = 40 # size of box height & width in pixels
GAPSIZE = 10 # size of gap between boxes in pixels
BOARDWIDTH = 10 # number of columns of icons
BOARDHEIGHT = 7 # number of rows of icons
assert (BOARDWIDTH * BOARDHEIGHT) % 2 == 0, 'Board needs to have an even number of boxes for pairs of matches.'
XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * (BOXSIZE + GAPSIZE))) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * (BOXSIZE + GAPSIZE))) / 2)
# R G B
GRAY = (100, 100, 100)
NAVYBLUE = ( 60, 60, 100)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
PURPLE = (255, 0, 255)
CYAN = ( 0, 255, 255)
BGCOLOR = NAVYBLUE
LIGHTBGCOLOR = GRAY
BOXCOLOR = WHITE
HIGHLIGHTCOLOR = BLUE
DONUT = 'donut'
SQUARE = 'square'
DIAMOND = 'diamond'
LINES = 'lines'
OVAL = 'oval'
ALLCOLORS = (RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN)
ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)
assert len(ALLCOLORS) * len(ALLSHAPES) * 2 >= BOARDWIDTH * BOARDHEIGHT, "Board is too big for the number of shapes/colors defined."
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
mousex = 0 # used to store x coordinate of mouse event
mousey = 0 # used to store y coordinate of mouse event
pygame.display.set_caption('Memory Game')
mainBoard = getRandomizedBoard()
revealedBoxes = generateRevealedBoxesData(False)
firstSelection = None # stores the (x, y) of the first box clicked.
DISPLAYSURF.fill(BGCOLOR)
startGameAnimation(mainBoard)
while True: # main game loop
mouseClicked = False
DISPLAYSURF.fill(BGCOLOR) # drawing the window
drawBoard(mainBoard, revealedBoxes)
for event in pygame.event.get(): # event handling loop
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouseClicked = True
boxx, boxy = getBoxAtPixel(mousex, mousey)
if boxx != None and boxy != None:
# The mouse is currently over a box.
if not revealedBoxes[boxx][boxy]:
drawHighlightBox(boxx, boxy)
if not revealedBoxes[boxx][boxy] and mouseClicked:
revealBoxesAnimation(mainBoard, [(boxx, boxy)])
revealedBoxes[boxx][boxy] = True # set the box as "revealed"
if firstSelection == None: # the current box was the first box clicked
firstSelection = (boxx, boxy)
else: # the current box was the second box clicked
# Check if there is a match between the two icons.
icon1shape, icon1color = getShapeAndColor(mainBoard, firstSelection[0], firstSelection[1])
icon2shape, icon2color = getShapeAndColor(mainBoard, boxx, boxy)
if icon1shape != icon2shape or icon1color != icon2color:
# Icons don't match. Re-cover up both selections.
pygame.time.wait(1000) # 1000 milliseconds = 1 sec
coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])
revealedBoxes[firstSelection[0]][firstSelection[1]] = False
revealedBoxes[boxx][boxy] = False
elif hasWon(revealedBoxes): # check if all pairs found
gameWonAnimation(mainBoard)
pygame.time.wait(2000)
# Reset the board
mainBoard = getRandomizedBoard()
revealedBoxes = generateRevealedBoxesData(False)
# Show the fully unrevealed board for a second.
drawBoard(mainBoard, revealedBoxes)
pygame.display.update()
pygame.time.wait(1000)
# Replay the start game animation.
startGameAnimation(mainBoard)
firstSelection = None # reset firstSelection variable
# Redraw the screen and wait a clock tick.
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateRevealedBoxesData(val):
revealedBoxes = []
for i in range(BOARDWIDTH):
revealedBoxes.append([val] * BOARDHEIGHT)
return revealedBoxes
def getRandomizedBoard():
# Get a list of every possible shape in every possible color.
icons = []
for color in ALLCOLORS:
for shape in ALLSHAPES:
icons.append( (shape, color) )
random.shuffle(icons) # randomize the order of the icons list
numIconsUsed = int(BOARDWIDTH * BOARDHEIGHT / 2) # calculate how many icons are needed
icons = icons[:numIconsUsed] * 2 # make two of each
random.shuffle(icons)
# Create the board data structure, with randomly placed icons.
board = []
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(icons[0])
del icons[0] # remove the icons as we assign them
board.append(column)
return board
def splitIntoGroupsOf(groupSize, theList):
# splits a list into a list of lists, where the inner lists have at
# most groupSize number of items.
result = []
for i in range(0, len(theList), groupSize):
result.append(theList[i:i + groupSize])
return result
def leftTopCoordsOfBox(boxx, boxy):
# Convert board coordinates to pixel coordinates
left = boxx * (BOXSIZE + GAPSIZE) + XMARGIN
top = boxy * (BOXSIZE + GAPSIZE) + YMARGIN
return (left, top)
def getBoxAtPixel(x, y):
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left, top = leftTopCoordsOfBox(boxx, boxy)
boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)
if boxRect.collidepoint(x, y):
return (boxx, boxy)
return (None, None)
def drawIcon(shape, color, boxx, boxy):
quarter = int(BOXSIZE * 0.25) # syntactic sugar
half = int(BOXSIZE * 0.5) # syntactic sugar
left, top = leftTopCoordsOfBox(boxx, boxy) # get pixel coords from board coords
# Draw the shapes
if shape == DONUT:
pygame.draw.circle(DISPLAYSURF, color, (left + half, top + half), half - 5)
pygame.draw.circle(DISPLAYSURF, BGCOLOR, (left + half, top + half), quarter - 5)
elif shape == SQUARE:
pygame.draw.rect(DISPLAYSURF, color, (left + quarter, top + quarter, BOXSIZE - half, BOXSIZE - half))
elif shape == DIAMOND:
pygame.draw.polygon(DISPLAYSURF, color, ((left + half, top), (left + BOXSIZE - 1, top + half), (left + half, top + BOXSIZE - 1), (left, top + half)))
elif shape == LINES:
for i in range(0, BOXSIZE, 4):
pygame.draw.line(DISPLAYSURF, color, (left, top + i), (left + i, top))
pygame.draw.line(DISPLAYSURF, color, (left + i, top + BOXSIZE - 1), (left + BOXSIZE - 1, top + i))
elif shape == OVAL:
pygame.draw.ellipse(DISPLAYSURF, color, (left, top + quarter, BOXSIZE, half))
def getShapeAndColor(board, boxx, boxy):
# shape value for x, y spot is stored in board[x][y][0]
# color value for x, y spot is stored in board[x][y][1]
return board[boxx][boxy][0], board[boxx][boxy][1]
def drawBoxCovers(board, boxes, coverage):
# Draws boxes being covered/revealed. "boxes" is a list
# of two-item lists, which have the x & y spot of the box.
for box in boxes:
left, top = leftTopCoordsOfBox(box[0], box[1])
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, BOXSIZE, BOXSIZE))
shape, color = getShapeAndColor(board, box[0], box[1])
drawIcon(shape, color, box[0], box[1])
if coverage > 0: # only draw the cover if there is an coverage
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, coverage, BOXSIZE))
pygame.display.update()
FPSCLOCK.tick(FPS)
def revealBoxesAnimation(board, boxesToReveal):
# Do the "box reveal" animation.
for coverage in range(BOXSIZE, (-REVEALSPEED) - 1, -REVEALSPEED):
drawBoxCovers(board, boxesToReveal, coverage)
def coverBoxesAnimation(board, boxesToCover):
# Do the "box cover" animation.
for coverage in range(0, BOXSIZE + REVEALSPEED, REVEALSPEED):
drawBoxCovers(board, boxesToCover, coverage)
def drawBoard(board, revealed):
# Draws all of the boxes in their covered or revealed state.
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left, top = leftTopCoordsOfBox(boxx, boxy)
if not revealed[boxx][boxy]:
# Draw a covered box.
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))
else:
# Draw the (revealed) icon.
shape, color = getShapeAndColor(board, boxx, boxy)
drawIcon(shape, color, boxx, boxy)
def drawHighlightBox(boxx, boxy):
left, top = leftTopCoordsOfBox(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left - 5, top - 5, BOXSIZE + 10, BOXSIZE + 10), 4)
def startGameAnimation(board):
# Randomly reveal the boxes 8 at a time.
coveredBoxes = generateRevealedBoxesData(False)
boxes = []
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
boxes.append( (x, y) )
random.shuffle(boxes)
boxGroups = splitIntoGroupsOf(8, boxes)
drawBoard(board, coveredBoxes)
for boxGroup in boxGroups:
revealBoxesAnimation(board, boxGroup)
coverBoxesAnimation(board, boxGroup)
def gameWonAnimation(board):
# flash the background color when the player has won
coveredBoxes = generateRevealedBoxesData(True)
color1 = LIGHTBGCOLOR
color2 = BGCOLOR
for i in range(13):
color1, color2 = color2, color1 # swap colors
DISPLAYSURF.fill(color1)
drawBoard(board, coveredBoxes)
pygame.display.update()
pygame.time.wait(300)
def hasWon(revealedBoxes):
# Returns True if all the boxes have been revealed, otherwise False
for i in revealedBoxes:
if False in i:
return False # return False if any boxes are covered.
return True
if __name__ == '__main__':
main()

View File

@ -0,0 +1,167 @@
import random, pygame, sys
from pygame.locals import *
def hhh():
global a, b
pygame.init()
a = pygame.time.Clock()
b = pygame.display.set_mode((640, 480))
j = 0
k = 0
pygame.display.set_caption('Memory Game')
i = c()
hh = d(False)
h = None
b.fill((60, 60, 100))
g(i)
while True:
e = False
b.fill((60, 60, 100))
f(i, hh)
for eee in pygame.event.get():
if eee.type == QUIT or (eee.type == KEYUP and eee.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif eee.type == MOUSEMOTION:
j, k = eee.pos
elif eee.type == MOUSEBUTTONUP:
j, k = eee.pos
e = True
bb, ee = m(j, k)
if bb != None and ee != None:
if not hh[bb][ee]:
n(bb, ee)
if not hh[bb][ee] and e:
o(i, [(bb, ee)])
hh[bb][ee] = True
if h == None:
h = (bb, ee)
else:
q, fff = s(i, h[0], h[1])
r, ggg = s(i, bb, ee)
if q != r or fff != ggg:
pygame.time.wait(1000)
p(i, [(h[0], h[1]), (bb, ee)])
hh[h[0]][h[1]] = False
hh[bb][ee] = False
elif ii(hh):
jj(i)
pygame.time.wait(2000)
i = c()
hh = d(False)
f(i, hh)
pygame.display.update()
pygame.time.wait(1000)
g(i)
h = None
pygame.display.update()
a.tick(30)
def d(ccc):
hh = []
for i in range(10):
hh.append([ccc] * 7)
return hh
def c():
rr = []
for tt in ((255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 128, 0), (255, 0, 255), (0, 255, 255)):
for ss in ('a', 'b', 'c', 'd', 'e'):
rr.append( (ss, tt) )
random.shuffle(rr)
rr = rr[:35] * 2
random.shuffle(rr)
bbb = []
for x in range(10):
v = []
for y in range(7):
v.append(rr[0])
del rr[0]
bbb.append(v)
return bbb
def t(vv, uu):
ww = []
for i in range(0, len(uu), vv):
ww.append(uu[i:i + vv])
return ww
def aa(bb, ee):
return (bb * 50 + 70, ee * 50 + 65)
def m(x, y):
for bb in range(10):
for ee in range(7):
oo, ddd = aa(bb, ee)
aaa = pygame.Rect(oo, ddd, 40, 40)
if aaa.collidepoint(x, y):
return (bb, ee)
return (None, None)
def w(ss, tt, bb, ee):
oo, ddd = aa(bb, ee)
if ss == 'a':
pygame.draw.circle(b, tt, (oo + 20, ddd + 20), 15)
pygame.draw.circle(b, (60, 60, 100), (oo + 20, ddd + 20), 5)
elif ss == 'b':
pygame.draw.rect(b, tt, (oo + 10, ddd + 10, 20, 20))
elif ss == 'c':
pygame.draw.polygon(b, tt, ((oo + 20, ddd), (oo + 40 - 1, ddd + 20), (oo + 20, ddd + 40 - 1), (oo, ddd + 20)))
elif ss == 'd':
for i in range(0, 40, 4):
pygame.draw.line(b, tt, (oo, ddd + i), (oo + i, ddd))
pygame.draw.line(b, tt, (oo + i, ddd + 39), (oo + 39, ddd + i))
elif ss == 'e':
pygame.draw.ellipse(b, tt, (oo, ddd + 10, 40, 20))
def s(bbb, bb, ee):
return bbb[bb][ee][0], bbb[bb][ee][1]
def dd(bbb, boxes, gg):
for box in boxes:
oo, ddd = aa(box[0], box[1])
pygame.draw.rect(b, (60, 60, 100), (oo, ddd, 40, 40))
ss, tt = s(bbb, box[0], box[1])
w(ss, tt, box[0], box[1])
if gg > 0:
pygame.draw.rect(b, (255, 255, 255), (oo, ddd, gg, 40))
pygame.display.update()
a.tick(30)
def o(bbb, cc):
for gg in range(40, (-8) - 1, -8):
dd(bbb, cc, gg)
def p(bbb, ff):
for gg in range(0, 48, 8):
dd(bbb, ff, gg)
def f(bbb, pp):
for bb in range(10):
for ee in range(7):
oo, ddd = aa(bb, ee)
if not pp[bb][ee]:
pygame.draw.rect(b, (255, 255, 255), (oo, ddd, 40, 40))
else:
ss, tt = s(bbb, bb, ee)
w(ss, tt, bb, ee)
def n(bb, ee):
oo, ddd = aa(bb, ee)
pygame.draw.rect(b, (0, 0, 255), (oo - 5, ddd - 5, 50, 50), 4)
def g(bbb):
mm = d(False)
boxes = []
for x in range(10):
for y in range(7):
boxes.append( (x, y) )
random.shuffle(boxes)
kk = t(8, boxes)
f(bbb, mm)
for nn in kk:
o(bbb, nn)
p(bbb, nn)
def jj(bbb):
mm = d(True)
tt1 = (100, 100, 100)
tt2 = (60, 60, 100)
for i in range(13):
tt1, tt2 = tt2, tt1
b.fill(tt1)
f(bbb, mm)
pygame.display.update()
pygame.time.wait(300)
def ii(hh):
for i in hh:
if False in i:
return False
return True
if __name__ == '__main__':
hhh()

749
python_games/pentomino.py Normal file
View File

@ -0,0 +1,749 @@
# Pentomino (a 5-block Tetris clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
# KRT 17/06/2012 rewrite event detection to deal with mouse use
import random, time, pygame, sys
from pygame.locals import *
FPS = 25
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BOXSIZE = 20
BOARDWIDTH = 10
BOARDHEIGHT = 20
BLANK = '.'
MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
# R G B
WHITE = (255, 255, 255)
GRAY = (185, 185, 185)
BLACK = ( 0, 0, 0)
RED = (155, 0, 0)
LIGHTRED = (175, 20, 20)
GREEN = ( 0, 155, 0)
LIGHTGREEN = ( 20, 175, 20)
BLUE = ( 0, 0, 155)
LIGHTBLUE = ( 20, 20, 175)
YELLOW = (155, 155, 0)
LIGHTYELLOW = (175, 175, 20)
BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS = ( BLUE, GREEN, RED, YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color
TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5
F_TEMPLATE = [['.....',
'..OO.',
'.OO..',
'..O..',
'.....'],
['.....',
'..O..',
'.OOO.',
'...O.',
'.....'],
['.....',
'..O..',
'..OO.',
'.OO..',
'.....'],
['.....',
'.O...',
'.OOO.',
'..O..',
'.....']]
RF_TEMPLATE = [['.....',
'.OO..',
'..OO.',
'..O..',
'.....'],
['.....',
'...O.',
'.OOO.',
'..O..',
'.....'],
['.....',
'..O..',
'.OO..',
'..OO.',
'.....'],
['.....',
'..O..',
'.OOO.',
'.O...',
'.....']]
I_TEMPLATE = [['..O..',
'..O..',
'..O..',
'..O..',
'..O..'],
['.....',
'.....',
'OOOOO',
'.....',
'.....']]
L_TEMPLATE = [['..O..',
'..O..',
'..O..',
'..OO.',
'.....'],
['.....',
'.....',
'.OOOO',
'.O...',
'.....'],
['.....',
'.OO..',
'..O..',
'..O..',
'..O..'],
['.....',
'...O.',
'OOOO.',
'.....',
'.....']]
J_TEMPLATE = [['..O..',
'..O..',
'..O..',
'.OO..',
'.....'],
['.....',
'.O...',
'.OOOO',
'.....',
'.....'],
['.....',
'..OO.',
'..O..',
'..O..',
'..O..'],
['.....',
'.....',
'OOOO.',
'...O.',
'.....']]
N_TEMPLATE = [['.....',
'.OO..',
'..OOO',
'.....',
'.....'],
['.....',
'...O.',
'..OO.',
'..O..',
'..O..'],
['.....',
'.....',
'OOO..',
'..OO.',
'.....'],
['..O..',
'..O..',
'.OO..',
'.O...',
'.....']]
RN_TEMPLATE = [['.....',
'..OO.',
'OOO..',
'.....',
'.....'],
['..O..',
'..O..',
'..OO.',
'...O.',
'.....'],
['.....',
'.....',
'..OOO',
'.OO..',
'.....'],
['.....',
'.O...',
'.OO..',
'..O..',
'..O..']]
P_TEMPLATE = [['.....',
'..OO.',
'..OO.',
'..O..',
'.....'],
['.....',
'.....',
'.OOO.',
'..OO.',
'.....'],
['.....',
'..O..',
'.OO..',
'.OO..',
'.....'],
['.....',
'.OO..',
'.OOO.',
'.....',
'.....']]
RP_TEMPLATE = [['.....',
'.OO..',
'.OO..',
'..O..',
'.....'],
['.....',
'..OO.',
'.OOO.',
'.....',
'.....'],
['.....',
'..O..',
'..OO.',
'..OO.',
'.....'],
['.....',
'.....',
'.OOO.',
'.OO..',
'.....']]
T_TEMPLATE = [['.....',
'.OOO.',
'..O..',
'..O..',
'.....'],
['.....',
'...O.',
'.OOO.',
'...O.',
'.....'],
['.....',
'..O..',
'..O..',
'.OOO.',
'.....'],
['.....',
'.O...',
'.OOO.',
'.O...',
'.....']]
U_TEMPLATE = [['.....',
'.O.O.',
'.OOO.',
'.....',
'.....'],
['.....',
'..OO.',
'..O..',
'..OO.',
'.....'],
['.....',
'.....',
'.OOO.',
'.O.O.',
'.....'],
['.....',
'.OO..',
'..O..',
'.OO..',
'.....']]
V_TEMPLATE = [['..O..',
'..O..',
'..OOO',
'.....',
'.....'],
['.....',
'.....',
'..OOO',
'..O..',
'..O..'],
['.....',
'.....',
'OOO..',
'..O..',
'..O..'],
['..O..',
'..O..',
'OOO..',
'.....',
'.....']]
W_TEMPLATE = [['.....',
'.O...',
'.OO..',
'..OO.',
'.....'],
['.....',
'..OO.',
'.OO..',
'.O...',
'.....'],
['.....',
'.OO..',
'..OO.',
'...O.',
'.....'],
['.....',
'...O.',
'..OO.',
'.OO..',
'.....']]
X_TEMPLATE = [['.....',
'..O..',
'.OOO.',
'..O..',
'.....']]
Y_TEMPLATE = [['.....',
'..O..',
'OOOO.',
'.....',
'.....'],
['..O..',
'..O..',
'..OO.',
'..O..',
'.....'],
['.....',
'.....',
'.OOOO',
'..O..',
'.....'],
['.....',
'..O..',
'.OO..',
'..O..',
'..O..']]
RY_TEMPLATE = [['.....',
'.....',
'OOOO.',
'..O..',
'.....'],
['..O..',
'..O..',
'..OO.',
'..O..',
'.....'],
['.....',
'.....',
'.OOOO',
'..O..',
'.....'],
['.....',
'..O..',
'.OO..',
'..O..',
'..O..']]
Z_TEMPLATE = [['.....',
'.OO..',
'..O..',
'..OO.',
'.....'],
['.....',
'...O.',
'.OOO.',
'.O...',
'.....']]
RZ_TEMPLATE = [['.....',
'..OO.',
'..O..',
'.OO..',
'.....'],
['.....',
'.O...',
'.OOO.',
'...O.',
'.....']]
PIECES = {'F': F_TEMPLATE,
'RF': RF_TEMPLATE,
'I': I_TEMPLATE,
'L': L_TEMPLATE,
'J': J_TEMPLATE,
'N': N_TEMPLATE,
'RN': RN_TEMPLATE,
'P': P_TEMPLATE,
'RP': RP_TEMPLATE,
'T': T_TEMPLATE,
'U': U_TEMPLATE,
'V': V_TEMPLATE,
'W': W_TEMPLATE,
'X': X_TEMPLATE,
'Y': Y_TEMPLATE,
'RY': RY_TEMPLATE,
'Z': Z_TEMPLATE,
'RZ': RZ_TEMPLATE}
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
BIGFONT = pygame.font.Font('freesansbold.ttf', 100)
pygame.display.set_caption('Pentomino')
showTextScreen('Pentomino')
while True: # game loop
if random.randint(0, 1) == 0:
pygame.mixer.music.load('tetrisb.mid')
else:
pygame.mixer.music.load('tetrisc.mid')
pygame.mixer.music.play(-1, 0.0)
runGame()
pygame.mixer.music.stop()
showTextScreen('Game Over')
def runGame():
# setup variables for the start of the game
board = getBlankBoard()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
lastFallTime = time.time()
movingDown = False # note: there is no movingUp variable
movingLeft = False
movingRight = False
score = 0
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = getNewPiece()
nextPiece = getNewPiece()
while True: # game loop
if fallingPiece == None:
# No falling piece in play, so start a new piece at the top
fallingPiece = nextPiece
nextPiece = getNewPiece()
lastFallTime = time.time() # reset lastFallTime
if not isValidPosition(board, fallingPiece):
return # can't fit a new piece on the board, so game over
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == KEYUP:
if (event.key == K_p):
# Pausing the game
DISPLAYSURF.fill(BGCOLOR)
pygame.mixer.music.stop()
showTextScreen('Paused') # pause until a key press
pygame.mixer.music.play(-1, 0.0)
lastFallTime = time.time()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
elif (event.key == K_LEFT or event.key == K_a):
movingLeft = False
elif (event.key == K_RIGHT or event.key == K_d):
movingRight = False
elif (event.key == K_DOWN or event.key == K_s):
movingDown = False
elif event.type == KEYDOWN:
# moving the piece sideways
if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
movingLeft = True
movingRight = False
lastMoveSidewaysTime = time.time()
elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
movingRight = True
movingLeft = False
lastMoveSidewaysTime = time.time()
# rotating the piece (if there is room to rotate)
elif (event.key == K_UP or event.key == K_w):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
elif (event.key == K_q): # rotate the other direction
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
# making the piece fall faster with the down key
elif (event.key == K_DOWN or event.key == K_s):
movingDown = True
if isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# move the current piece all the way down
elif event.key == K_SPACE:
movingDown = False
movingLeft = False
movingRight = False
for i in range(1, BOARDHEIGHT):
if not isValidPosition(board, fallingPiece, adjY=i):
break
fallingPiece['y'] += i - 1
# handle moving the piece because of user input
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
lastMoveSidewaysTime = time.time()
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# let the piece fall if it is time to fall
if time.time() - lastFallTime > fallFreq:
# see if the piece has landed
if not isValidPosition(board, fallingPiece, adjY=1):
# falling piece has landed, set it on the board
addToBoard(board, fallingPiece)
score += removeCompleteLines(board)
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = None
else:
# piece did not land, just move the piece down
fallingPiece['y'] += 1
lastFallTime = time.time()
# drawing everything on the screen
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
drawStatus(score, level)
drawNextPiece(nextPiece)
if fallingPiece != None:
drawPiece(fallingPiece)
pygame.display.update()
FPSCLOCK.tick(FPS)
def makeTextObjs(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
def terminate():
pygame.quit()
sys.exit()
# KRT 17/06/2012 rewrite event detection to deal with mouse use
def checkForKeyPress():
for event in pygame.event.get():
if event.type == QUIT: #event is quit
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: #event is escape key
terminate()
else:
return event.key #key found return with it
# no quit or key events in queue so return None
return None
##def checkForKeyPress():
## # Go through event queue looking for a KEYUP event.
## # Grab KEYDOWN events to remove them from the event queue.
## checkForQuit()
##
## for event in pygame.event.get([KEYDOWN, KEYUP]):
## if event.type == KEYDOWN:
## continue
## return event.key
## return None
def showTextScreen(text):
# This function displays large text in the
# center of the screen until a key is pressed.
# Draw the text drop shadow
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the text
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the additional "Press a key to play." text.
pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while checkForKeyPress() == None:
pygame.display.update()
FPSCLOCK.tick()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def calculateLevelAndFallFreq(score):
# Based on the score, return the level the player is on and
# how many seconds pass until a falling piece falls one space.
level = int(score / 10) + 1
fallFreq = 0.27 - (level * 0.02)
return level, fallFreq
def getNewPiece():
# return a random new piece in a random rotation and color
shape = random.choice(list(PIECES.keys()))
newPiece = {'shape': shape,
'rotation': random.randint(0, len(PIECES[shape]) - 1),
'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),
'y': -2, # start it above the board (i.e. less than 0)
'color': random.randint(0, len(COLORS)-1)}
return newPiece
def addToBoard(board, piece):
# fill in the board based on piece's location, shape, and rotation
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
board[x + piece['x']][y + piece['y']] = piece['color']
def getBlankBoard():
# create and return a new blank board data structure
board = []
for i in range(BOARDWIDTH):
board.append([BLANK] * BOARDHEIGHT)
return board
def isOnBoard(x, y):
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT
def isValidPosition(board, piece, adjX=0, adjY=0):
# Return True if the piece is within the board and not colliding
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
return False
return True
def isCompleteLine(board, y):
# Return True if the line filled with boxes with no gaps.
for x in range(BOARDWIDTH):
if board[x][y] == BLANK:
return False
return True
def removeCompleteLines(board):
# Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
numLinesRemoved = 0
y = BOARDHEIGHT - 1 # start y at the bottom of the board
while y >= 0:
if isCompleteLine(board, y):
# Remove the line and pull boxes down by one line.
for pullDownY in range(y, 0, -1):
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]
# Set very top line to blank.
for x in range(BOARDWIDTH):
board[x][0] = BLANK
numLinesRemoved += 1
# Note on the next iteration of the loop, y is the same.
# This is so that if the line that was pulled down is also
# complete, it will be removed.
else:
y -= 1 # move on to check next row up
return numLinesRemoved
def convertToPixelCoords(boxx, boxy):
# Convert the given xy coordinates of the board to xy
# coordinates of the location on the screen.
return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
# draw a single box (each pentomino piece has four boxes)
# at xy coordinates on the board. Or, if pixelx & pixely
# are specified, draw to the pixel coordinates stored in
# pixelx & pixely (this is used for the "Next" piece).
if color == BLANK:
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))
def drawBoard(board):
# draw the border around the board
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)
# fill the background of the board
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
# draw the individual boxes on the board
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
drawBox(x, y, board[x][y])
def drawStatus(score, level):
# draw the score text
scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 150, 20)
DISPLAYSURF.blit(scoreSurf, scoreRect)
# draw the level text
levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
levelRect = levelSurf.get_rect()
levelRect.topleft = (WINDOWWIDTH - 150, 50)
DISPLAYSURF.blit(levelSurf, levelRect)
def drawPiece(piece, pixelx=None, pixely=None):
shapeToDraw = PIECES[piece['shape']][piece['rotation']]
if pixelx == None and pixely == None:
# if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])
# draw each of the boxes that make up the piece
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != BLANK:
drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))
def drawNextPiece(piece):
# draw the "next" text
nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
nextRect = nextSurf.get_rect()
nextRect.topleft = (WINDOWWIDTH - 120, 80)
DISPLAYSURF.blit(nextSurf, nextRect)
# draw the "next" piece
drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)
if __name__ == '__main__':
main()

BIN
python_games/pinkgirl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
python_games/princess.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

251
python_games/simulate.py Normal file
View File

@ -0,0 +1,251 @@
# Simulate (a Simon clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, sys, time, pygame
from pygame.locals import *
FPS = 30
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
FLASHSPEED = 500 # in milliseconds
FLASHDELAY = 200 # in milliseconds
BUTTONSIZE = 200
BUTTONGAPSIZE = 20
TIMEOUT = 4 # seconds before game over if no button is pushed.
# R G B
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
BRIGHTRED = (255, 0, 0)
RED = (155, 0, 0)
BRIGHTGREEN = ( 0, 255, 0)
GREEN = ( 0, 155, 0)
BRIGHTBLUE = ( 0, 0, 255)
BLUE = ( 0, 0, 155)
BRIGHTYELLOW = (255, 255, 0)
YELLOW = (155, 155, 0)
DARKGRAY = ( 40, 40, 40)
bgColor = BLACK
XMARGIN = int((WINDOWWIDTH - (2 * BUTTONSIZE) - BUTTONGAPSIZE) / 2)
YMARGIN = int((WINDOWHEIGHT - (2 * BUTTONSIZE) - BUTTONGAPSIZE) / 2)
# Rect objects for each of the four buttons
YELLOWRECT = pygame.Rect(XMARGIN, YMARGIN, BUTTONSIZE, BUTTONSIZE)
BLUERECT = pygame.Rect(XMARGIN + BUTTONSIZE + BUTTONGAPSIZE, YMARGIN, BUTTONSIZE, BUTTONSIZE)
REDRECT = pygame.Rect(XMARGIN, YMARGIN + BUTTONSIZE + BUTTONGAPSIZE, BUTTONSIZE, BUTTONSIZE)
GREENRECT = pygame.Rect(XMARGIN + BUTTONSIZE + BUTTONGAPSIZE, YMARGIN + BUTTONSIZE + BUTTONGAPSIZE, BUTTONSIZE, BUTTONSIZE)
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, BEEP1, BEEP2, BEEP3, BEEP4
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Simulate')
BASICFONT = pygame.font.Font('freesansbold.ttf', 16)
infoSurf = BASICFONT.render('Match the pattern by clicking on the button or using the Q, W, A, S keys.', 1, DARKGRAY)
infoRect = infoSurf.get_rect()
infoRect.topleft = (10, WINDOWHEIGHT - 25)
# load the sound files
BEEP1 = pygame.mixer.Sound('beep1.ogg')
BEEP2 = pygame.mixer.Sound('beep2.ogg')
BEEP3 = pygame.mixer.Sound('beep3.ogg')
BEEP4 = pygame.mixer.Sound('beep4.ogg')
# Initialize some variables for a new game
pattern = [] # stores the pattern of colors
currentStep = 0 # the color the player must push next
lastClickTime = 0 # timestamp of the player's last button push
score = 0
# when False, the pattern is playing. when True, waiting for the player to click a colored button:
waitingForInput = False
while True: # main game loop
clickedButton = None # button that was clicked (set to YELLOW, RED, GREEN, or BLUE)
DISPLAYSURF.fill(bgColor)
drawButtons()
scoreSurf = BASICFONT.render('Score: ' + str(score), 1, WHITE)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 100, 10)
DISPLAYSURF.blit(scoreSurf, scoreRect)
DISPLAYSURF.blit(infoSurf, infoRect)
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
clickedButton = getButtonClicked(mousex, mousey)
elif event.type == KEYDOWN:
if event.key == K_q:
clickedButton = YELLOW
elif event.key == K_w:
clickedButton = BLUE
elif event.key == K_a:
clickedButton = RED
elif event.key == K_s:
clickedButton = GREEN
if not waitingForInput:
# play the pattern
pygame.display.update()
pygame.time.wait(1000)
pattern.append(random.choice((YELLOW, BLUE, RED, GREEN)))
for button in pattern:
flashButtonAnimation(button)
pygame.time.wait(FLASHDELAY)
waitingForInput = True
else:
# wait for the player to enter buttons
if clickedButton and clickedButton == pattern[currentStep]:
# pushed the correct button
flashButtonAnimation(clickedButton)
currentStep += 1
lastClickTime = time.time()
if currentStep == len(pattern):
# pushed the last button in the pattern
changeBackgroundAnimation()
score += 1
waitingForInput = False
currentStep = 0 # reset back to first step
elif (clickedButton and clickedButton != pattern[currentStep]) or (currentStep != 0 and time.time() - TIMEOUT > lastClickTime):
# pushed the incorrect button, or has timed out
gameOverAnimation()
# reset the variables for a new game:
pattern = []
currentStep = 0
waitingForInput = False
score = 0
pygame.time.wait(1000)
changeBackgroundAnimation()
pygame.display.update()
FPSCLOCK.tick(FPS)
def terminate():
pygame.quit()
sys.exit()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def flashButtonAnimation(color, animationSpeed=50):
if color == YELLOW:
sound = BEEP1
flashColor = BRIGHTYELLOW
rectangle = YELLOWRECT
elif color == BLUE:
sound = BEEP2
flashColor = BRIGHTBLUE
rectangle = BLUERECT
elif color == RED:
sound = BEEP3
flashColor = BRIGHTRED
rectangle = REDRECT
elif color == GREEN:
sound = BEEP4
flashColor = BRIGHTGREEN
rectangle = GREENRECT
origSurf = DISPLAYSURF.copy()
flashSurf = pygame.Surface((BUTTONSIZE, BUTTONSIZE))
flashSurf = flashSurf.convert_alpha()
r, g, b = flashColor
sound.play()
for start, end, step in ((0, 255, 1), (255, 0, -1)): # animation loop
for alpha in range(start, end, animationSpeed * step):
checkForQuit()
DISPLAYSURF.blit(origSurf, (0, 0))
flashSurf.fill((r, g, b, alpha))
DISPLAYSURF.blit(flashSurf, rectangle.topleft)
pygame.display.update()
FPSCLOCK.tick(FPS)
DISPLAYSURF.blit(origSurf, (0, 0))
def drawButtons():
pygame.draw.rect(DISPLAYSURF, YELLOW, YELLOWRECT)
pygame.draw.rect(DISPLAYSURF, BLUE, BLUERECT)
pygame.draw.rect(DISPLAYSURF, RED, REDRECT)
pygame.draw.rect(DISPLAYSURF, GREEN, GREENRECT)
def changeBackgroundAnimation(animationSpeed=40):
global bgColor
newBgColor = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
newBgSurf = pygame.Surface((WINDOWWIDTH, WINDOWHEIGHT))
newBgSurf = newBgSurf.convert_alpha()
r, g, b = newBgColor
for alpha in range(0, 255, animationSpeed): # animation loop
checkForQuit()
DISPLAYSURF.fill(bgColor)
newBgSurf.fill((r, g, b, alpha))
DISPLAYSURF.blit(newBgSurf, (0, 0))
drawButtons() # redraw the buttons on top of the tint
pygame.display.update()
FPSCLOCK.tick(FPS)
bgColor = newBgColor
def gameOverAnimation(color=WHITE, animationSpeed=50):
# play all beeps at once, then flash the background
origSurf = DISPLAYSURF.copy()
flashSurf = pygame.Surface(DISPLAYSURF.get_size())
flashSurf = flashSurf.convert_alpha()
BEEP1.play() # play all four beeps at the same time, roughly.
BEEP2.play()
BEEP3.play()
BEEP4.play()
r, g, b = color
for i in range(3): # do the flash 3 times
for start, end, step in ((0, 255, 1), (255, 0, -1)):
# The first iteration in this loop sets the following for loop
# to go from 0 to 255, the second from 255 to 0.
for alpha in range(start, end, animationSpeed * step): # animation loop
# alpha means transparency. 255 is opaque, 0 is invisible
checkForQuit()
flashSurf.fill((r, g, b, alpha))
DISPLAYSURF.blit(origSurf, (0, 0))
DISPLAYSURF.blit(flashSurf, (0, 0))
drawButtons()
pygame.display.update()
FPSCLOCK.tick(FPS)
def getButtonClicked(x, y):
if YELLOWRECT.collidepoint( (x, y) ):
return YELLOW
elif BLUERECT.collidepoint( (x, y) ):
return BLUE
elif REDRECT.collidepoint( (x, y) ):
return RED
elif GREENRECT.collidepoint( (x, y) ):
return GREEN
return None
if __name__ == '__main__':
main()

332
python_games/slidepuzzle.py Normal file
View File

@ -0,0 +1,332 @@
# Slide Puzzle
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import pygame, sys, random
from pygame.locals import *
# Create the constants (go ahead and experiment with different values)
BOARDWIDTH = 4 # number of columns in the board
BOARDHEIGHT = 4 # number of rows in the board
TILESIZE = 80
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
FPS = 30
BLANK = None
# R G B
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BRIGHTBLUE = ( 0, 50, 255)
DARKTURQUOISE = ( 3, 54, 73)
GREEN = ( 0, 204, 0)
BGCOLOR = DARKTURQUOISE
TILECOLOR = GREEN
TEXTCOLOR = WHITE
BORDERCOLOR = BRIGHTBLUE
BASICFONTSIZE = 20
BUTTONCOLOR = WHITE
BUTTONTEXTCOLOR = BLACK
MESSAGECOLOR = WHITE
XMARGIN = int((WINDOWWIDTH - (TILESIZE * BOARDWIDTH + (BOARDWIDTH - 1))) / 2)
YMARGIN = int((WINDOWHEIGHT - (TILESIZE * BOARDHEIGHT + (BOARDHEIGHT - 1))) / 2)
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, RESET_SURF, RESET_RECT, NEW_SURF, NEW_RECT, SOLVE_SURF, SOLVE_RECT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Slide Puzzle')
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
# Store the option buttons and their rectangles in OPTIONS.
RESET_SURF, RESET_RECT = makeText('Reset', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 90)
NEW_SURF, NEW_RECT = makeText('New Game', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 60)
SOLVE_SURF, SOLVE_RECT = makeText('Solve', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 30)
mainBoard, solutionSeq = generateNewPuzzle(80)
SOLVEDBOARD = getStartingBoard() # a solved board is the same as the board in a start state.
allMoves = [] # list of moves made from the solved configuration
while True: # main game loop
slideTo = None # the direction, if any, a tile should slide
msg = 'Click tile or press arrow keys to slide.' # contains the message to show in the upper left corner.
if mainBoard == SOLVEDBOARD:
msg = 'Solved!'
drawBoard(mainBoard, msg)
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
spotx, spoty = getSpotClicked(mainBoard, event.pos[0], event.pos[1])
if (spotx, spoty) == (None, None):
# check if the user clicked on an option button
if RESET_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, allMoves) # clicked on Reset button
allMoves = []
elif NEW_RECT.collidepoint(event.pos):
mainBoard, solutionSeq = generateNewPuzzle(80) # clicked on New Game button
allMoves = []
elif SOLVE_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, solutionSeq + allMoves) # clicked on Solve button
allMoves = []
else:
# check if the clicked tile was next to the blank spot
blankx, blanky = getBlankPosition(mainBoard)
if spotx == blankx + 1 and spoty == blanky:
slideTo = LEFT
elif spotx == blankx - 1 and spoty == blanky:
slideTo = RIGHT
elif spotx == blankx and spoty == blanky + 1:
slideTo = UP
elif spotx == blankx and spoty == blanky - 1:
slideTo = DOWN
elif event.type == KEYUP:
# check if the user pressed a key to slide a tile
if event.key in (K_LEFT, K_a) and isValidMove(mainBoard, LEFT):
slideTo = LEFT
elif event.key in (K_RIGHT, K_d) and isValidMove(mainBoard, RIGHT):
slideTo = RIGHT
elif event.key in (K_UP, K_w) and isValidMove(mainBoard, UP):
slideTo = UP
elif event.key in (K_DOWN, K_s) and isValidMove(mainBoard, DOWN):
slideTo = DOWN
if slideTo:
slideAnimation(mainBoard, slideTo, 'Click tile or press arrow keys to slide.', 8) # show slide on screen
makeMove(mainBoard, slideTo)
allMoves.append(slideTo) # record the slide
pygame.display.update()
FPSCLOCK.tick(FPS)
def terminate():
pygame.quit()
sys.exit()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def getStartingBoard():
# Return a board data structure with tiles in the solved state.
# For example, if BOARDWIDTH and BOARDHEIGHT are both 3, this function
# returns [[1, 4, 7], [2, 5, 8], [3, 6, BLANK]]
counter = 1
board = []
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(counter)
counter += BOARDWIDTH
board.append(column)
counter -= BOARDWIDTH * (BOARDHEIGHT - 1) + BOARDWIDTH - 1
board[BOARDWIDTH-1][BOARDHEIGHT-1] = BLANK
return board
def getBlankPosition(board):
# Return the x and y of board coordinates of the blank space.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == BLANK:
return (x, y)
def makeMove(board, move):
# This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if move == UP:
board[blankx][blanky], board[blankx][blanky + 1] = board[blankx][blanky + 1], board[blankx][blanky]
elif move == DOWN:
board[blankx][blanky], board[blankx][blanky - 1] = board[blankx][blanky - 1], board[blankx][blanky]
elif move == LEFT:
board[blankx][blanky], board[blankx + 1][blanky] = board[blankx + 1][blanky], board[blankx][blanky]
elif move == RIGHT:
board[blankx][blanky], board[blankx - 1][blanky] = board[blankx - 1][blanky], board[blankx][blanky]
def isValidMove(board, move):
blankx, blanky = getBlankPosition(board)
return (move == UP and blanky != len(board[0]) - 1) or \
(move == DOWN and blanky != 0) or \
(move == LEFT and blankx != len(board) - 1) or \
(move == RIGHT and blankx != 0)
def getRandomMove(board, lastMove=None):
# start with a full list of all four moves
validMoves = [UP, DOWN, LEFT, RIGHT]
# remove moves from the list as they are disqualified
if lastMove == UP or not isValidMove(board, DOWN):
validMoves.remove(DOWN)
if lastMove == DOWN or not isValidMove(board, UP):
validMoves.remove(UP)
if lastMove == LEFT or not isValidMove(board, RIGHT):
validMoves.remove(RIGHT)
if lastMove == RIGHT or not isValidMove(board, LEFT):
validMoves.remove(LEFT)
# return a random move from the list of remaining moves
return random.choice(validMoves)
def getLeftTopOfTile(tileX, tileY):
left = XMARGIN + (tileX * TILESIZE) + (tileX - 1)
top = YMARGIN + (tileY * TILESIZE) + (tileY - 1)
return (left, top)
def getSpotClicked(board, x, y):
# from the x & y pixel coordinates, get the x & y board coordinates
for tileX in range(len(board)):
for tileY in range(len(board[0])):
left, top = getLeftTopOfTile(tileX, tileY)
tileRect = pygame.Rect(left, top, TILESIZE, TILESIZE)
if tileRect.collidepoint(x, y):
return (tileX, tileY)
return (None, None)
def drawTile(tilex, tiley, number, adjx=0, adjy=0):
# draw a tile at board coordinates tilex and tiley, optionally a few
# pixels over (determined by adjx and adjy)
left, top = getLeftTopOfTile(tilex, tiley)
pygame.draw.rect(DISPLAYSURF, TILECOLOR, (left + adjx, top + adjy, TILESIZE, TILESIZE))
textSurf = BASICFONT.render(str(number), True, TEXTCOLOR)
textRect = textSurf.get_rect()
textRect.center = left + int(TILESIZE / 2) + adjx, top + int(TILESIZE / 2) + adjy
DISPLAYSURF.blit(textSurf, textRect)
def makeText(text, color, bgcolor, top, left):
# create the Surface and Rect objects for some text.
textSurf = BASICFONT.render(text, True, color, bgcolor)
textRect = textSurf.get_rect()
textRect.topleft = (top, left)
return (textSurf, textRect)
def drawBoard(board, message):
DISPLAYSURF.fill(BGCOLOR)
if message:
textSurf, textRect = makeText(message, MESSAGECOLOR, BGCOLOR, 5, 5)
DISPLAYSURF.blit(textSurf, textRect)
for tilex in range(len(board)):
for tiley in range(len(board[0])):
if board[tilex][tiley]:
drawTile(tilex, tiley, board[tilex][tiley])
left, top = getLeftTopOfTile(0, 0)
width = BOARDWIDTH * TILESIZE
height = BOARDHEIGHT * TILESIZE
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (left - 5, top - 5, width + 11, height + 11), 4)
DISPLAYSURF.blit(RESET_SURF, RESET_RECT)
DISPLAYSURF.blit(NEW_SURF, NEW_RECT)
DISPLAYSURF.blit(SOLVE_SURF, SOLVE_RECT)
def slideAnimation(board, direction, message, animationSpeed):
# Note: This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if direction == UP:
movex = blankx
movey = blanky + 1
elif direction == DOWN:
movex = blankx
movey = blanky - 1
elif direction == LEFT:
movex = blankx + 1
movey = blanky
elif direction == RIGHT:
movex = blankx - 1
movey = blanky
# prepare the base surface
drawBoard(board, message)
baseSurf = DISPLAYSURF.copy()
# draw a blank space over the moving tile on the baseSurf Surface.
moveLeft, moveTop = getLeftTopOfTile(movex, movey)
pygame.draw.rect(baseSurf, BGCOLOR, (moveLeft, moveTop, TILESIZE, TILESIZE))
for i in range(0, TILESIZE, animationSpeed):
# animate the tile sliding over
checkForQuit()
DISPLAYSURF.blit(baseSurf, (0, 0))
if direction == UP:
drawTile(movex, movey, board[movex][movey], 0, -i)
if direction == DOWN:
drawTile(movex, movey, board[movex][movey], 0, i)
if direction == LEFT:
drawTile(movex, movey, board[movex][movey], -i, 0)
if direction == RIGHT:
drawTile(movex, movey, board[movex][movey], i, 0)
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateNewPuzzle(numSlides):
# From a starting configuration, make numSlides number of moves (and
# animate these moves).
sequence = []
board = getStartingBoard()
drawBoard(board, '')
pygame.display.update()
pygame.time.wait(500) # pause 500 milliseconds for effect
lastMove = None
for i in range(numSlides):
move = getRandomMove(board, lastMove)
slideAnimation(board, move, 'Generating new puzzle...', animationSpeed=int(TILESIZE / 3))
makeMove(board, move)
sequence.append(move)
lastMove = move
return (board, sequence)
def resetAnimation(board, allMoves):
# make all of the moves in allMoves in reverse.
revAllMoves = allMoves[:] # gets a copy of the list
revAllMoves.reverse()
for move in revAllMoves:
if move == UP:
oppositeMove = DOWN
elif move == DOWN:
oppositeMove = UP
elif move == RIGHT:
oppositeMove = LEFT
elif move == LEFT:
oppositeMove = RIGHT
slideAnimation(board, oppositeMove, '', animationSpeed=int(TILESIZE / 2))
makeMove(board, oppositeMove)
if __name__ == '__main__':
main()

BIN
python_games/squirrel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

396
python_games/squirrel.py Normal file
View File

@ -0,0 +1,396 @@
# Squirrel Eat Squirrel (a 2D Katamari Damacy clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, sys, time, math, pygame
from pygame.locals import *
FPS = 30 # frames per second to update the screen
WINWIDTH = 640 # width of the program's window, in pixels
WINHEIGHT = 480 # height in pixels
HALF_WINWIDTH = int(WINWIDTH / 2)
HALF_WINHEIGHT = int(WINHEIGHT / 2)
GRASSCOLOR = (24, 255, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
CAMERASLACK = 90 # how far from the center the squirrel moves before moving the camera
MOVERATE = 9 # how fast the player moves
BOUNCERATE = 6 # how fast the player bounces (large is slower)
BOUNCEHEIGHT = 30 # how high the player bounces
STARTSIZE = 25 # how big the player starts off
WINSIZE = 300 # how big the player needs to be to win
INVULNTIME = 2 # how long the player is invulnerable after being hit in seconds
GAMEOVERTIME = 4 # how long the "game over" text stays on the screen in seconds
MAXHEALTH = 3 # how much health the player starts with
NUMGRASS = 80 # number of grass objects in the active area
NUMSQUIRRELS = 30 # number of squirrels in the active area
SQUIRRELMINSPEED = 3 # slowest squirrel speed
SQUIRRELMAXSPEED = 7 # fastest squirrel speed
DIRCHANGEFREQ = 2 # % chance of direction change per frame
LEFT = 'left'
RIGHT = 'right'
"""
This program has three data structures to represent the player, enemy squirrels, and grass background objects. The data structures are dictionaries with the following keys:
Keys used by all three data structures:
'x' - the left edge coordinate of the object in the game world (not a pixel coordinate on the screen)
'y' - the top edge coordinate of the object in the game world (not a pixel coordinate on the screen)
'rect' - the pygame.Rect object representing where on the screen the object is located.
Player data structure keys:
'surface' - the pygame.Surface object that stores the image of the squirrel which will be drawn to the screen.
'facing' - either set to LEFT or RIGHT, stores which direction the player is facing.
'size' - the width and height of the player in pixels. (The width & height are always the same.)
'bounce' - represents at what point in a bounce the player is in. 0 means standing (no bounce), up to BOUNCERATE (the completion of the bounce)
'health' - an integer showing how many more times the player can be hit by a larger squirrel before dying.
Enemy Squirrel data structure keys:
'surface' - the pygame.Surface object that stores the image of the squirrel which will be drawn to the screen.
'movex' - how many pixels per frame the squirrel moves horizontally. A negative integer is moving to the left, a positive to the right.
'movey' - how many pixels per frame the squirrel moves vertically. A negative integer is moving up, a positive moving down.
'width' - the width of the squirrel's image, in pixels
'height' - the height of the squirrel's image, in pixels
'bounce' - represents at what point in a bounce the player is in. 0 means standing (no bounce), up to BOUNCERATE (the completion of the bounce)
'bouncerate' - how quickly the squirrel bounces. A lower number means a quicker bounce.
'bounceheight' - how high (in pixels) the squirrel bounces
Grass data structure keys:
'grassImage' - an integer that refers to the index of the pygame.Surface object in GRASSIMAGES used for this grass object
"""
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, L_SQUIR_IMG, R_SQUIR_IMG, GRASSIMAGES
pygame.init()
FPSCLOCK = pygame.time.Clock()
pygame.display.set_icon(pygame.image.load('gameicon.png'))
DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))
pygame.display.set_caption('Squirrel Eat Squirrel')
BASICFONT = pygame.font.Font('freesansbold.ttf', 32)
# load the image files
L_SQUIR_IMG = pygame.image.load('squirrel.png')
R_SQUIR_IMG = pygame.transform.flip(L_SQUIR_IMG, True, False)
GRASSIMAGES = []
for i in range(1, 5):
GRASSIMAGES.append(pygame.image.load('grass%s.png' % i))
while True:
runGame()
def runGame():
# set up variables for the start of a new game
invulnerableMode = False # if the player is invulnerable
invulnerableStartTime = 0 # time the player became invulnerable
gameOverMode = False # if the player has lost
gameOverStartTime = 0 # time the player lost
winMode = False # if the player has won
# create the surfaces to hold game text
gameOverSurf = BASICFONT.render('Game Over', True, WHITE)
gameOverRect = gameOverSurf.get_rect()
gameOverRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
winSurf = BASICFONT.render('You have achieved OMEGA SQUIRREL!', True, WHITE)
winRect = winSurf.get_rect()
winRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
winSurf2 = BASICFONT.render('(Press "r" to restart.)', True, WHITE)
winRect2 = winSurf2.get_rect()
winRect2.center = (HALF_WINWIDTH, HALF_WINHEIGHT + 30)
# camerax and cameray are the top left of where the camera view is
camerax = 0
cameray = 0
grassObjs = [] # stores all the grass objects in the game
squirrelObjs = [] # stores all the non-player squirrel objects
# stores the player object:
playerObj = {'surface': pygame.transform.scale(L_SQUIR_IMG, (STARTSIZE, STARTSIZE)),
'facing': LEFT,
'size': STARTSIZE,
'x': HALF_WINWIDTH,
'y': HALF_WINHEIGHT,
'bounce':0,
'health': MAXHEALTH}
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
# start off with some random grass images on the screen
for i in range(10):
grassObjs.append(makeNewGrass(camerax, cameray))
grassObjs[i]['x'] = random.randint(0, WINWIDTH)
grassObjs[i]['y'] = random.randint(0, WINHEIGHT)
while True: # main game loop
# Check if we should turn off invulnerability
if invulnerableMode and time.time() - invulnerableStartTime > INVULNTIME:
invulnerableMode = False
# move all the squirrels
for sObj in squirrelObjs:
# move the squirrel, and adjust for their bounce
sObj['x'] += sObj['movex']
sObj['y'] += sObj['movey']
sObj['bounce'] += 1
if sObj['bounce'] > sObj['bouncerate']:
sObj['bounce'] = 0 # reset bounce amount
# random chance they change direction
if random.randint(0, 99) < DIRCHANGEFREQ:
sObj['movex'] = getRandomVelocity()
sObj['movey'] = getRandomVelocity()
if sObj['movex'] > 0: # faces right
sObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sObj['width'], sObj['height']))
else: # faces left
sObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sObj['width'], sObj['height']))
# go through all the objects and see if any need to be deleted.
for i in range(len(grassObjs) - 1, -1, -1):
if isOutsideActiveArea(camerax, cameray, grassObjs[i]):
del grassObjs[i]
for i in range(len(squirrelObjs) - 1, -1, -1):
if isOutsideActiveArea(camerax, cameray, squirrelObjs[i]):
del squirrelObjs[i]
# add more grass & squirrels if we don't have enough.
while len(grassObjs) < NUMGRASS:
grassObjs.append(makeNewGrass(camerax, cameray))
while len(squirrelObjs) < NUMSQUIRRELS:
squirrelObjs.append(makeNewSquirrel(camerax, cameray))
# adjust camerax and cameray if beyond the "camera slack"
playerCenterx = playerObj['x'] + int(playerObj['size'] / 2)
playerCentery = playerObj['y'] + int(playerObj['size'] / 2)
if (camerax + HALF_WINWIDTH) - playerCenterx > CAMERASLACK:
camerax = playerCenterx + CAMERASLACK - HALF_WINWIDTH
elif playerCenterx - (camerax + HALF_WINWIDTH) > CAMERASLACK:
camerax = playerCenterx - CAMERASLACK - HALF_WINWIDTH
if (cameray + HALF_WINHEIGHT) - playerCentery > CAMERASLACK:
cameray = playerCentery + CAMERASLACK - HALF_WINHEIGHT
elif playerCentery - (cameray + HALF_WINHEIGHT) > CAMERASLACK:
cameray = playerCentery - CAMERASLACK - HALF_WINHEIGHT
# draw the green background
DISPLAYSURF.fill(GRASSCOLOR)
# draw all the grass objects on the screen
for gObj in grassObjs:
gRect = pygame.Rect( (gObj['x'] - camerax,
gObj['y'] - cameray,
gObj['width'],
gObj['height']) )
DISPLAYSURF.blit(GRASSIMAGES[gObj['grassImage']], gRect)
# draw the other squirrels
for sObj in squirrelObjs:
sObj['rect'] = pygame.Rect( (sObj['x'] - camerax,
sObj['y'] - cameray - getBounceAmount(sObj['bounce'], sObj['bouncerate'], sObj['bounceheight']),
sObj['width'],
sObj['height']) )
DISPLAYSURF.blit(sObj['surface'], sObj['rect'])
# draw the player squirrel
flashIsOn = round(time.time(), 1) * 10 % 2 == 1
if not gameOverMode and not (invulnerableMode and flashIsOn):
playerObj['rect'] = pygame.Rect( (playerObj['x'] - camerax,
playerObj['y'] - cameray - getBounceAmount(playerObj['bounce'], BOUNCERATE, BOUNCEHEIGHT),
playerObj['size'],
playerObj['size']) )
DISPLAYSURF.blit(playerObj['surface'], playerObj['rect'])
# draw the health meter
drawHealthMeter(playerObj['health'])
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if event.key in (K_UP, K_w):
moveDown = False
moveUp = True
elif event.key in (K_DOWN, K_s):
moveUp = False
moveDown = True
elif event.key in (K_LEFT, K_a):
moveRight = False
moveLeft = True
if playerObj['facing'] != LEFT: # change player image
playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
playerObj['facing'] = LEFT
elif event.key in (K_RIGHT, K_d):
moveLeft = False
moveRight = True
if playerObj['facing'] != RIGHT: # change player image
playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
playerObj['facing'] = RIGHT
elif winMode and event.key == K_r:
return
elif event.type == KEYUP:
# stop moving the player's squirrel
if event.key in (K_LEFT, K_a):
moveLeft = False
elif event.key in (K_RIGHT, K_d):
moveRight = False
elif event.key in (K_UP, K_w):
moveUp = False
elif event.key in (K_DOWN, K_s):
moveDown = False
elif event.key == K_ESCAPE:
terminate()
if not gameOverMode:
# actually move the player
if moveLeft:
playerObj['x'] -= MOVERATE
if moveRight:
playerObj['x'] += MOVERATE
if moveUp:
playerObj['y'] -= MOVERATE
if moveDown:
playerObj['y'] += MOVERATE
if (moveLeft or moveRight or moveUp or moveDown) or playerObj['bounce'] != 0:
playerObj['bounce'] += 1
if playerObj['bounce'] > BOUNCERATE:
playerObj['bounce'] = 0 # reset bounce amount
# check if the player has collided with any squirrels
for i in range(len(squirrelObjs)-1, -1, -1):
sqObj = squirrelObjs[i]
if 'rect' in sqObj and playerObj['rect'].colliderect(sqObj['rect']):
# a player/squirrel collision has occurred
if sqObj['width'] * sqObj['height'] <= playerObj['size']**2:
# player is larger and eats the squirrel
playerObj['size'] += int( (sqObj['width'] * sqObj['height'])**0.2 ) + 1
del squirrelObjs[i]
if playerObj['facing'] == LEFT:
playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
if playerObj['facing'] == RIGHT:
playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
if playerObj['size'] > WINSIZE:
winMode = True # turn on "win mode"
elif not invulnerableMode:
# player is smaller and takes damage
invulnerableMode = True
invulnerableStartTime = time.time()
playerObj['health'] -= 1
if playerObj['health'] == 0:
gameOverMode = True # turn on "game over mode"
gameOverStartTime = time.time()
else:
# game is over, show "game over" text
DISPLAYSURF.blit(gameOverSurf, gameOverRect)
if time.time() - gameOverStartTime > GAMEOVERTIME:
return # end the current game
# check if the player has won.
if winMode:
DISPLAYSURF.blit(winSurf, winRect)
DISPLAYSURF.blit(winSurf2, winRect2)
pygame.display.update()
FPSCLOCK.tick(FPS)
def drawHealthMeter(currentHealth):
for i in range(currentHealth): # draw red health bars
pygame.draw.rect(DISPLAYSURF, RED, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10))
for i in range(MAXHEALTH): # draw the white outlines
pygame.draw.rect(DISPLAYSURF, WHITE, (15, 5 + (10 * MAXHEALTH) - i * 10, 20, 10), 1)
def terminate():
pygame.quit()
sys.exit()
def getBounceAmount(currentBounce, bounceRate, bounceHeight):
# Returns the number of pixels to offset based on the bounce.
# Larger bounceRate means a slower bounce.
# Larger bounceHeight means a higher bounce.
# currentBounce will always be less than bounceRate
return int(math.sin( (math.pi / float(bounceRate)) * currentBounce ) * bounceHeight)
def getRandomVelocity():
speed = random.randint(SQUIRRELMINSPEED, SQUIRRELMAXSPEED)
if random.randint(0, 1) == 0:
return speed
else:
return -speed
def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
# create a Rect of the camera view
cameraRect = pygame.Rect(camerax, cameray, WINWIDTH, WINHEIGHT)
while True:
x = random.randint(camerax - WINWIDTH, camerax + (2 * WINWIDTH))
y = random.randint(cameray - WINHEIGHT, cameray + (2 * WINHEIGHT))
# create a Rect object with the random coordinates and use colliderect()
# to make sure the right edge isn't in the camera view.
objRect = pygame.Rect(x, y, objWidth, objHeight)
if not objRect.colliderect(cameraRect):
return x, y
def makeNewSquirrel(camerax, cameray):
sq = {}
generalSize = random.randint(5, 25)
multiplier = random.randint(1, 3)
sq['width'] = (generalSize + random.randint(0, 10)) * multiplier
sq['height'] = (generalSize + random.randint(0, 10)) * multiplier
sq['x'], sq['y'] = getRandomOffCameraPos(camerax, cameray, sq['width'], sq['height'])
sq['movex'] = getRandomVelocity()
sq['movey'] = getRandomVelocity()
if sq['movex'] < 0: # squirrel is facing left
sq['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sq['width'], sq['height']))
else: # squirrel is facing right
sq['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sq['width'], sq['height']))
sq['bounce'] = 0
sq['bouncerate'] = random.randint(10, 18)
sq['bounceheight'] = random.randint(10, 50)
return sq
def makeNewGrass(camerax, cameray):
gr = {}
gr['grassImage'] = random.randint(0, len(GRASSIMAGES) - 1)
gr['width'] = GRASSIMAGES[0].get_width()
gr['height'] = GRASSIMAGES[0].get_height()
gr['x'], gr['y'] = getRandomOffCameraPos(camerax, cameray, gr['width'], gr['height'])
gr['rect'] = pygame.Rect( (gr['x'], gr['y'], gr['width'], gr['height']) )
return gr
def isOutsideActiveArea(camerax, cameray, obj):
# Return False if camerax and cameray are more than
# a half-window length beyond the edge of the window.
boundsLeftEdge = camerax - WINWIDTH
boundsTopEdge = cameray - WINHEIGHT
boundsRect = pygame.Rect(boundsLeftEdge, boundsTopEdge, WINWIDTH * 3, WINHEIGHT * 3)
objRect = pygame.Rect(obj['x'], obj['y'], obj['width'], obj['height'])
return not boundsRect.colliderect(objRect)
if __name__ == '__main__':
main()

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
python_games/star_title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

598
python_games/starpusher.py Normal file
View File

@ -0,0 +1,598 @@
# Star Pusher (a Sokoban clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
import random, sys, copy, os, pygame
from pygame.locals import *
FPS = 30 # frames per second to update the screen
WINWIDTH = 800 # width of the program's window, in pixels
WINHEIGHT = 600 # height in pixels
HALF_WINWIDTH = int(WINWIDTH / 2)
HALF_WINHEIGHT = int(WINHEIGHT / 2)
# The total width and height of each tile in pixels.
TILEWIDTH = 50
TILEHEIGHT = 85
TILEFLOORHEIGHT = 40
CAM_MOVE_SPEED = 5 # how many pixels per frame the camera moves
# The percentage of outdoor tiles that have additional
# decoration on them, such as a tree or rock.
OUTSIDE_DECORATION_PCT = 20
BRIGHTBLUE = ( 0, 170, 255)
WHITE = (255, 255, 255)
BGCOLOR = BRIGHTBLUE
TEXTCOLOR = WHITE
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
def main():
global FPSCLOCK, DISPLAYSURF, IMAGESDICT, TILEMAPPING, OUTSIDEDECOMAPPING, BASICFONT, PLAYERIMAGES, currentImage
# Pygame initialization and basic set up of the global variables.
pygame.init()
FPSCLOCK = pygame.time.Clock()
# Because the Surface object stored in DISPLAYSURF was returned
# from the pygame.display.set_mode() function, this is the
# Surface object that is drawn to the actual computer screen
# when pygame.display.update() is called.
DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))
pygame.display.set_caption('Star Pusher')
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
# A global dict value that will contain all the Pygame
# Surface objects returned by pygame.image.load().
IMAGESDICT = {'uncovered goal': pygame.image.load('RedSelector.png'),
'covered goal': pygame.image.load('Selector.png'),
'star': pygame.image.load('Star.png'),
'corner': pygame.image.load('Wall_Block_Tall.png'),
'wall': pygame.image.load('Wood_Block_Tall.png'),
'inside floor': pygame.image.load('Plain_Block.png'),
'outside floor': pygame.image.load('Grass_Block.png'),
'title': pygame.image.load('star_title.png'),
'solved': pygame.image.load('star_solved.png'),
'princess': pygame.image.load('princess.png'),
'boy': pygame.image.load('boy.png'),
'catgirl': pygame.image.load('catgirl.png'),
'horngirl': pygame.image.load('horngirl.png'),
'pinkgirl': pygame.image.load('pinkgirl.png'),
'rock': pygame.image.load('Rock.png'),
'short tree': pygame.image.load('Tree_Short.png'),
'tall tree': pygame.image.load('Tree_Tall.png'),
'ugly tree': pygame.image.load('Tree_Ugly.png')}
# These dict values are global, and map the character that appears
# in the level file to the Surface object it represents.
TILEMAPPING = {'x': IMAGESDICT['corner'],
'#': IMAGESDICT['wall'],
'o': IMAGESDICT['inside floor'],
' ': IMAGESDICT['outside floor']}
OUTSIDEDECOMAPPING = {'1': IMAGESDICT['rock'],
'2': IMAGESDICT['short tree'],
'3': IMAGESDICT['tall tree'],
'4': IMAGESDICT['ugly tree']}
# PLAYERIMAGES is a list of all possible characters the player can be.
# currentImage is the index of the player's current player image.
currentImage = 0
PLAYERIMAGES = [IMAGESDICT['princess'],
IMAGESDICT['boy'],
IMAGESDICT['catgirl'],
IMAGESDICT['horngirl'],
IMAGESDICT['pinkgirl']]
startScreen() # show the title screen until the user presses a key
# Read in the levels from the text file. See the readLevelsFile() for
# details on the format of this file and how to make your own levels.
levels = readLevelsFile('starPusherLevels.txt')
currentLevelIndex = 0
# The main game loop. This loop runs a single level, when the user
# finishes that level, the next/previous level is loaded.
while True: # main game loop
# Run the level to actually start playing the game:
result = runLevel(levels, currentLevelIndex)
if result in ('solved', 'next'):
# Go to the next level.
currentLevelIndex += 1
if currentLevelIndex >= len(levels):
# If there are no more levels, go back to the first one.
currentLevelIndex = 0
elif result == 'back':
# Go to the previous level.
currentLevelIndex -= 1
if currentLevelIndex < 0:
# If there are no previous levels, go to the last one.
currentLevelIndex = len(levels)-1
elif result == 'reset':
pass # Do nothing. Loop re-calls runLevel() to reset the level
def runLevel(levels, levelNum):
global currentImage
levelObj = levels[levelNum]
mapObj = decorateMap(levelObj['mapObj'], levelObj['startState']['player'])
gameStateObj = copy.deepcopy(levelObj['startState'])
mapNeedsRedraw = True # set to True to call drawMap()
levelSurf = BASICFONT.render('Level %s of %s' % (levelNum + 1, len(levels)), 1, TEXTCOLOR)
levelRect = levelSurf.get_rect()
levelRect.bottomleft = (20, WINHEIGHT - 35)
mapWidth = len(mapObj) * TILEWIDTH
mapHeight = (len(mapObj[0]) - 1) * TILEFLOORHEIGHT + TILEHEIGHT
MAX_CAM_X_PAN = abs(HALF_WINHEIGHT - int(mapHeight / 2)) + TILEWIDTH
MAX_CAM_Y_PAN = abs(HALF_WINWIDTH - int(mapWidth / 2)) + TILEHEIGHT
levelIsComplete = False
# Track how much the camera has moved:
cameraOffsetX = 0
cameraOffsetY = 0
# Track if the keys to move the camera are being held down:
cameraUp = False
cameraDown = False
cameraLeft = False
cameraRight = False
while True: # main game loop
# Reset these variables:
playerMoveTo = None
keyPressed = False
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
# Player clicked the "X" at the corner of the window.
terminate()
elif event.type == KEYDOWN:
# Handle key presses
keyPressed = True
if event.key == K_LEFT:
playerMoveTo = LEFT
elif event.key == K_RIGHT:
playerMoveTo = RIGHT
elif event.key == K_UP:
playerMoveTo = UP
elif event.key == K_DOWN:
playerMoveTo = DOWN
# Set the camera move mode.
elif event.key == K_a:
cameraLeft = True
elif event.key == K_d:
cameraRight = True
elif event.key == K_w:
cameraUp = True
elif event.key == K_s:
cameraDown = True
elif event.key == K_n:
return 'next'
elif event.key == K_b:
return 'back'
elif event.key == K_ESCAPE:
terminate() # Esc key quits.
elif event.key == K_BACKSPACE:
return 'reset' # Reset the level.
elif event.key == K_p:
# Change the player image to the next one.
currentImage += 1
if currentImage >= len(PLAYERIMAGES):
# After the last player image, use the first one.
currentImage = 0
mapNeedsRedraw = True
elif event.type == KEYUP:
# Unset the camera move mode.
if event.key == K_a:
cameraLeft = False
elif event.key == K_d:
cameraRight = False
elif event.key == K_w:
cameraUp = False
elif event.key == K_s:
cameraDown = False
if playerMoveTo != None and not levelIsComplete:
# If the player pushed a key to move, make the move
# (if possible) and push any stars that are pushable.
moved = makeMove(mapObj, gameStateObj, playerMoveTo)
if moved:
# increment the step counter.
gameStateObj['stepCounter'] += 1
mapNeedsRedraw = True
if isLevelFinished(levelObj, gameStateObj):
# level is solved, we should show the "Solved!" image.
levelIsComplete = True
keyPressed = False
DISPLAYSURF.fill(BGCOLOR)
if mapNeedsRedraw:
mapSurf = drawMap(mapObj, gameStateObj, levelObj['goals'])
mapNeedsRedraw = False
if cameraUp and cameraOffsetY < MAX_CAM_X_PAN:
cameraOffsetY += CAM_MOVE_SPEED
elif cameraDown and cameraOffsetY > -MAX_CAM_X_PAN:
cameraOffsetY -= CAM_MOVE_SPEED
if cameraLeft and cameraOffsetX < MAX_CAM_Y_PAN:
cameraOffsetX += CAM_MOVE_SPEED
elif cameraRight and cameraOffsetX > -MAX_CAM_Y_PAN:
cameraOffsetX -= CAM_MOVE_SPEED
# Adjust mapSurf's Rect object based on the camera offset.
mapSurfRect = mapSurf.get_rect()
mapSurfRect.center = (HALF_WINWIDTH + cameraOffsetX, HALF_WINHEIGHT + cameraOffsetY)
# Draw mapSurf to the DISPLAYSURF Surface object.
DISPLAYSURF.blit(mapSurf, mapSurfRect)
DISPLAYSURF.blit(levelSurf, levelRect)
stepSurf = BASICFONT.render('Steps: %s' % (gameStateObj['stepCounter']), 1, TEXTCOLOR)
stepRect = stepSurf.get_rect()
stepRect.bottomleft = (20, WINHEIGHT - 10)
DISPLAYSURF.blit(stepSurf, stepRect)
if levelIsComplete:
# is solved, show the "Solved!" image until the player
# has pressed a key.
solvedRect = IMAGESDICT['solved'].get_rect()
solvedRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
DISPLAYSURF.blit(IMAGESDICT['solved'], solvedRect)
if keyPressed:
return 'solved'
pygame.display.update() # draw DISPLAYSURF to the screen.
FPSCLOCK.tick()
def isWall(mapObj, x, y):
"""Returns True if the (x, y) position on
the map is a wall, otherwise return False."""
if x < 0 or x >= len(mapObj) or y < 0 or y >= len(mapObj[x]):
return False # x and y aren't actually on the map.
elif mapObj[x][y] in ('#', 'x'):
return True # wall is blocking
return False
def decorateMap(mapObj, startxy):
"""Makes a copy of the given map object and modifies it.
Here is what is done to it:
* Walls that are corners are turned into corner pieces.
* The outside/inside floor tile distinction is made.
* Tree/rock decorations are randomly added to the outside tiles.
Returns the decorated map object."""
startx, starty = startxy # Syntactic sugar
# Copy the map object so we don't modify the original passed
mapObjCopy = copy.deepcopy(mapObj)
# Remove the non-wall characters from the map data
for x in range(len(mapObjCopy)):
for y in range(len(mapObjCopy[0])):
if mapObjCopy[x][y] in ('$', '.', '@', '+', '*'):
mapObjCopy[x][y] = ' '
# Flood fill to determine inside/outside floor tiles.
floodFill(mapObjCopy, startx, starty, ' ', 'o')
# Convert the adjoined walls into corner tiles.
for x in range(len(mapObjCopy)):
for y in range(len(mapObjCopy[0])):
if mapObjCopy[x][y] == '#':
if (isWall(mapObjCopy, x, y-1) and isWall(mapObjCopy, x+1, y)) or \
(isWall(mapObjCopy, x+1, y) and isWall(mapObjCopy, x, y+1)) or \
(isWall(mapObjCopy, x, y+1) and isWall(mapObjCopy, x-1, y)) or \
(isWall(mapObjCopy, x-1, y) and isWall(mapObjCopy, x, y-1)):
mapObjCopy[x][y] = 'x'
elif mapObjCopy[x][y] == ' ' and random.randint(0, 99) < OUTSIDE_DECORATION_PCT:
mapObjCopy[x][y] = random.choice(list(OUTSIDEDECOMAPPING.keys()))
return mapObjCopy
def isBlocked(mapObj, gameStateObj, x, y):
"""Returns True if the (x, y) position on the map is
blocked by a wall or star, otherwise return False."""
if isWall(mapObj, x, y):
return True
elif x < 0 or x >= len(mapObj) or y < 0 or y >= len(mapObj[x]):
return True # x and y aren't actually on the map.
elif (x, y) in gameStateObj['stars']:
return True # a star is blocking
return False
def makeMove(mapObj, gameStateObj, playerMoveTo):
"""Given a map and game state object, see if it is possible for the
player to make the given move. If it is, then change the player's
position (and the position of any pushed star). If not, do nothing.
Returns True if the player moved, otherwise False."""
# Make sure the player can move in the direction they want.
playerx, playery = gameStateObj['player']
# This variable is "syntactic sugar". Typing "stars" is more
# readable than typing "gameStateObj['stars']" in our code.
stars = gameStateObj['stars']
# The code for handling each of the directions is so similar aside
# from adding or subtracting 1 to the x/y coordinates. We can
# simplify it by using the xOffset and yOffset variables.
if playerMoveTo == UP:
xOffset = 0
yOffset = -1
elif playerMoveTo == RIGHT:
xOffset = 1
yOffset = 0
elif playerMoveTo == DOWN:
xOffset = 0
yOffset = 1
elif playerMoveTo == LEFT:
xOffset = -1
yOffset = 0
# See if the player can move in that direction.
if isWall(mapObj, playerx + xOffset, playery + yOffset):
return False
else:
if (playerx + xOffset, playery + yOffset) in stars:
# There is a star in the way, see if the player can push it.
if not isBlocked(mapObj, gameStateObj, playerx + (xOffset*2), playery + (yOffset*2)):
# Move the star.
ind = stars.index((playerx + xOffset, playery + yOffset))
stars[ind] = (stars[ind][0] + xOffset, stars[ind][1] + yOffset)
else:
return False
# Move the player upwards.
gameStateObj['player'] = (playerx + xOffset, playery + yOffset)
return True
def startScreen():
"""Display the start screen (which has the title and instructions)
until the player presses a key. Returns None."""
# Position the title image.
titleRect = IMAGESDICT['title'].get_rect()
topCoord = 50 # topCoord tracks where to position the top of the text
titleRect.top = topCoord
titleRect.centerx = HALF_WINWIDTH
topCoord += titleRect.height
# Unfortunately, Pygame's font & text system only shows one line at
# a time, so we can't use strings with \n newline characters in them.
# So we will use a list with each line in it.
instructionText = ['Push the stars over the marks.',
'Arrow keys to move, WASD for camera control, P to change character.',
'Backspace to reset level, Esc to quit.',
'N for next level, B to go back a level.']
# Start with drawing a blank color to the entire window:
DISPLAYSURF.fill(BGCOLOR)
# Draw the title image to the window:
DISPLAYSURF.blit(IMAGESDICT['title'], titleRect)
# Position and draw the text.
for i in range(len(instructionText)):
instSurf = BASICFONT.render(instructionText[i], 1, TEXTCOLOR)
instRect = instSurf.get_rect()
topCoord += 10 # 10 pixels will go in between each line of text.
instRect.top = topCoord
instRect.centerx = HALF_WINWIDTH
topCoord += instRect.height # Adjust for the height of the line.
DISPLAYSURF.blit(instSurf, instRect)
while True: # Main loop for the start screen.
for event in pygame.event.get():
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return # user has pressed a key, so return.
# Display the DISPLAYSURF contents to the actual screen.
pygame.display.update()
FPSCLOCK.tick()
def readLevelsFile(filename):
assert os.path.exists(filename), 'Cannot find the level file: %s' % (filename)
mapFile = open(filename, 'r')
# Each level must end with a blank line
content = mapFile.readlines() + ['\r\n']
mapFile.close()
levels = [] # Will contain a list of level objects.
levelNum = 0
mapTextLines = [] # contains the lines for a single level's map.
mapObj = [] # the map object made from the data in mapTextLines
for lineNum in range(len(content)):
# Process each line that was in the level file.
line = content[lineNum].rstrip('\r\n')
if ';' in line:
# Ignore the ; lines, they're comments in the level file.
line = line[:line.find(';')]
if line != '':
# This line is part of the map.
mapTextLines.append(line)
elif line == '' and len(mapTextLines) > 0:
# A blank line indicates the end of a level's map in the file.
# Convert the text in mapTextLines into a level object.
# Find the longest row in the map.
maxWidth = -1
for i in range(len(mapTextLines)):
if len(mapTextLines[i]) > maxWidth:
maxWidth = len(mapTextLines[i])
# Add spaces to the ends of the shorter rows. This
# ensures the map will be rectangular.
for i in range(len(mapTextLines)):
mapTextLines[i] += ' ' * (maxWidth - len(mapTextLines[i]))
# Convert mapTextLines to a map object.
for x in range(len(mapTextLines[0])):
mapObj.append([])
for y in range(len(mapTextLines)):
for x in range(maxWidth):
mapObj[x].append(mapTextLines[y][x])
# Loop through the spaces in the map and find the @, ., and $
# characters for the starting game state.
startx = None # The x and y for the player's starting position
starty = None
goals = [] # list of (x, y) tuples for each goal.
stars = [] # list of (x, y) for each star's starting position.
for x in range(maxWidth):
for y in range(len(mapObj[x])):
if mapObj[x][y] in ('@', '+'):
# '@' is player, '+' is player & goal
startx = x
starty = y
if mapObj[x][y] in ('.', '+', '*'):
# '.' is goal, '*' is star & goal
goals.append((x, y))
if mapObj[x][y] in ('$', '*'):
# '$' is star
stars.append((x, y))
# Basic level design sanity checks:
assert startx != None and starty != None, 'Level %s (around line %s) in %s is missing a "@" or "+" to mark the start point.' % (levelNum+1, lineNum, filename)
assert len(goals) > 0, 'Level %s (around line %s) in %s must have at least one goal.' % (levelNum+1, lineNum, filename)
assert len(stars) >= len(goals), 'Level %s (around line %s) in %s is impossible to solve. It has %s goals but only %s stars.' % (levelNum+1, lineNum, filename, len(goals), len(stars))
# Create level object and starting game state object.
gameStateObj = {'player': (startx, starty),
'stepCounter': 0,
'stars': stars}
levelObj = {'width': maxWidth,
'height': len(mapObj),
'mapObj': mapObj,
'goals': goals,
'startState': gameStateObj}
levels.append(levelObj)
# Reset the variables for reading the next map.
mapTextLines = []
mapObj = []
gameStateObj = {}
levelNum += 1
return levels
def floodFill(mapObj, x, y, oldCharacter, newCharacter):
"""Changes any values matching oldCharacter on the map object to
newCharacter at the (x, y) position, and does the same for the
positions to the left, right, down, and up of (x, y), recursively."""
# In this game, the flood fill algorithm creates the inside/outside
# floor distinction. This is a "recursive" function.
# For more info on the Flood Fill algorithm, see:
# http://en.wikipedia.org/wiki/Flood_fill
if mapObj[x][y] == oldCharacter:
mapObj[x][y] = newCharacter
if x < len(mapObj) - 1 and mapObj[x+1][y] == oldCharacter:
floodFill(mapObj, x+1, y, oldCharacter, newCharacter) # call right
if x > 0 and mapObj[x-1][y] == oldCharacter:
floodFill(mapObj, x-1, y, oldCharacter, newCharacter) # call left
if y < len(mapObj[x]) - 1 and mapObj[x][y+1] == oldCharacter:
floodFill(mapObj, x, y+1, oldCharacter, newCharacter) # call down
if y > 0 and mapObj[x][y-1] == oldCharacter:
floodFill(mapObj, x, y-1, oldCharacter, newCharacter) # call up
def drawMap(mapObj, gameStateObj, goals):
"""Draws the map to a Surface object, including the player and
stars. This function does not call pygame.display.update(), nor
does it draw the "Level" and "Steps" text in the corner."""
# mapSurf will be the single Surface object that the tiles are drawn
# on, so that it is easy to position the entire map on the DISPLAYSURF
# Surface object. First, the width and height must be calculated.
mapSurfWidth = len(mapObj) * TILEWIDTH
mapSurfHeight = (len(mapObj[0]) - 1) * TILEFLOORHEIGHT + TILEHEIGHT
mapSurf = pygame.Surface((mapSurfWidth, mapSurfHeight))
mapSurf.fill(BGCOLOR) # start with a blank color on the surface.
# Draw the tile sprites onto this surface.
for x in range(len(mapObj)):
for y in range(len(mapObj[x])):
spaceRect = pygame.Rect((x * TILEWIDTH, y * TILEFLOORHEIGHT, TILEWIDTH, TILEHEIGHT))
if mapObj[x][y] in TILEMAPPING:
baseTile = TILEMAPPING[mapObj[x][y]]
elif mapObj[x][y] in OUTSIDEDECOMAPPING:
baseTile = TILEMAPPING[' ']
# First draw the base ground/wall tile.
mapSurf.blit(baseTile, spaceRect)
if mapObj[x][y] in OUTSIDEDECOMAPPING:
# Draw any tree/rock decorations that are on this tile.
mapSurf.blit(OUTSIDEDECOMAPPING[mapObj[x][y]], spaceRect)
elif (x, y) in gameStateObj['stars']:
if (x, y) in goals:
# A goal AND star are on this space, draw goal first.
mapSurf.blit(IMAGESDICT['covered goal'], spaceRect)
# Then draw the star sprite.
mapSurf.blit(IMAGESDICT['star'], spaceRect)
elif (x, y) in goals:
# Draw a goal without a star on it.
mapSurf.blit(IMAGESDICT['uncovered goal'], spaceRect)
# Last draw the player on the board.
if (x, y) == gameStateObj['player']:
# Note: The value "currentImage" refers
# to a key in "PLAYERIMAGES" which has the
# specific player image we want to show.
mapSurf.blit(PLAYERIMAGES[currentImage], spaceRect)
return mapSurf
def isLevelFinished(levelObj, gameStateObj):
"""Returns True if all the goals have stars in them."""
for goal in levelObj['goals']:
if goal not in gameStateObj['stars']:
# Found a space with a goal but no star on it.
return False
return True
def terminate():
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()

BIN
python_games/tetrisb.mid Normal file

Binary file not shown.

BIN
python_games/tetrisc.mid Normal file

Binary file not shown.

523
python_games/tetromino.py Normal file
View File

@ -0,0 +1,523 @@
# Tetromino (a Tetris clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
# KRT 17/06/2012 rewrite event detection to deal with mouse use
import random, time, pygame, sys
from pygame.locals import *
FPS = 25
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BOXSIZE = 20
BOARDWIDTH = 10
BOARDHEIGHT = 20
BLANK = '.'
MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
# R G B
WHITE = (255, 255, 255)
GRAY = (185, 185, 185)
BLACK = ( 0, 0, 0)
RED = (155, 0, 0)
LIGHTRED = (175, 20, 20)
GREEN = ( 0, 155, 0)
LIGHTGREEN = ( 20, 175, 20)
BLUE = ( 0, 0, 155)
LIGHTBLUE = ( 20, 20, 175)
YELLOW = (155, 155, 0)
LIGHTYELLOW = (175, 175, 20)
BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS = ( BLUE, GREEN, RED, YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color
TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5
S_SHAPE_TEMPLATE = [['.....',
'.....',
'..OO.',
'.OO..',
'.....'],
['.....',
'..O..',
'..OO.',
'...O.',
'.....']]
Z_SHAPE_TEMPLATE = [['.....',
'.....',
'.OO..',
'..OO.',
'.....'],
['.....',
'..O..',
'.OO..',
'.O...',
'.....']]
I_SHAPE_TEMPLATE = [['..O..',
'..O..',
'..O..',
'..O..',
'.....'],
['.....',
'.....',
'OOOO.',
'.....',
'.....']]
O_SHAPE_TEMPLATE = [['.....',
'.....',
'.OO..',
'.OO..',
'.....']]
J_SHAPE_TEMPLATE = [['.....',
'.O...',
'.OOO.',
'.....',
'.....'],
['.....',
'..OO.',
'..O..',
'..O..',
'.....'],
['.....',
'.....',
'.OOO.',
'...O.',
'.....'],
['.....',
'..O..',
'..O..',
'.OO..',
'.....']]
L_SHAPE_TEMPLATE = [['.....',
'...O.',
'.OOO.',
'.....',
'.....'],
['.....',
'..O..',
'..O..',
'..OO.',
'.....'],
['.....',
'.....',
'.OOO.',
'.O...',
'.....'],
['.....',
'.OO..',
'..O..',
'..O..',
'.....']]
T_SHAPE_TEMPLATE = [['.....',
'..O..',
'.OOO.',
'.....',
'.....'],
['.....',
'..O..',
'..OO.',
'..O..',
'.....'],
['.....',
'.....',
'.OOO.',
'..O..',
'.....'],
['.....',
'..O..',
'.OO..',
'..O..',
'.....']]
PIECES = {'S': S_SHAPE_TEMPLATE,
'Z': Z_SHAPE_TEMPLATE,
'J': J_SHAPE_TEMPLATE,
'L': L_SHAPE_TEMPLATE,
'I': I_SHAPE_TEMPLATE,
'O': O_SHAPE_TEMPLATE,
'T': T_SHAPE_TEMPLATE}
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
BIGFONT = pygame.font.Font('freesansbold.ttf', 100)
pygame.display.set_caption('Tetromino')
showTextScreen('Tetromino')
while True: # game loop
if random.randint(0, 1) == 0:
pygame.mixer.music.load('tetrisb.mid')
else:
pygame.mixer.music.load('tetrisc.mid')
pygame.mixer.music.play(-1, 0.0)
runGame()
pygame.mixer.music.stop()
showTextScreen('Game Over')
def runGame():
# setup variables for the start of the game
board = getBlankBoard()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
lastFallTime = time.time()
movingDown = False # note: there is no movingUp variable
movingLeft = False
movingRight = False
score = 0
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = getNewPiece()
nextPiece = getNewPiece()
while True: # game loop
if fallingPiece == None:
# No falling piece in play, so start a new piece at the top
fallingPiece = nextPiece
nextPiece = getNewPiece()
lastFallTime = time.time() # reset lastFallTime
if not isValidPosition(board, fallingPiece):
return # can't fit a new piece on the board, so game over
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == KEYUP:
if (event.key == K_p):
# Pausing the game
DISPLAYSURF.fill(BGCOLOR)
pygame.mixer.music.stop()
showTextScreen('Paused') # pause until a key press
pygame.mixer.music.play(-1, 0.0)
lastFallTime = time.time()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
elif (event.key == K_LEFT or event.key == K_a):
movingLeft = False
elif (event.key == K_RIGHT or event.key == K_d):
movingRight = False
elif (event.key == K_DOWN or event.key == K_s):
movingDown = False
elif event.type == KEYDOWN:
# moving the piece sideways
if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
movingLeft = True
movingRight = False
lastMoveSidewaysTime = time.time()
elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
movingRight = True
movingLeft = False
lastMoveSidewaysTime = time.time()
# rotating the piece (if there is room to rotate)
elif (event.key == K_UP or event.key == K_w):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
elif (event.key == K_q): # rotate the other direction
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
# making the piece fall faster with the down key
elif (event.key == K_DOWN or event.key == K_s):
movingDown = True
if isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# move the current piece all the way down
elif event.key == K_SPACE:
movingDown = False
movingLeft = False
movingRight = False
for i in range(1, BOARDHEIGHT):
if not isValidPosition(board, fallingPiece, adjY=i):
break
fallingPiece['y'] += i - 1
# handle moving the piece because of user input
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
lastMoveSidewaysTime = time.time()
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# let the piece fall if it is time to fall
if time.time() - lastFallTime > fallFreq:
# see if the piece has landed
if not isValidPosition(board, fallingPiece, adjY=1):
# falling piece has landed, set it on the board
addToBoard(board, fallingPiece)
score += removeCompleteLines(board)
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = None
else:
# piece did not land, just move the piece down
fallingPiece['y'] += 1
lastFallTime = time.time()
# drawing everything on the screen
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
drawStatus(score, level)
drawNextPiece(nextPiece)
if fallingPiece != None:
drawPiece(fallingPiece)
pygame.display.update()
FPSCLOCK.tick(FPS)
def makeTextObjs(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
def terminate():
pygame.quit()
sys.exit()
# KRT 17/06/2012 rewrite event detection to deal with mouse use
def checkForKeyPress():
for event in pygame.event.get():
if event.type == QUIT: #event is quit
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: #event is escape key
terminate()
else:
return event.key #key found return with it
# no quit or key events in queue so return None
return None
##def checkForKeyPress():
## # Go through event queue looking for a KEYUP event.
## # Grab KEYDOWN events to remove them from the event queue.
## checkForQuit()
##
## for event in pygame.event.get([KEYDOWN, KEYUP]):
## if event.type == KEYDOWN:
## continue
## return event.key
## return None
def showTextScreen(text):
# This function displays large text in the
# center of the screen until a key is pressed.
# Draw the text drop shadow
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the text
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the additional "Press a key to play." text.
pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while checkForKeyPress() == None:
pygame.display.update()
FPSCLOCK.tick()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def calculateLevelAndFallFreq(score):
# Based on the score, return the level the player is on and
# how many seconds pass until a falling piece falls one space.
level = int(score / 10) + 1
fallFreq = 0.27 - (level * 0.02)
return level, fallFreq
def getNewPiece():
# return a random new piece in a random rotation and color
shape = random.choice(list(PIECES.keys()))
newPiece = {'shape': shape,
'rotation': random.randint(0, len(PIECES[shape]) - 1),
'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),
'y': -2, # start it above the board (i.e. less than 0)
'color': random.randint(0, len(COLORS)-1)}
return newPiece
def addToBoard(board, piece):
# fill in the board based on piece's location, shape, and rotation
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
board[x + piece['x']][y + piece['y']] = piece['color']
def getBlankBoard():
# create and return a new blank board data structure
board = []
for i in range(BOARDWIDTH):
board.append([BLANK] * BOARDHEIGHT)
return board
def isOnBoard(x, y):
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT
def isValidPosition(board, piece, adjX=0, adjY=0):
# Return True if the piece is within the board and not colliding
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
return False
return True
def isCompleteLine(board, y):
# Return True if the line filled with boxes with no gaps.
for x in range(BOARDWIDTH):
if board[x][y] == BLANK:
return False
return True
def removeCompleteLines(board):
# Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
numLinesRemoved = 0
y = BOARDHEIGHT - 1 # start y at the bottom of the board
while y >= 0:
if isCompleteLine(board, y):
# Remove the line and pull boxes down by one line.
for pullDownY in range(y, 0, -1):
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]
# Set very top line to blank.
for x in range(BOARDWIDTH):
board[x][0] = BLANK
numLinesRemoved += 1
# Note on the next iteration of the loop, y is the same.
# This is so that if the line that was pulled down is also
# complete, it will be removed.
else:
y -= 1 # move on to check next row up
return numLinesRemoved
def convertToPixelCoords(boxx, boxy):
# Convert the given xy coordinates of the board to xy
# coordinates of the location on the screen.
return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
# draw a single box (each tetromino piece has four boxes)
# at xy coordinates on the board. Or, if pixelx & pixely
# are specified, draw to the pixel coordinates stored in
# pixelx & pixely (this is used for the "Next" piece).
if color == BLANK:
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))
def drawBoard(board):
# draw the border around the board
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)
# fill the background of the board
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
# draw the individual boxes on the board
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
drawBox(x, y, board[x][y])
def drawStatus(score, level):
# draw the score text
scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 150, 20)
DISPLAYSURF.blit(scoreSurf, scoreRect)
# draw the level text
levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
levelRect = levelSurf.get_rect()
levelRect.topleft = (WINDOWWIDTH - 150, 50)
DISPLAYSURF.blit(levelSurf, levelRect)
def drawPiece(piece, pixelx=None, pixely=None):
shapeToDraw = PIECES[piece['shape']][piece['rotation']]
if pixelx == None and pixely == None:
# if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])
# draw each of the boxes that make up the piece
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != BLANK:
drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))
def drawNextPiece(piece):
# draw the "next" text
nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
nextRect = nextSurf.get_rect()
nextRect.topleft = (WINDOWWIDTH - 120, 80)
DISPLAYSURF.blit(nextSurf, nextRect)
# draw the "next" piece
drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,420 @@
# Tetromino for Idiots
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
# KRT 17/06/2012 rewrite event detection to deal with mouse use
import random, time, pygame, sys
from pygame.locals import *
FPS = 25
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BOXSIZE = 20
BOARDWIDTH = 10
BOARDHEIGHT = 20
BLANK = '.'
MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
# R G B
WHITE = (255, 255, 255)
GRAY = (185, 185, 185)
BLACK = ( 0, 0, 0)
RED = (155, 0, 0)
LIGHTRED = (175, 20, 20)
GREEN = ( 0, 155, 0)
LIGHTGREEN = ( 20, 175, 20)
BLUE = ( 0, 0, 155)
LIGHTBLUE = ( 20, 20, 175)
YELLOW = (155, 155, 0)
LIGHTYELLOW = (175, 175, 20)
BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS = ( BLUE, GREEN, RED, YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color
TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5
SHAPE_TEMPLATE = [['.....',
'.....',
'..O..',
'.....',
'.....']]
PIECES = {'A': SHAPE_TEMPLATE}
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
BIGFONT = pygame.font.Font('freesansbold.ttf', 60)
pygame.display.set_caption('Tetromino for Idiots')
showTextScreen('Tetromino for Idiots')
while True: # game loop
if random.randint(0, 1) == 0:
pygame.mixer.music.load('tetrisb.mid')
else:
pygame.mixer.music.load('tetrisc.mid')
pygame.mixer.music.play(-1, 0.0)
runGame()
pygame.mixer.music.stop()
showTextScreen('Game Over')
def runGame():
# setup variables for the start of the game
board = getBlankBoard()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
lastFallTime = time.time()
movingDown = False # note: there is no movingUp variable
movingLeft = False
movingRight = False
score = 0
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = getNewPiece()
nextPiece = getNewPiece()
while True: # game loop
if fallingPiece == None:
# No falling piece in play, so start a new piece at the top
fallingPiece = nextPiece
nextPiece = getNewPiece()
lastFallTime = time.time() # reset lastFallTime
if not isValidPosition(board, fallingPiece):
return # can't fit a new piece on the board, so game over
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == KEYUP:
if (event.key == K_p):
# Pausing the game
DISPLAYSURF.fill(BGCOLOR)
pygame.mixer.music.stop()
showTextScreen('Paused') # pause until a key press
pygame.mixer.music.play(-1, 0.0)
lastFallTime = time.time()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
elif (event.key == K_LEFT or event.key == K_a):
movingLeft = False
elif (event.key == K_RIGHT or event.key == K_d):
movingRight = False
elif (event.key == K_DOWN or event.key == K_s):
movingDown = False
elif event.type == KEYDOWN:
# moving the piece sideways
if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
movingLeft = True
movingRight = False
lastMoveSidewaysTime = time.time()
elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
movingRight = True
movingLeft = False
lastMoveSidewaysTime = time.time()
# rotating the piece (if there is room to rotate)
elif (event.key == K_UP or event.key == K_w):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
elif (event.key == K_q): # rotate the other direction
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
# making the piece fall faster with the down key
elif (event.key == K_DOWN or event.key == K_s):
movingDown = True
if isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# move the current piece all the way down
elif event.key == K_SPACE:
movingDown = False
movingLeft = False
movingRight = False
for i in range(1, BOARDHEIGHT):
if not isValidPosition(board, fallingPiece, adjY=i):
break
fallingPiece['y'] += i - 1
# handle moving the piece because of user input
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
lastMoveSidewaysTime = time.time()
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# let the piece fall if it is time to fall
if time.time() - lastFallTime > fallFreq:
# see if the piece has landed
if not isValidPosition(board, fallingPiece, adjY=1):
# falling piece has landed, set it on the board
addToBoard(board, fallingPiece)
score += removeCompleteLines(board)
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = None
else:
# piece did not land, just move the piece down
fallingPiece['y'] += 1
lastFallTime = time.time()
# drawing everything on the screen
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
drawStatus(score, level)
drawNextPiece(nextPiece)
if fallingPiece != None:
drawPiece(fallingPiece)
pygame.display.update()
FPSCLOCK.tick(FPS)
def makeTextObjs(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
def terminate():
pygame.quit()
sys.exit()
# KRT 17/06/2012 rewrite event detection to deal with mouse use
def checkForKeyPress():
for event in pygame.event.get():
if event.type == QUIT: #event is quit
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: #event is escape key
terminate()
else:
return event.key #key found return with it
# no quit or key events in queue so return None
return None
##def checkForKeyPress():
## # Go through event queue looking for a KEYUP event.
## # Grab KEYDOWN events to remove them from the event queue.
## checkForQuit()
##
## for event in pygame.event.get([KEYDOWN, KEYUP]):
## if event.type == KEYDOWN:
## continue
## return event.key
## return None
def showTextScreen(text):
# This function displays large text in the
# center of the screen until a key is pressed.
# Draw the text drop shadow
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the text
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 2, int(WINDOWHEIGHT / 2) - 2)
DISPLAYSURF.blit(titleSurf, titleRect)
# Draw the additional "Press a key to play." text.
pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while checkForKeyPress() == None:
pygame.display.update()
FPSCLOCK.tick()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def calculateLevelAndFallFreq(score):
# Based on the score, return the level the player is on and
# how many seconds pass until a falling piece falls one space.
level = int(score / 10) + 1
fallFreq = 0.27 - (level * 0.02)
return level, fallFreq
def getNewPiece():
# return a random new piece in a random rotation and color
shape = random.choice(list(PIECES.keys()))
newPiece = {'shape': shape,
'rotation': random.randint(0, len(PIECES[shape]) - 1),
'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),
'y': -2, # start it above the board (i.e. less than 0)
'color': random.randint(0, len(COLORS)-1)}
return newPiece
def addToBoard(board, piece):
# fill in the board based on piece's location, shape, and rotation
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
board[x + piece['x']][y + piece['y']] = piece['color']
def getBlankBoard():
# create and return a new blank board data structure
board = []
for i in range(BOARDWIDTH):
board.append([BLANK] * BOARDHEIGHT)
return board
def isOnBoard(x, y):
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT
def isValidPosition(board, piece, adjX=0, adjY=0):
# Return True if the piece is within the board and not colliding
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
return False
return True
def isCompleteLine(board, y):
# Return True if the line filled with boxes with no gaps.
for x in range(BOARDWIDTH):
if board[x][y] == BLANK:
return False
return True
def removeCompleteLines(board):
# Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
numLinesRemoved = 0
y = BOARDHEIGHT - 1 # start y at the bottom of the board
while y >= 0:
if isCompleteLine(board, y):
# Remove the line and pull boxes down by one line.
for pullDownY in range(y, 0, -1):
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]
# Set very top line to blank.
for x in range(BOARDWIDTH):
board[x][0] = BLANK
numLinesRemoved += 1
# Note on the next iteration of the loop, y is the same.
# This is so that if the line that was pulled down is also
# complete, it will be removed.
else:
y -= 1 # move on to check next row up
return numLinesRemoved
def convertToPixelCoords(boxx, boxy):
# Convert the given xy coordinates of the board to xy
# coordinates of the location on the screen.
return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
# draw a single box (each tetromino piece has four boxes)
# at xy coordinates on the board. Or, if pixelx & pixely
# are specified, draw to the pixel coordinates stored in
# pixelx & pixely (this is used for the "Next" piece).
if color == BLANK:
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))
def drawBoard(board):
# draw the border around the board
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)
# fill the background of the board
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
# draw the individual boxes on the board
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
drawBox(x, y, board[x][y])
def drawStatus(score, level):
# draw the score text
scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 150, 20)
DISPLAYSURF.blit(scoreSurf, scoreRect)
# draw the level text
levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
levelRect = levelSurf.get_rect()
levelRect.topleft = (WINDOWWIDTH - 150, 50)
DISPLAYSURF.blit(levelSurf, levelRect)
def drawPiece(piece, pixelx=None, pixely=None):
shapeToDraw = PIECES[piece['shape']][piece['rotation']]
if pixelx == None and pixely == None:
# if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])
# draw each of the boxes that make up the piece
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != BLANK:
drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))
def drawNextPiece(piece):
# draw the "next" text
nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
nextRect = nextSurf.get_rect()
nextRect.topleft = (WINDOWWIDTH - 120, 80)
DISPLAYSURF.blit(nextSurf, nextRect)
# draw the "next" piece
drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)
if __name__ == '__main__':
main()

229
python_games/wormy.py Normal file
View File

@ -0,0 +1,229 @@
# Wormy (a Nibbles clone)
# By Al Sweigart al@inventwithpython.com
# http://inventwithpython.com/pygame
# Released under a "Simplified BSD" license
#KRT 14/06/2012 modified Start Screen and Game Over screen to cope with mouse events
#KRT 14/06/2012 Added a non-busy wait to Game Over screen to reduce processor loading from near 100%
import random, pygame, sys
from pygame.locals import *
FPS = 15
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
CELLSIZE = 20
assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
# R G B
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
DARKGREEN = ( 0, 155, 0)
DARKGRAY = ( 40, 40, 40)
BGCOLOR = BLACK
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
HEAD = 0 # syntactic sugar: index of the worm's head
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
pygame.display.set_caption('Wormy')
showStartScreen()
while True:
runGame()
showGameOverScreen()
def runGame():
# Set a random start point.
startx = random.randint(5, CELLWIDTH - 6)
starty = random.randint(5, CELLHEIGHT - 6)
wormCoords = [{'x': startx, 'y': starty},
{'x': startx - 1, 'y': starty},
{'x': startx - 2, 'y': starty}]
direction = RIGHT
# Start the apple in a random place.
apple = getRandomLocation()
while True: # main game loop
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
direction = LEFT
elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
direction = RIGHT
elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
direction = UP
elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
direction = DOWN
elif event.key == K_ESCAPE:
terminate()
# check if the worm has hit itself or the edge
if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
return # game over
for wormBody in wormCoords[1:]:
if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
return # game over
# check if worm has eaten an apply
if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
# don't remove worm's tail segment
apple = getRandomLocation() # set a new apple somewhere
else:
del wormCoords[-1] # remove worm's tail segment
# move the worm by adding a segment in the direction it is moving
if direction == UP:
newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
elif direction == DOWN:
newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
elif direction == LEFT:
newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
elif direction == RIGHT:
newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
wormCoords.insert(0, newHead)
DISPLAYSURF.fill(BGCOLOR)
drawGrid()
drawWorm(wormCoords)
drawApple(apple)
drawScore(len(wormCoords) - 3)
pygame.display.update()
FPSCLOCK.tick(FPS)
def drawPressKeyMsg():
pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
pressKeyRect = pressKeySurf.get_rect()
pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
# KRT 14/06/2012 rewrite event detection to deal with mouse use
def checkForKeyPress():
for event in pygame.event.get():
if event.type == QUIT: #event is quit
terminate()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE: #event is escape key
terminate()
else:
return event.key #key found return with it
# no quit or key events in queue so return None
return None
def showStartScreen():
titleFont = pygame.font.Font('freesansbold.ttf', 100)
titleSurf1 = titleFont.render('Wormy!', True, WHITE, DARKGREEN)
titleSurf2 = titleFont.render('Wormy!', True, GREEN)
degrees1 = 0
degrees2 = 0
#KRT 14/06/2012 rewrite event detection to deal with mouse use
pygame.event.get() #clear out event queue
while True:
DISPLAYSURF.fill(BGCOLOR)
rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
rotatedRect1 = rotatedSurf1.get_rect()
rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
rotatedRect2 = rotatedSurf2.get_rect()
rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
drawPressKeyMsg()
#KRT 14/06/2012 rewrite event detection to deal with mouse use
if checkForKeyPress():
return
pygame.display.update()
FPSCLOCK.tick(FPS)
degrees1 += 3 # rotate by 3 degrees each frame
degrees2 += 7 # rotate by 7 degrees each frame
def terminate():
pygame.quit()
sys.exit()
def getRandomLocation():
return {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
def showGameOverScreen():
gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
gameSurf = gameOverFont.render('Game', True, WHITE)
overSurf = gameOverFont.render('Over', True, WHITE)
gameRect = gameSurf.get_rect()
overRect = overSurf.get_rect()
gameRect.midtop = (WINDOWWIDTH / 2, 10)
overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
DISPLAYSURF.blit(gameSurf, gameRect)
DISPLAYSURF.blit(overSurf, overRect)
drawPressKeyMsg()
pygame.display.update()
pygame.time.wait(500)
#KRT 14/06/2012 rewrite event detection to deal with mouse use
pygame.event.get() #clear out event queue
while True:
if checkForKeyPress():
return
#KRT 12/06/2012 reduce processor loading in gameover screen.
pygame.time.wait(100)
def drawScore(score):
scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WINDOWWIDTH - 120, 10)
DISPLAYSURF.blit(scoreSurf, scoreRect)
def drawWorm(wormCoords):
for coord in wormCoords:
x = coord['x'] * CELLSIZE
y = coord['y'] * CELLSIZE
wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect)
wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)
def drawApple(coord):
x = coord['x'] * CELLSIZE
y = coord['y'] * CELLSIZE
appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
pygame.draw.rect(DISPLAYSURF, RED, appleRect)
def drawGrid():
for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
if __name__ == '__main__':
main()