Created
November 6, 2013 05:45
-
-
Save virtualanup/7331507 to your computer and use it in GitHub Desktop.
Tic Tac Toe without AI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# tictactoe | |
# by Virtualanup | |
import pygame,random | |
from pygame.locals import * | |
from sys import exit | |
import math | |
from collections import defaultdict | |
#game constants | |
FPS=20 | |
#color codes | |
black=(0,0,0) | |
white = (255,255,255) | |
blue=(0,0,200) | |
red=(200,0,0) | |
green=(0,200,0) | |
cross=1 | |
circle=2 | |
empty=0 | |
computer=1 | |
human=2 | |
class Player: | |
def __init__(self,type,sign): | |
self.type=type | |
self.sign=sign | |
def SetBoard(self,board): | |
self.board=board | |
def GetMove(self): | |
pass | |
#process click of mouse | |
def MouseClick(self,cell): | |
pass | |
#the human player class. handles mouse clicks | |
class HumanPlayer(Player): | |
def __init__(self,sign): | |
super().__init__(human,sign)#human player | |
self.lastmove=-1 | |
def GetMove(self): | |
if(self.lastmove != -1): | |
move=self.lastmove | |
self.lastmove=-1 | |
return move | |
def MouseClick(self,cell): | |
if not cell in self.board.moves: #it no move in the position | |
self.lastmove=cell | |
class BoardAnalyzer: | |
alllines=[[(a,b) for a in range(0,3)] for b in range(0,3)]+[[(b,a) for a in range(0,3)] for b in range(0,3)]+[[(0,0),(1,1),(2,2)],[(0,2),(1,1),(2,0)]] | |
def __init__(self): | |
print("creating new board analyzer") | |
self.moves=[] #this will store the moves. | |
self.gameover=False | |
self.draw=False | |
self.board=defaultdict(lambda:empty) #board is a dictionary that is initially empty | |
def Move(self,position,symbol): | |
#if the board position is free,copy an item to it | |
if self.board[position] != empty: | |
return False | |
self.board[position]=symbol | |
self.moves.append(position) | |
self.CheckGameOver() | |
return True | |
#undo the last move. | |
def UndoMove(self): | |
if len(self.moves) == 0: | |
return False | |
self.board[self.moves.pop()]=empty | |
return True | |
def GameOver(self): | |
return self.gameover | |
def Draw(self): | |
return self.draw | |
def CheckGameOver(self): | |
print("inside check game over") | |
for line in self.alllines: | |
px,py,pz=line | |
if self.board[px] != empty and self.board[px]==self.board[py]==self.board[pz]: | |
self.gameover = True | |
self.draw=False | |
break | |
else: | |
if len(self.moves) == 9: | |
self.draw=True | |
self.gameover = True | |
else: | |
self.gameover = False | |
#the computer player | |
class ComputerPlayer(Player): | |
#analyze the current board position and return heuristic value | |
def Heuristic(self): | |
pass | |
class Board: | |
gridcolor=blue | |
circlecolor=red | |
crosscolor=green | |
def __init__(self,boardsize=400): | |
self.players=[] | |
self.boardsize=boardsize | |
self.gameboard=BoardAnalyzer() | |
self.font = pygame.font.Font(None, 30) #load the font for displaying text | |
def reset(self): | |
print("resetting game board") | |
self.gameboard=BoardAnalyzer() | |
#notify the players about the new game board | |
for player in self.players: | |
player.SetBoard(self.gameboard) | |
#whoever loses gets the first chance | |
self.player1,self.player2=self.player2,self.player1 | |
def printstatus(self,screen): | |
textstr='' | |
if game.gameboard.GameOver(): | |
if game.gameboard.Draw(): | |
textstr="Draw. Click here to reset" | |
else: | |
textstr="Player "+str(self.players.index(self.player1)+1)+" wins. Click here to reset" | |
else: | |
textstr="Player "+str(self.players.index(self.player1)+1)+"'s turn" | |
text = self.font.render(textstr, 1,(255,255,255)) | |
textpos = text.get_rect(centerx=screen.get_width()/2,y=self.boardsize+5) | |
screen.blit(text, textpos) | |
def AddPlayer(self,player): | |
player.SetBoard(self.gameboard) | |
self.players.append(player) | |
if(len(self.players) > 1): | |
self.player1=self.players[0] | |
self.player2=self.players[1] | |
def draw(self,screen): | |
#draw the board in blue color | |
tolerance=20 | |
pygame.draw.line(screen, self.gridcolor, (self.boardsize/3,tolerance), (self.boardsize/3,self.boardsize-tolerance),10) | |
pygame.draw.line(screen, self.gridcolor, ((2*self.boardsize)/3,tolerance), ((2*self.boardsize)/3,self.boardsize-tolerance),10) | |
pygame.draw.line(screen, self.gridcolor, (tolerance,(self.boardsize)/3), (self.boardsize-tolerance,(self.boardsize)/3),10) | |
pygame.draw.line(screen, self.gridcolor, (tolerance,(2*self.boardsize)/3), (self.boardsize-tolerance,(2*self.boardsize)/3),10) | |
#draw each cross or circle | |
for move in self.gameboard.moves: | |
mx,my=move | |
onethird=int(self.boardsize/3) | |
if self.gameboard.board[move] == circle: | |
#draw a circle in that position | |
pos=mx*onethird+int(onethird/2),my*onethird+int(onethird/2) | |
pygame.draw.circle(screen, self.circlecolor, pos, int(onethird/3), 10) | |
elif self.gameboard.board[move] == cross: | |
tl=mx*onethird+int(onethird/5),my*onethird+int(onethird/5) | |
tr=(mx+1)*onethird-int(onethird/5),my*onethird+int(onethird/5) | |
bl=mx*onethird+int(onethird/5),(my+1)*onethird-int(onethird/5) | |
br=(mx+1)*onethird-int(onethird/5),(my+1)*onethird-int(onethird/5) | |
pygame.draw.line(screen, self.crosscolor, tl, br,10) | |
pygame.draw.line(screen, self.crosscolor, tr, bl,10) | |
#get items from board analyzer and draw the required items | |
#find the position of the mouse click and pass to the snake | |
def MouseClick(self,position): | |
#get the cell position and pass it to the player(s) | |
mx,my=position | |
if my < self.boardsize: #if inside range | |
onethird=int(self.boardsize/3) | |
cx=int(math.floor(mx/onethird)) | |
cy=int(math.floor(my/onethird)) | |
cell=cx,cy | |
print("mouse click in ",cell,". Calling for players") | |
self.player1.MouseClick(cell) #pass along to the player | |
elif self.gameboard.GameOver(): | |
self.reset() | |
def update(self): | |
#update the board | |
if not self.gameboard.GameOver(): | |
nextpos=self.player1.GetMove() | |
if nextpos is not None: | |
#move the player in that position | |
self.gameboard.Move(nextpos,self.player1.sign) | |
#if any player caused game over, keep him as player 1 | |
if not self.gameboard.GameOver(): | |
self.player1,self.player2=self.player2,self.player1 #exchange the players | |
if(__name__ == "__main__"): | |
pygame.init() | |
boardsize=400 | |
screen = pygame.display.set_mode((boardsize,boardsize+35)) | |
pygame.display.set_caption('Tic Tac Toe') | |
gameover=False | |
clock = pygame.time.Clock() | |
game=Board() | |
game.AddPlayer(HumanPlayer(cross)) | |
game.AddPlayer(HumanPlayer(circle)) | |
while gameover==False: | |
clock.tick(FPS) | |
screen.fill(black); | |
for event in pygame.event.get(): | |
if event.type == QUIT: | |
pygame.quit();exit() | |
if event.type == pygame.MOUSEBUTTONUP: | |
game.MouseClick(event.pos) | |
game.update() | |
game.draw(screen) | |
game.printstatus(screen) | |
pygame.display.update() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment