import random, pygame, sysfrom pygame.locals import *FPS = 30 # frames per second, the general speed of the programWINDOWWIDTH = 340 # size of window's width in pixelsWINDOWHEIGHT = 340 # size of windows' height in pixelsBOXSIZE = 100 # size of box height & width in pixelsGAPSIZE = 10 # size of gap between boxes in pixelsBOARDWIDTH = 3 # number of columns of iconsBOARDHEIGHT = 3 # number of rows of icons# ColorsetBLACK = (0, 0, 0)WHITE = (255, 255, 255)GRAY = (100, 100, 100)LIGHTBLUE = (153, 204, 255)BGCOLOR = WHITEBOXCOLOR = BLACKHIGHLIGHTCOLOR = GRAYLINECOLOR = WHITEdef main():global FPSCLOCK, DISPLAYSURFpygame.init()FPSCLOCK = pygame.time.Clock()DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))mousex = 0 # used to store x coordinate of mouse eventmousey = 0 # used to store y coordinate of mouse eventpygame.display.set_caption('TicTacToe - harang97')mainBoard = [[None,None,None],[None,None,None],[None,None,None]]playerTurn = 'X'firstSelection = None # stores the (x, y) of the first box clicked.DISPLAYSURF.fill(BGCOLOR)drawBoard(mainBoard)Message = 'None'while True: # main game loopmouseClicked = FalseDISPLAYSURF.fill(BGCOLOR)drawBoard(mainBoard)for event in pygame.event.get():if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):pygame.quit()sys.exit()elif event.type == MOUSEMOTION:mousex, mousey = event.poselif event.type == MOUSEBUTTONUP:mousex, mousey = event.posmouseClicked = Trueboxx, boxy = getBoxAtPixel(mousex, mousey)if boxx != None and boxy != None:# the mouse is currently over a box.if mainBoard[boxx][boxy] == None:drawHighlightBox(boxx, boxy)if mainBoard[boxx][boxy] == None and mouseClicked:mainBoard[boxx][boxy] = playerTurn # set the box as "filled"drawXO(playerTurn, boxx, boxy)if playerTurn == 'X':playerTurn = 'O'else: playerTurn = 'X'# Algorithm that check the game is overif hasWon(mainBoard):if playerTurn == 'X': Message = 'Player 1 Wins!'else: Message = 'Player 2 Wins!'popMessage(Message)mainBoard = [[None,None,None],[None,None,None],[None,None,None]]playerTurn = 'X'elif hasDraw(mainBoard):Message = ' Draw! 'popMessage(Message)mainBoard = [[None,None,None],[None,None,None],[None,None,None]]playerTurn = 'X'# Redraw the screen and wait a clock tick.pygame.display.update()FPSCLOCK.tick(FPS)def popMessage(Message):font = pygame.font.Font('font/nanum.ttf', 32)textSurface = font.render(Message, True, BLACK, LIGHTBLUE)textRect = textSurface.get_rect()textRect.center = (170, 85)DISPLAYSURF.blit(textSurface, textRect)pygame.display.update()pygame.time.wait(2000)def getBoxAtPixel(x, y):# Draw Box on display surfacefor boxx in range(BOARDWIDTH):for boxy in range(BOARDHEIGHT):left, top = leftTopCoordsOfBox(boxx, boxy)boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)if boxRect.collidepoint(x, y):return (boxx, boxy)return (None, None)def drawBoard(board):# Draws all of the boxes in their covered or revealed state.for boxx in range(BOARDWIDTH):for boxy in range(BOARDHEIGHT):left, top = leftTopCoordsOfBox(boxx, boxy)if board[boxx][boxy] == None:pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))else:pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))drawXO(board[boxx][boxy], boxx, boxy)def leftTopCoordsOfBox(boxx, boxy):# Convert board coordinates to pixel coordinatesleft = boxx* (BOXSIZE + GAPSIZE) + GAPSIZEtop = boxy * (BOXSIZE + GAPSIZE) + GAPSIZEreturn (left, top)def drawHighlightBox(boxx, boxy):left, top = leftTopCoordsOfBox(boxx, boxy)pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left , top , BOXSIZE , BOXSIZE))def drawXO(playerTurn, boxx, boxy):left, top = leftTopCoordsOfBox(boxx, boxy)if playerTurn == 'X':pygame.draw.line(DISPLAYSURF, LINECOLOR, (left + 3, top + 3), (left + BOXSIZE - 3, top + BOXSIZE - 3), 4)pygame.draw.line(DISPLAYSURF, LINECOLOR, (left + BOXSIZE - 3, top + 3), (left + 3, top + BOXSIZE - 3), 4)else:HALF = int(BOXSIZE / 2)pygame.draw.circle(DISPLAYSURF, LINECOLOR, (left + HALF, top + HALF), HALF - 3, 4)def hasWon(board):# Returns True if player 1 or 2 winsfor xrow in board: # horizontalif xrow[0] != None and xrow[0] == xrow[1] and xrow[1] == xrow[2]:return Truefor i in range(3): # verticalif board[0][i] != None and board[0][i] == board[1][i] and board[1][i] == board[2][i]:return Trueif board[0][0] != None and board[0][0] == board[1][1] and board[1][1] == board[2][2]: # diagnol 1return Trueif board[2][0] != None and board[2][0] == board[1][1] and board[1][1] == board[0][2]: # diagnol 2return Truereturn False # no winnerdef hasDraw(board):# Returns True if all the boxes have been filledfor i in board:if None in i:return Falsereturn Trueif __name__ == '__main__':main()
(1)에서 구현해야 할 점 구현 완료!
부족한 점
- 승리시 표시하는 배경 박스를 그린 후 배경색이 없는 텍스트를 그리려 했으나, 결국 텍스트 배경색 이용
- 승리&무승부시 텍스트가 떠 있는 상태에서 클릭을 할 경우 다음 판에 반영된다.
보완점
- 텍스트를 사용하는 것이 아니라 팝업 텍스트 자체를 png로 저장한 후 불러오는 방법 고려
알게된 점
- pygame.display.update() 함수를 사용하는 이유는 화면 상에서 그래픽 변경 사항을 저장한 후 실제로 우리가 볼 수 있도록 하기 위해서이다.