#!/usr/bin/python """ Submission for CITS1401 Project 2 Author: ... Student Number: ... Date: 11/05/2014 Version 1.0 Notes: Launching game will display a splash screen which will prompt for board size, and allow selection of player modes This allows for human vs human, human vs computer and computer vs computer play There are two options for computer players, one will randomly pick a move, while the other will prioritise corner and edge spaces To play as a human, when it is your turn (as indicated by the turn marker up the top), click the square you wish to place your marker. Some global variables have been used in a manner that isnt ideal, however they were used primarily to allow for callback functions that deal with clicks, without modifying the functions signitures as presented in the requirements """ from turtle import Turtle import random #t = undefined playermodes = ["Human", "Computer Random"] playeroptions = ["Human", "Computer Random", "Computer Corner"] boardsize = 8 turn = 1 previouspass = False def initialiseBoard(n): b = [] for i in range((n//2)-1): b.append([0]*n) b.append([0]*((n//2)-1) + [1,-1] + [0]*((n//2)-1)) b.append([0]*((n//2)-1) + [-1,1] + [0]*((n//2)-1)) for i in range((n//2)-1): b.append([0]*n) return b def drawBoard(b): #t = Turtle() t.clear() t.screen.setworldcoordinates(0,0,len(b)*100,len(b)*100+50) t.hideturtle() t.speed(0) t.pencolor(0.0,0.0,0.0) t.up t.goto(len(b)*50,len(b)*100+10) t.write("Turn:", False, align="center", font=("Arial", 30, "normal")) t.goto(len(b)*50+100, len(b)*100+10) t.down() t.begin_fill() t.circle(20) t.end_fill() t.up() t.goto(10,len(b)*100+10) t.write("Black:", False, align="left", font=("Arial", 20, "normal")) t.pencolor(1.0,1.0,1.0) t.goto(len(b)*100 - 60,len(b)*100+10) t.write("White:", False, align="right", font=("Arial", 20, "normal")) t.pencolor(0.0,0.0,0.0) for x in range(0,(len(b)+1)*100, 100): t.goto(0,x) t.down() t.goto(len(b)*100, x) t.up() t.goto(x,0) t.down() t.goto(x,len(b)*100) t.up() for y in range(len(b)): for x in range(len(b)) : if (b[y][x] < 0): t.fillcolor(1.0,1.0,1.0) else : t.fillcolor(0.0,0.0,0.0) if (b[y][x] != 0): t.goto(x*100 + 50, y*100 + 10 ) t.down() t.begin_fill() t.circle(40) t.end_fill() t.up() def drawSplash(): global boardsize t.speed(0) t.screen.bgcolor(0.0,0.5,0.0) t.screen.setworldcoordinates(0,0,500,500) t.hideturtle() t.up() t.goto(250,400) t.write("Othello", False, align="center", font=("Arial", 60, "normal")) t.goto(100,350) t.write("Black Player", False, align="center", font=("Arial", 30, "normal")) t.goto(400,350) t.pencolor(1.0,1.0,1.0) t.write("White Player", False, align="center", font=("Arial", 30, "normal")) drawOptions(True) t.screen.onclick(splashClick) boardsize = int(t.screen.numinput("Othello", "Board Size:", 8)) while boardsize % 2 != 0 or boardsize < 4: boardsize = int(t.screen.numinput("Othello", "Please enter a valid board size:", 8)) t.fillcolor(0.0,0.0,0.0) t.begin_fill() drawBox((200,70),(300,30)) t.end_fill() t.goto(250, 35) t.pencolor(1.0,1.0,1.0) t.write("Play", False, align="center", font=("Arial", 30, "normal")) def splashClick(x,y): global playermodes global board playerupdate = -1 if x > 10 and x <30: playerupdate = 0 elif x > 470 and x <490: playerupdate = 1 elif x >= 200 and x <= 300 and y>=30 and y<= 70: board = initialiseBoard(boardsize) drawBoard(board) nextMove() if y < 320 and y > (320 - len(playeroptions) * 30) and playerupdate >= 0: offset = (y - (320 - (len(playeroptions)*30))) if (offset % 30) >= 10: button = int((len(playeroptions) -1 ) - (offset // 30)) playermodes[playerupdate] = playeroptions[button] #print(str(playerupdate)+" col clicked button " + str(button)) drawOptions(False) def drawOptions(drawtext): t.pencolor(0.0,0.0,0.0) for idx, val in enumerate(range(320,320-len(playeroptions)*30, -30)): if playermodes[0] == playeroptions[idx]: t.fillcolor(0.0,0.0,0.0) else: t.fillcolor(0.0,0.5,0.0) t.begin_fill() drawBox((10,val), (30,val-20)) t.end_fill() if drawtext: t.goto(40,val-20) t.write(playeroptions[idx], False, align="left", font=("Arial", 20, "normal")) if playermodes[1] == playeroptions[idx]: t.fillcolor(0.0,0.0,0.0) else: t.fillcolor(0.0,0.5,0.0) t.begin_fill() drawBox((470,val), (490,val-20)) t.end_fill() if drawtext: t.goto(460,val-20) t.write(playeroptions[idx], False, align="right", font=("Arial", 20, "normal")) def drawBox(tl, br): t.speed(0) t.up() t.goto(tl[0], tl[1]) t.down() t.goto(tl[0],br[1]) t.goto(br[0],br[1]) t.goto(br[0],tl[1]) t.goto(tl[0],tl[1]) t.up() def drawPiece(r, c, p): if __name__ == "__main__": #used to ensure that the testing program can call move independantly if p == 1: t.fillcolor(0.0,0.0,0.0) else : t.fillcolor(1.0,1.0,1.0) t.goto(c*100 + 50, r*100 + 10 ) t.down() t.begin_fill() t.circle(40) t.end_fill() t.up() def move(b, m, p): r = m[0] c = m[1] ms = m[2] b[r][c] = p drawPiece(r,c,p) for cd in ms: y = cd[0]+r x = cd[1]+c while (b[y][x] < 0) != (p < 0): b[y][x] = (b[y][x] - p)*(-1) drawPiece(y,x,p) y = y + cd[0] x = x + cd[1] return b def legalDirection(r, c, b, p, u, v): valid = False nextx = c+v nexty = r+u while (nextx < len(b)) and (nexty < len(b)) and (nextx >= 0) and (nexty >= 0) and ((b[nexty][nextx] < 0) != (p < 0)) and b[nexty][nextx] != 0: valid = True nextx = nextx+v nexty = nexty+u if (nextx >= len(b)) or (nexty >= len(b)) or (nextx < 0) or (nexty < 0) : return False elif ((b[nexty][nextx] < 0) == (p<0)) and b[nexty][nextx] != 0: return (True and valid) else: return False def legalMove(r,c,b,p): dirs = [(1,0),(-1,0),(1,1),(-1,1),(0,1),(0,-1),(1,-1),(-1,-1)] legal = [d for d in dirs if legalDirection(r,c,b,p,d[0],d[1])] return legal def moves(b,p): output = [] for y in range(len(b)): for x in range(len(b)): if b[y][x] == 0: output.append((y,x,legalMove(y,x,b,p))) output = [o for o in output if o[2] != []] return output def selectMove(ms, b, p): if getPlayerMode(p) == "Computer Random": return random.choice(ms) if getPlayerMode(p) == "Computer Corner": #tries to play in corners, then edges then random for m in ms: if (m[0] == 0 and m[1] == 0) or (m[0] == len(b)-1 and m[1] == 0) or (m[0] == len(b)-1 and m[1] == len(b)-1) or (m[0] == 0 and m[1] == len(b)-1): return m for m in ms: if m[0] == 0 or m[1] == 0 or m[0] == len(b)-1 or m[1] == len(b)-1 : return m return random.choice(ms) def getPlayerMode(p): if p == 1: return playermodes[0] else : return playermodes[1] def computerMove(): global turn global board global previouspass t.screen.onclick(None) possiblemoves = moves(board, turn) selectedMove = selectMove(possiblemoves, board, turn) board = move(board, selectedMove, turn) turn = -1 if turn == 1 else 1 nextMove() def nextMove(): global turn global previouspass drawScore() drawTurn() if moves(board, turn) != []: previouspass = False if turnIsComputer(): t.screen.onclick(None) computerMove() else : t.screen.onclick(humanMove) else : if previouspass: gameover() else: previouspass = True turn = -1 if turn == 1 else 1 nextMove() def drawScore(): scores = scoreBoard(board) t.pencolor(0.0,0.5,0.0) t.fillcolor(0.0,0.5,0.0) t.begin_fill() drawBox((180,len(board)*100+10), (270, len(board)*100+50)) t.end_fill() t.begin_fill() drawBox((len(board)*100 - 50,len(board)*100+10), (len(board)*100, len(board)*100+50)) t.end_fill() t.pencolor(0.0,0.0,0.0) t.goto(200, len(board)*100+10) t.write(str(scores[0]), False, align="left", font=("Arial", 20, "normal")) t.pencolor(1.0,1.0,1.0) t.goto(len(board)*100 - 10, len(board)*100+10) t.write(str(scores[1]), False, align="right", font=("Arial", 20, "normal")) t.pencolor(0.0,0.0,0.0) def drawTurn(): if turn == 1: t.fillcolor(0.0,0.0,0.0) else : t.fillcolor(1.0,1.0,1.0) t.goto(len(board)*50+100, len(board)*100+10) t.down() t.begin_fill() t.circle(20) t.end_fill() t.up() t.fillcolor(0.0,0.0,0.0) def humanMove(x,y): global board global turn global previouspass if x < boardsize * 100 and x > 0 and y < boardsize * 100 and y > 0: col = int(x // 100) row = int(y // 100) #print("clicked col:"+str(col)+" row:"+str(row)) legalMoves = legalMove(row, col, board, turn) if legalMoves != [] and board[row][col] == 0: t.screen.onclick(None) board = move(board, (row, col, legalMoves), turn) turn = -1 if turn == 1 else 1 nextMove() def turnIsComputer(): if turn == -1: return playermodes[1] != "Human" else : return playermodes[0] != "Human" def gameover(): score = scoreBoard(board) t.goto(boardsize*50, boardsize*50) if score[0] > score[1]: winner = "Black" wid = 0 lid = 1 else : winner = "White" wid = 1 lid = 0 t.pencolor(0.0,0.0,1.0) t.write(winner+" wins!", False, align="center", font=("Arial", 60, "normal")) t.goto(boardsize*50, boardsize*50 - 50) t.write(str(score[wid])+" to "+str(score[lid]), False, align="center", font=("Arial", 40, "normal")) def scoreBoard(b): black = 0 white = 0 for y in b: for x in y: if x < 0: white = white + (x * (-1)) else: black = black + x return (black, white) def main(): global t t = Turtle() drawSplash() t.screen.mainloop() #size = int(input("Game Board Size: ")) #init board if __name__ == "__main__": main()