Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


tp9

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

Topics I've Started

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()

 

 

EDIT: Added a class and function, based on feedback, for readability.

# 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()

 

 

EDIT: Added final abstractions.

# 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.


Space Invaders clone

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.

 

Bugs Invade

 

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