blog

파이썬과 파이게임으로 게임을 만들어 보세요:

이 장에는 4개의 추가 게임에 대한 소스 코드가 포함되어 있습니다. 아쉽게도 이 장에는 소스코드만 포함되어 있으며 코드에 대한 자세한 설명은 포함되어 있지 않습니다. 지금까지는 소...

Oct 24, 2025 · 102 min. read
シェア

장: 네 가지 추가 게임

프로토콜:CC BY-NC-SA 4.0

이 장에는 4개의 추가 게임에 대한 소스 코드가 포함되어 있습니다. 아쉽게도 이 장에는 소스 코드만 포함되어 있으며 코드에 대한 자세한 설명은 없습니다. 지금까지는 소스 코드와 주석을 보고 이 게임들을 플레이하고 코드가 어떻게 작동하는지 파악할 수 있습니다.

이러한 게임에는 다음이 포함됩니다:

  • 플리피 - 플레이어가 컴퓨터 AI 플레이어의 큐브를 뒤집는 '오델로' 클론 게임입니다.

  • 잉크 유출 - 플러드 채우기 알고리즘을 사용하는 '플러드 잇' 복제본입니다.

  • 연속 4연승 - 컴퓨터 AI 플레이어와 대결하는 '커넥트 포' 클론 게임입니다.

  • 보석 - 플레이어가 보석을 교환하여 같은 보석 세 개를 연속으로 획득하는 "보석" 클론입니다.

이 책의 소스 코드에 대해 궁금한 점이 있으면 언제든지 저자에게 이메일 ([email protected] 으로 문의하시기 바랍니다.

버그 수정을 연습하고 싶다면 이러한 프로그램의 버기 버전도 사용할 수 있습니다:

Flippy,"오델로”복제

리버스시라고도 하는 오델로는 한 면은 검은색, 다른 면은 흰색으로 된 8x8 보드입니다. 시작 보드는 그림 10-1에 나와 있습니다. 각 플레이어는 번갈아 가며 자신의 색깔의 새 사각형을 놓습니다. 새 사각형과 같은 색의 다른 사각형 사이에 있는 상대방의 사각형은 뒤집습니다. 게임의 목표는 가능한 한 많은 같은 색의 사각형을 갖는 것입니다. 예를 들어, 그림 10-2는 흰색이 5, 6에 새 흰색 사각형을 놓으면 어떻게 되는지 보여줍니다.

5, 5의 검은색 사각형은 새로운 흰색 사각형과 기존 흰색 사각형 5, 4 사이에 있습니다. 이 검은색 사각형이 뒤집혀서 새로운 흰색 사각형이 되면 보드는 그림 10-3과 같이 됩니다. 이 검은색 사각형이 뒤집혀 새로운 흰색 사각형이 되어 그림 10-3과 같은 보드가 됩니다. 그런 다음 검은색은 비슷한 방법으로 4, 6에 검은색 사각형을 배치하고 5, 4에 흰색 사각형을 뒤집습니다. 이렇게 하면 그림 10-4와 같은 보드가 만들어집니다.

사각형은 플레이어의 새 사각형과 기존 사각형 사이에 있는 한 모든 방향으로 뒤집습니다. 그림 10-5에서 백인은 3, 6에 정사각형을 배치하고 검은색 정사각형을 양방향으로 뒤집습니다. 결과는 그림 10-6에 나와 있습니다.

보시다시피, 각 플레이어는 한두 번의 이동으로 보드의 대부분의 사각형을 빠르게 차지할 수 있습니다. 플레이어는 항상 한 칸 이상을 점유하는 이동을 해야 합니다. 플레이어가 움직일 수 없거나 보드가 완전히 가득 차면 게임이 종료됩니다. 자신의 색깔의 사각형을 가장 많이 차지한 플레이어가 승리합니다.

리버시에 대한 자세한 내용은 invpy.com/buggy/gemgem 확인할 수 있습니다.

파이게임 대신 인쇄() 및 입력()을 사용하는 이 게임의 텍스트 버전은 15장, '파이썬으로 나만의 컴퓨터 게임 발명하기'에 나와 있습니다. 해당 챕터에서 컴퓨터 AI 알고리즘이 어떻게 구성되는지 배울 수 있습니다. en.wikipedia.org/wiki/Reversi

컴퓨터가 가능한 모든 움직임을 쉽게 시뮬레이션하고 가장 많은 타일을 뒤집는 움직임을 선택하기 때문에 이 게임의 컴퓨터 AI는 훌륭합니다. 제가 플레이할 때마다 항상 저를 이깁니다.

Flippy 소스 코드

이 소스 코드는 inventwithpython.com/chapter15.html 다운로드할 수 있습니다.

Flippy에서 사용하는 이미지 파일은 invpy.com/flippyimages.zip 다운로드할 수 있습니다.

 # Flippy (an Othello or Reversi clone)
 # By Al Sweigart [[email protected]](/cdn-cgi/l/email-protection)
 # http://.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://.com/.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()

잉크 유출, "플러드 잇" 복제본.

"플러드 잇" 게임은 색 타일로 가득 찬 보드에서 시작됩니다. 각 라운드에서 플레이어는 새로운 색을 선택하여 왼쪽 상단 모서리에 있는 타일과 같은 색의 인접한 타일을 칠합니다. 이 게임은 플러드 채우기 알고리즘을 사용합니다. 게임의 목표는 모든 라운드가 사용된 후 보드 전체를 하나의 색상으로 바꾸는 것입니다.

이 게임에는 플레이어가 보드의 크기와 게임의 난이도를 변경할 수 있는 설정 화면도 있습니다. 플레이어가 색상에 지루함을 느낀다면 다른 색 구성표로 전환할 수도 있습니다.

잉크 유출 소스 코드

이 소스 코드는 invpy.com/inkspill.py 다운로드할 수 있습니다.

Flippy에서 사용하는 이미지 파일은 invpy.com/inkspillimages.zip 다운로드할 수 있습니다.

 # Ink Spill (a Flood It clone)
 # http://.com/pygame
 # By Al Sweigart [[email protected]](/cdn-cgi/l/email-protection)
 # 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)
         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 
             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://.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()

네쌍둥이. "네쌍둥이" 복제본입니다.

"테트리스" 게임에는 7x6 보드가 있으며 플레이어는 보드 상단에서 교대로 마커를 놓습니다. 마커는 각 열의 상단에서 떨어지며 해당 열의 하단 또는 상단 마커에 놓이게 됩니다. 네 개의 마커가 가로, 세로 또는 대각선으로 정렬되면 플레이어가 승리합니다.

이 게임의 AI는 훌륭합니다. 컴퓨터는 가능한 모든 수를 모델링한 다음, 각 수에 대한 인간 플레이어의 반응을 모델링하고, 가능한 모든 수를 모델링한 다음, 각 수에 대한 인간 플레이어의 반응을 모델링했습니다! 이 모든 생각 끝에 컴퓨터는 승리할 가능성이 가장 높은 수를 결정합니다.

그래서 컴퓨터는 이기기 어렵습니다. 저는 보통 컴퓨터에게 집니다.

자신의 차례에 7개의 가능한 수를 둘 수 있고 상대방은 7개의 가능한 수를 둘 수 있으며, 7개의 가능한 수를 둘 수 있는 상대방은 7개의 가능한 수를 둘 수 있으므로 각 턴에서 컴퓨터는 7 x 7 x 7 x 7 = 2,401개의 가능한 수를 고려한다는 의미입니다. 난이도 상수를 더 큰 숫자로 설정하면 컴퓨터가 게임을 더 고려하도록 할 수 있지만, 그보다 큰 값으로 설정하면 컴퓨터가 자신의 차례를 계산하는 데 시간이 오래 걸립니다.

난이도를 '보통'으로 설정하여 컴퓨터의 난이도를 낮출 수도 있습니다. 그러면 컴퓨터는 각 단계와 해당 단계에 대한 플레이어의 가능한 반응만 고려합니다. 난이도를 0으로 설정하면 컴퓨터는 모든 지능을 잃고 무작위로만 움직입니다.

네 아들의 진주 소스 코드

이 소스 코드는 invpy.com/fourinarow.py 다운로드할 수 있습니다.

Flippy에서 사용하는 이미지 파일은 invpy.com/fourinarowimages.zip 다운로드할 수 있습니다.

 # Four-In-A-Row (a Connect Four clone)
 # By Al Sweigart [[email protected]](/cdn-cgi/l/email-protection)
 # http://.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 slow)
 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()

"보석으로 장식된" 클론, 젬젬.

"보석은 보석을 떨어뜨려 보드를 채우는 게임입니다. 플레이어는 인접한 두 개의 보석을 교환하여 세 개의 보석을 연속으로 맞추려고 시도할 수 있습니다. 일치하는 보석은 사라지고 위에서부터 새로운 보석이 떨어집니다. 세 개 이상의 보석을 맞추거나 보석이 연쇄 반응을 일으키면 더 많은 점수를 획득할 수 있습니다. 플레이어의 점수는 시간이 지남에 따라 서서히 감소하므로 플레이어는 계속해서 새로운 보석을 맞춰야 합니다. 보드에 더 이상 보석을 매치할 수 없게 되면 게임이 종료됩니다.

Gemgem 소스 코드

이 소스 코드는 invpy.com/fourinarowimages.zip 다운로드할 수 있습니다.

Flippy에서 사용하는 이미지 파일은 # Four-In-A-Row (a Connect Four clone) # By Al Sweigart [[email protected]](/cdn-cgi/l/email-protection) # http://.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 slow) 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() 다운로드할 수 있습니다.

 # Gemgem (a Bejeweled clone)
 # By Al Sweigart [[email protected]](/cdn-cgi/l/email-protection)
 # http://.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.
     # initialize 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 player gets 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, in case 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 if 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()

요약

이 게임 프로그램을 통해 어떤 게임을 만들고 싶은지, 어떻게 작성할지 자신만의 아이디어를 얻으셨기를 바랍니다. 자신만의 아이디어가 없더라도 자신이 플레이한 다른 게임의 복제품을 만들어 보는 것도 좋은 연습이 될 것입니다.

다음은 파이썬 프로그래밍에 대해 자세히 알아볼 수 있는 웹사이트입니다:

  • - 공식 파이게임 웹사이트에는 파이게임 라이브러리를 활용하는 수백 개의 게임에 대한 소스 코드가 있습니다. 다른 사람의 소스 코드를 다운로드하여 읽으면 많은 것을 배울 수 있습니다.

  • python.org/doc/ - 모든 Python 모듈 및 함수에 대한 더 많은 Python 튜토리얼과 문서.

  • pygame.org/docs/ - Pygame 모듈 및 기능에 대한 전체 문서

  • 프로그래밍 학습을 위한 리소스를 찾는 데 도움을 줄 수 있는 많은 사용자가 있습니다.

  • _ - 이 책의 웹사이트로, 이 프로그램의 모든 소스 코드와 추가 정보가 포함되어 있습니다. 이 사이트에는 파이게임 프로그램에 사용된 이미지와 사운드 파일도 포함되어 있습니다.

  • _ - 기본 Python 프로그래밍을 다루는 "Invent 나만의 컴퓨터 게임 만들기" 책 웹사이트.

  • invpy.com/wiki - 특정 내용을 알아야 할 경우 참조할 수 있는 개별 Python 프로그래밍 개념을 다루는 위키입니다.

  • invpy.com/traces - 이 책의 프로그램 실행을 단계별로 따라할 수 있도록 도와주는 웹 애플리케이션입니다.

  • invpy.com/videos - 이 책에 수록된 절차에 대한 동영상입니다.

  • gamedevlessons.com - 비디오 게임을 디자인하고 프로그래밍하는 방법에 대한 유용한 사이트입니다.

또는 월드 와이드 웹을 검색하여 Python에 대해 자세히 알아볼 수 있습니다. 검색 사이트 google.com으로 이동하여 "Python 프로그래밍" 또는 "Python 튜토리얼"을 검색하면 Python 프로그래밍에 관한 더 많은 사이트를 찾을 수 있습니다.

이제 나만의 게임을 만들어 보세요. 행운을 빕니다!

Read next

centos7에서 yum을 사용하여 컨테이너를 설치합니다.

방화벽, SELinux를 종료하고 스왑합니다. 미러 소스를 설치, 구성 및 수정합니다.

Oct 24, 2025 · 2 min read