• Create Account

Banner advertising on our site currently available from just \$5!

# tp9

Member Since 26 Feb 2013
Offline Last Active Nov 14 2014 08:32 PM

### Tic-Tac-Toe code review request, basic AI

23 June 2014 - 06:02 PM

I'd appreciate any feedback on my Tic-Tac-Toe Pygame code. I'm making a basic clone so I can learn about minimax for the computer AI. Currently the AI is just random open blocks.

I'm using the Wikipedia page on minimax HERE, if anyone has a better reference on the algorithm I'd appreciate that information too. Here's my code, and it's available on GitHub as well.

EDIT: Added in minimax for unbeatable AI.

```# coding=UTF8
import pygame, os, sys, random, copy
import pygame.freetype
from pygame.locals import *
from pprint import pprint as pp

# Constants
PLAYER = 'player'
COMPUTER = 'computer'
WINDOWWIDTH = 600
WINDOWHEIGHT= 500
TILESIZE    = 120
HALFTILE    = int(TILESIZE / 2)
BOARDWIDTH  = 3
BOARDHEIGHT = 3
FONTSIZE = 50

XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * TILESIZE)) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * TILESIZE)) / 2)

# Colors
WHITE       = (255, 255, 255)
DARKGRAY    = (40, 40, 40)

def tile_available(board):
tile_available = False
for y in range(BOARDHEIGHT):
if None in board[y]:
tile_available = True
break;
return tile_available

def player_wins(board, current_player):
if [current_player, current_player, current_player] in (
board[0], board[1], board[2],
[board[0][0], board[1][0], board[2][0]],
[board[0][1], board[1][1], board[2][1]],
[board[0][2], board[1][2], board[2][2]],
[board[0][0], board[1][1], board[2][2]],
[board[2][0], board[1][1], board[0][2]] ):
return True
else:
return False

def minimax(board, player):
if player_wins(board, PLAYER):
return(-1, None)
elif player_wins(board, COMPUTER):
return(+1, None)
elif not tile_available(board):
return (0, None)
elif player == COMPUTER:
best_move = (-2, None)
for y in range(BOARDHEIGHT):
for x in range(BOARDWIDTH):
if board[y][x] == None:
new_board = copy.deepcopy(board)
new_board[y][x] = COMPUTER
value = minimax(new_board, PLAYER)[0]
if value>best_move[0]:
best_move = (value,(x,y))
return best_move
else:
best_move = (+2, None)
for y in range(BOARDHEIGHT):
for x in range(BOARDWIDTH):
if board[y][x] == None:
new_board = copy.deepcopy(board)
new_board[y][x] = PLAYER
value = minimax(new_board, COMPUTER)[0]
if value<best_move[0]:
best_move = (value,(x,y))
return best_move

def main():
pygame.init()
DISPLAYSURF = pygame.display.set_mode( (WINDOWWIDTH, WINDOWHEIGHT) )
pygame.display.set_caption("Tic-Tac-Toe")
FONT = pygame.freetype.Font(None, FONTSIZE)

board = [[None] * 3 for i in range(3)]
game_over = False
winner = None

while not game_over:
mouse_clicked = False
# Event handler
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouse_clicked = True
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
if mouse_clicked:
for tiley in range(BOARDHEIGHT):
for tilex in range(BOARDWIDTH):
leftpos = tilex * TILESIZE + XMARGIN
toppos = tiley * TILESIZE + YMARGIN
tile_rect = pygame.Rect(leftpos, toppos, TILESIZE, TILESIZE)
if tile_rect.collidepoint(mousex, mousey) and board[tiley][tilex] == None:
board[tiley][tilex] = PLAYER
if player_wins(board, PLAYER):
game_over = True
winner = PLAYER
else:
# Make computer move
if tile_available(board):
compx, compy = minimax(copy.deepcopy(board), COMPUTER)[1]
board[compy][compx] = COMPUTER
else:
game_over = True
winner = 'No one'
if player_wins(board, COMPUTER):
game_over = True
winner = COMPUTER
# Draw board lines
for x in range(TILESIZE, BOARDWIDTH * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY,
(x + XMARGIN, YMARGIN), (x + XMARGIN, WINDOWHEIGHT - YMARGIN), 6)
for y in range(TILESIZE, BOARDHEIGHT * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY,
(XMARGIN, y + YMARGIN), (WINDOWWIDTH - XMARGIN, y + YMARGIN), 6)
# Make tile rects
for y in range(len(board)):
for x in range(len(board[y])):
if board[y][x] in (PLAYER, COMPUTER):
if board[y][x] == PLAYER:
surf, surfrect = FONT.render('X', DARKGRAY, None)
elif board[y][x] == COMPUTER:
surf, surfrect = FONT.render('O', DARKGRAY, None)
surfrect.center = (int(XMARGIN + (x * TILESIZE) + HALFTILE), int(YMARGIN + (y * TILESIZE) + HALFTILE))
DISPLAYSURF.blit(surf, surfrect)

pygame.display.update()
print(winner, "wins!")

if __name__ == '__main__':
while True:
main()```

```# coding=UTF8
import pygame, os, sys, random, copy
import pygame.freetype
from pygame.locals import *
from pprint import pprint as pp

# Constants
PLAYER = 'player'
COMPUTER = 'computer'
WINDOWWIDTH = 600
WINDOWHEIGHT= 500
TILESIZE    = 120
HALFTILE    = int(TILESIZE / 2)
BOARDWIDTH  = 3
BOARDHEIGHT = 3
FONTSIZE = 50

XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * TILESIZE)) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * TILESIZE)) / 2)

# Colors
WHITE       = (255, 255, 255)
DARKGRAY    = (40, 40, 40)

class BestMove():
def __init__(self, value, location):
self.value = value
self.location = location

def tile_available(board):
tile_available = False
for y in range(BOARDHEIGHT):
if None in board[y]:
tile_available = True
break;
return tile_available

def player_wins(board, current_player):
if [current_player, current_player, current_player] in (
board[0], board[1], board[2],
[board[0][0], board[1][0], board[2][0]],
[board[0][1], board[1][1], board[2][1]],
[board[0][2], board[1][2], board[2][2]],
[board[0][0], board[1][1], board[2][2]],
[board[2][0], board[1][1], board[0][2]] ):
return True
else:
return False

def next_player(current_player):
value = None
next = None
if current_player == COMPUTER:
value = -2
next = PLAYER
else:
value = +2
next = COMPUTER
return value, next

def minimax(board, player):
if player_wins(board, PLAYER):
return(-1, None)
elif player_wins(board, COMPUTER):
return(+1, None)
elif not tile_available(board):
return(0, None)
else:
point_value, next_person = next_player(player)
best_move = BestMove(value = point_value, location = None)
for y in range(BOARDHEIGHT):
for x in range(BOARDWIDTH):
if board[y][x] == None:
new_board = copy.deepcopy(board)
new_board[y][x] = player
value = minimax(new_board, next_person)[0]
if (value > best_move.value and player == COMPUTER) or (value < best_move.value and player == PLAYER):
best_move.value, best_move.location = value, (x,y)
return best_move.value, best_move.location

def main():
pygame.init()
DISPLAYSURF = pygame.display.set_mode( (WINDOWWIDTH, WINDOWHEIGHT) )
pygame.display.set_caption("Tic-Tac-Toe")
FONT = pygame.freetype.Font(None, FONTSIZE)

board = [[None] * 3 for i in range(3)]
game_over = False
winner = None

while not game_over:
mouse_clicked = False
# Event handler
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouse_clicked = True
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
if mouse_clicked:
for tiley in range(BOARDHEIGHT):
for tilex in range(BOARDWIDTH):
leftpos = tilex * TILESIZE + XMARGIN
toppos = tiley * TILESIZE + YMARGIN
tile_rect = pygame.Rect(leftpos, toppos, TILESIZE, TILESIZE)
if tile_rect.collidepoint(mousex, mousey) and board[tiley][tilex] == None:
board[tiley][tilex] = PLAYER
if player_wins(board, PLAYER):
game_over = True
winner = PLAYER
else:
# Make computer move
if tile_available(board):
compx, compy = minimax(board = board, player = COMPUTER)[1]
board[compy][compx] = COMPUTER
else:
game_over = True
winner = 'No one'
if player_wins(board, COMPUTER):
game_over = True
winner = COMPUTER
# Draw board lines
for x in range(TILESIZE, BOARDWIDTH * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY,
(x + XMARGIN, YMARGIN), (x + XMARGIN, WINDOWHEIGHT - YMARGIN), 6)
for y in range(TILESIZE, BOARDHEIGHT * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY,
(XMARGIN, y + YMARGIN), (WINDOWWIDTH - XMARGIN, y + YMARGIN), 6)
# Make tile rects
for y in range(len(board)):
for x in range(len(board[y])):
if board[y][x] in (PLAYER, COMPUTER):
if board[y][x] == PLAYER:
surf, surfrect = FONT.render('X', DARKGRAY, None)
elif board[y][x] == COMPUTER:
surf, surfrect = FONT.render('O', DARKGRAY, None)
surfrect.center = (int(XMARGIN + (x * TILESIZE) + HALFTILE), int(YMARGIN + (y * TILESIZE) + HALFTILE))
DISPLAYSURF.blit(surf, surfrect)

pygame.display.update()
print(winner, "wins!")

if __name__ == '__main__':
while True:
main()```

```# coding=UTF8
import pygame, os, sys, random, copy
import pygame.freetype
from pygame.locals import *
from pprint import pprint as pp

# Constants
PLAYER = 'player'
COMPUTER = 'computer'
WINDOWWIDTH = 600
WINDOWHEIGHT= 500
TILESIZE    = 120
HALFTILE    = int(TILESIZE / 2)
BOARDWIDTH  = 3
BOARDHEIGHT = 3
FONTSIZE = 50

XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * TILESIZE)) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * TILESIZE)) / 2)

# Colors
WHITE       = (255, 255, 255)
DARKGRAY    = (40, 40, 40)

class BestMove():
def __init__(self, value, location):
self.value = value
self.location = location

def mouse_clicked(in_board, mousex, mousey):
board = copy.deepcopy(in_board)
game_over = False
winner = None

for tiley in range(BOARDHEIGHT):
for tilex in range(BOARDWIDTH):
leftpos = tilex * TILESIZE + XMARGIN
toppos = tiley * TILESIZE + YMARGIN
tile_rect = pygame.Rect(leftpos, toppos, TILESIZE, TILESIZE)
if tile_rect.collidepoint(mousex, mousey) and board[tiley][tilex] == None:
board[tiley][tilex] = PLAYER
if player_wins(board, PLAYER):
game_over = True
winner = PLAYER
else:
# Make computer move
if tile_available(board):
compx, compy = minimax(board = board, player = COMPUTER)[1]
board[compy][compx] = COMPUTER
else:
game_over = True
winner = 'No one'
if player_wins(board, COMPUTER):
game_over = True
winner = COMPUTER
return board, game_over, winner

def tile_available(board):
tile_available = False
for y in range(BOARDHEIGHT):
if None in board[y]:
tile_available = True
break;
return tile_available

def player_wins(board, current_player):
if [current_player, current_player, current_player] in (
board[0], board[1], board[2],
[board[0][0], board[1][0], board[2][0]],
[board[0][1], board[1][1], board[2][1]],
[board[0][2], board[1][2], board[2][2]],
[board[0][0], board[1][1], board[2][2]],
[board[2][0], board[1][1], board[0][2]] ):
return True
else:
return False

def next_player(current_player):
value = None
next = None
if current_player == COMPUTER:
value = -2
next = PLAYER
else:
value = +2
next = COMPUTER
return value, next

def draw_board(displaysurf):
for x in range(TILESIZE, BOARDWIDTH * TILESIZE, TILESIZE):
pygame.draw.line(displaysurf, DARKGRAY,
(x + XMARGIN, YMARGIN), (x + XMARGIN, WINDOWHEIGHT - YMARGIN), 6)
for y in range(TILESIZE, BOARDHEIGHT * TILESIZE, TILESIZE):
pygame.draw.line(displaysurf, DARKGRAY,
(XMARGIN, y + YMARGIN), (WINDOWWIDTH - XMARGIN, y + YMARGIN), 6)

def draw_tiles(displaysurf, in_board, x_surf, x_surfrect, o_surf, o_surfrect):
board = copy.deepcopy(in_board)
for y in range(len(board)):
for x in range(len(board[y])):
if board[y][x] in (PLAYER, COMPUTER):
if board[y][x] == PLAYER:
surf, surfrect = x_surf, x_surfrect
elif board[y][x] == COMPUTER:
surf, surfrect = o_surf, o_surfrect
surfrect.center = (int(XMARGIN + (x * TILESIZE) + HALFTILE), int(YMARGIN + (y * TILESIZE) + HALFTILE))
displaysurf.blit(surf, surfrect)

def minimax(board, player):
if player_wins(board, PLAYER):
return(-1, None)
elif player_wins(board, COMPUTER):
return(+1, None)
elif not tile_available(board):
return(0, None)
else:
point_value, next_person = next_player(player)
best_move = BestMove(value = point_value, location = None)
for y in range(BOARDHEIGHT):
for x in range(BOARDWIDTH):
if board[y][x] == None:
new_board = copy.deepcopy(board)
new_board[y][x] = player
value = minimax(new_board, next_person)[0]
if (value > best_move.value and player == COMPUTER) or (value < best_move.value and player == PLAYER):
best_move.value, best_move.location = value, (x,y)
return best_move.value, best_move.location

def main():
pygame.init()
DISPLAYSURF = pygame.display.set_mode( (WINDOWWIDTH, WINDOWHEIGHT) )
pygame.display.set_caption("Tic-Tac-Toe")
FONT = pygame.freetype.Font(None, FONTSIZE)

board = [[None] * 3 for i in range(3)]
game_over = False
winner = None

x_surf, x_surfrect = FONT.render('X', DARKGRAY, None)
o_surf, o_surfrect = FONT.render('O', DARKGRAY, None)

draw_board(displaysurf = DISPLAYSURF)

while not game_over:
# Event handler
event = pygame.event.wait()
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
board, game_over, winner = mouse_clicked(in_board = board, mousex = mousex, mousey = mousey)
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos

draw_tiles( displaysurf = DISPLAYSURF
,in_board = board
,x_surf = x_surf
,x_surfrect = x_surfrect
,o_surf = o_surf
,o_surfrect = o_surfrect )

pygame.display.update()
print(winner, "wins!")

if __name__ == '__main__':
while True:
main()
```

### Latest project, a level editor for Star Pusher

02 May 2013 - 01:51 PM

Here's my latest project. It's a level editor for the Star Pusher game in Al Sweigart's book "Making Games with Python & Pygame." Took roughly 2 weeks of development. I honestly thought it would take only a week to do, since I wasn't creating a game from scratch, but it ended up being the most difficult thing I tackled so far. The hardest part of the project was definitely the camera handling.

Here's the GitHub

### Game Jams, when can I participate?

26 April 2013 - 08:47 PM

I'm interested in getting involved with other people who are also interested in game development. What level of knowledge is required before participating in social coding events like Game Jams or Code Jams? I consider myself an Advanced Beginner or Beginner Intermediate with Python and Pygame. I could probably participate in an event with other beginners, hacking around with programs or making basic beginner level game clones, but I wouldn't be much use on a full blown game created in a couple of days.

20 April 2013 - 04:43 PM

Here's my second project that I recently completed. It's a space invaders clone written with the Pygame library. My main goals were collision detection, basic enemy AI, sprite sheet and sprite handling, and timing.

My current project is a level editor for a Pygame tutorial. I hope to have it completed and posted here within the next week.

### Trying to modify a 2D list in Python

20 April 2013 - 02:13 AM

Can someone help me with a bug I'm having with modifying a 2D list? I'm making deep copies but the original is getting modified for some reason. I don't know how this is happening. Thanks.

https://gist.github.com/wokumura/5425191

```OBJECTIMAGES = ['#', '\$', '@', '.']
mapTiles =  [[None, '#', None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None],
[None, None, None, None, None, None, None, None, None, None]]

newMap = mapTiles[:]
for x in newMap[:]:
if set(OBJECTIMAGES).intersection(x) == set([]):
newMap.remove(x)
else:
break
tempMap = newMap[:]
objectFound = False
for row in range(len(newMap[0])):
for x in range(len(newMap)):
print x, row, mapTiles[0][1]
if newMap[x][row] in OBJECTIMAGES:
objectFound = True
break
if objectFound:
break
else:
for i in range(len(newMap)):
del tempMap[i][0]
```

PARTNERS