Committing my old Tak project to Forgejo
BIN
2D pieces/capstone-dark.png
Executable file
|
After Width: | Height: | Size: 48 KiB |
BIN
2D pieces/capstone-light.png
Executable file
|
After Width: | Height: | Size: 49 KiB |
5511
2D pieces/darkblocks.ai
Executable file
BIN
2D pieces/flat-dark.png
Executable file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
2D pieces/flat-light.png
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
5583
2D pieces/lightblock.ai
Executable file
BIN
2D pieces/wall-dark.png
Executable file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
2D pieces/wall-light.png
Executable file
|
After Width: | Height: | Size: 2 KiB |
73
Actions.py
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
def piecesLeft(board, val):
|
||||
used = board.countTotalPieces()
|
||||
if val > 0:
|
||||
if val > 2 and used[3] >= board.capstones:
|
||||
return False
|
||||
elif used[1] + used[2] >= board.pieces:
|
||||
return False
|
||||
else:
|
||||
if abs(val) > 2 and used[-3] >= board.capstones:
|
||||
return False
|
||||
elif used[-1] + used[-2] >= board.pieces:
|
||||
return False
|
||||
return True
|
||||
|
||||
def place(board, loc, type):
|
||||
if not piecesLeft(board, type):
|
||||
raise ValueError('No more of those pieces left')
|
||||
elif abs(type) > 3 or type == 0:
|
||||
raise ValueError('Not a valid piece')
|
||||
elif board.isEmpty(loc):
|
||||
board.getLocation(loc)[-1] = type
|
||||
else:
|
||||
raise ValueError('This location has pieces you cant place here')
|
||||
|
||||
def getPieces(board, loc, num):
|
||||
hand = []
|
||||
for i in range(num):
|
||||
hand.append(board.getLocation(loc).pop())
|
||||
if board.countStack(loc) == 0:
|
||||
board.getLocation(loc).append(0)
|
||||
return hand
|
||||
|
||||
def pickup(board, start, dropArray):
|
||||
number = sum(dropArray)
|
||||
if number <= board.countStack(start):
|
||||
return getPieces(board, start, number)
|
||||
else:
|
||||
raise ValueError("You can't pick up more pieces than are in the space")
|
||||
|
||||
def getDirection(start, end):
|
||||
if start[0] == end[0]:
|
||||
return 0, (end[1] - start[1])//abs(end[1] - start[1])
|
||||
elif start[1] == end[1]:
|
||||
return (end[0] - start[0])//abs(end[0] - start[0]), 0
|
||||
else:
|
||||
raise ValueError("Must move in a straight line")
|
||||
|
||||
def dropPieces(board, loc, num, hand):
|
||||
for i in range(num):
|
||||
if board.isEmpty(loc):
|
||||
place(board, loc, hand.pop())
|
||||
elif abs(board.getTop(loc)) == 1:
|
||||
board.getLocation(loc).append(hand.pop())
|
||||
elif abs(board.getTop(loc)) == 2 and abs(hand[-1]) == 3:
|
||||
board.getLocation(loc)[-1] = board.getTop(loc)/2
|
||||
board.getLocation(loc).append(hand.pop())
|
||||
else:
|
||||
raise ValueError("This piece can't be placed on that piece")
|
||||
|
||||
def checkCarry(board, num):
|
||||
if num <= board.size:
|
||||
return None
|
||||
else:
|
||||
raise ValueError("You can't pick up that may pieces at once")
|
||||
|
||||
def move(board, start, end, dropArray):
|
||||
checkCarry(board, sum(dropArray))
|
||||
hand = pickup(board, start, dropArray)
|
||||
xdir, ydir = getDirection(start, end)
|
||||
current = start.copy()
|
||||
for element in dropArray:
|
||||
current = [current[0] + xdir, current[1] + ydir]
|
||||
dropPieces(board, current, element, hand)
|
||||
31
AuxiliaryTestingMethods.py
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
def fillSpace(game, loc, val):
|
||||
game.board.board[loc[0]][loc[1]] = [val]
|
||||
|
||||
def fillRow(game, row, val):
|
||||
for i in range(game.board.size):
|
||||
fillSpace(game, [row, i], val)
|
||||
|
||||
def fillCol(game, col, val):
|
||||
for i in range(game.board.size):
|
||||
fillSpace(game, [i, col], val)
|
||||
|
||||
def fillBoardEndFull(game):
|
||||
for i in range(game.board.size):
|
||||
fillRow(game, i, (-1)**i)
|
||||
|
||||
def fillBoardEndPiece(game):
|
||||
pieces = game.pieces
|
||||
capstones = game.capstones
|
||||
for i in range(game.board.size):
|
||||
for j in range(game.board.size):
|
||||
if pieces > 0:
|
||||
fillSpace(game, [i, j], 1)
|
||||
pieces -= 1
|
||||
elif capstones > 0:
|
||||
fillSpace(game, [i, j], 3)
|
||||
capstones -= 1
|
||||
|
||||
def resetBoard(game):
|
||||
for i in range(game.board.size):
|
||||
fillRow(game, i, 0)
|
||||
game.turnCount = 1
|
||||
61
Board.py
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
import collections
|
||||
|
||||
class Board(object):
|
||||
|
||||
def __init__(self, size):
|
||||
self.size = size
|
||||
self.board = [[[0] for i in range(self.size)]for j in range(self.size)]
|
||||
self.pieces, self.capstones = self.getPieceCount(size)
|
||||
|
||||
def getPieceCount(self, size):
|
||||
if size == 8:
|
||||
cap, pie = 2, 50
|
||||
elif size == 7:
|
||||
cap, pie = 2, 40
|
||||
elif size == 6:
|
||||
cap, pie = 1, 30
|
||||
elif size == 5:
|
||||
cap, pie = 1, 21
|
||||
elif size == 4:
|
||||
cap, pie = 0, 15
|
||||
else:
|
||||
cap, pie = 0, 10
|
||||
return (pie, cap)
|
||||
|
||||
def printBoard(self):
|
||||
for i in range(self.size):
|
||||
print(self.board[i])
|
||||
|
||||
def isAdjacent(self, loc1, loc2):
|
||||
return (loc1[0] == loc2[0] and abs(loc1[1] - loc2[1]) == 1) or (loc1[1] == loc2[1] and abs(loc1[0] - loc2[0]) == 1)
|
||||
|
||||
def onboard(self, loc):
|
||||
return (loc[0] >= 0 and loc[0] < self.size and (loc[1] >=0 and loc[1] < self.size))
|
||||
|
||||
def adjacent(self, loc):
|
||||
adj = [[loc[0], loc[1]+1], [loc[0], loc[1]-1], [loc[0]+1, loc[1]], [loc[0]-1, loc[1]]]
|
||||
return list(filter(self.onboard, adj))
|
||||
|
||||
def getTop(self, loc):
|
||||
return self.getLocation(loc)[-1]
|
||||
|
||||
def getLocation(self, loc):
|
||||
return self.board[loc[0]][loc[1]]
|
||||
|
||||
def countStack(self, loc):
|
||||
return len(self.getLocation(loc))
|
||||
|
||||
def isEmpty(self, loc):
|
||||
return len(self.getLocation(loc)) == 1 and self.getTop(loc) == 0
|
||||
|
||||
def countRow(self, row):
|
||||
count = collections.Counter()
|
||||
for col in self.board[row]:
|
||||
count = count + collections.Counter(col)
|
||||
return count
|
||||
|
||||
def countTotalPieces(self):
|
||||
count = collections.Counter()
|
||||
for i in range(self.size):
|
||||
count = count + self.countRow(i)
|
||||
return count
|
||||
98
End.py
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
import collections
|
||||
|
||||
def isFull(board):
|
||||
for row in board.board:
|
||||
for col in row:
|
||||
if col[-1] == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
def outOfPieces(board):
|
||||
pC = board.countTotalPieces()
|
||||
return (pC[1] + pC[2] == board.pieces and pC[3] == board.capstones) or (pC[-1] + pC[-2] == board.pieces and pC[-3] == board.capstones)
|
||||
|
||||
def end(board):
|
||||
en = False
|
||||
if outOfPieces(board):
|
||||
en = True
|
||||
elif isFull(board):
|
||||
en = True
|
||||
elif road(board)[0] or road(board)[1]:
|
||||
en = True
|
||||
return en
|
||||
|
||||
def isRoadPiece(board, loc, player):
|
||||
mod = -1*((-1)**player)
|
||||
return board.getTop(loc) == 1*mod or board.getTop(loc) == 3*mod
|
||||
|
||||
def isGoal(board, start, loc):
|
||||
return (start[0] == 0 and loc[0] == board.size-1) or (start[1] == 0 and loc[1] == board.size-1)
|
||||
|
||||
def checkRow(board, start, player):
|
||||
return isRoadPiece(board, [start, 0], player) and roadSearch(board, [start, 0], player)
|
||||
|
||||
def checkCol(board, start, player):
|
||||
return isRoadPiece(board, [0, start], player) and roadSearch(board, [0, start], player)
|
||||
|
||||
def roadSearch(board, start, player):
|
||||
visited = [[False for i in range(board.size)] for j in range(board.size)]
|
||||
locations = [start]
|
||||
visited[start[0]][start[1]] = True
|
||||
while len(locations) > 0:
|
||||
check = locations.pop(-1)
|
||||
adj = board.adjacent(check)
|
||||
for loc in adj:
|
||||
if not visited[loc[0]][loc[1]] and isGoal(board, start, loc) and isRoadPiece(board, loc, player):
|
||||
return True
|
||||
elif not visited[loc[0]][loc[1]] and isRoadPiece(board, loc, player):
|
||||
locations.append(loc)
|
||||
visited[loc[0]][loc[1]] = True
|
||||
return False
|
||||
|
||||
def road(board):
|
||||
p1road, p2road = False, False
|
||||
for i in range(board.size):
|
||||
if checkRow(board, i, 1) or checkCol(board, i, 1):
|
||||
p1road = True
|
||||
elif checkRow(board, i, 2) or checkCol(board, i, 2):
|
||||
p2road = True
|
||||
return p1road, p2road
|
||||
|
||||
def points(board, player):
|
||||
win = player
|
||||
piecesLeft = board.capstones + board.pieces
|
||||
if win == 1:
|
||||
piecesLeft = piecesLeft - (board.countTotalPieces()[1] + board.countTotalPieces()[3])
|
||||
else:
|
||||
piecesLeft = piecesLeft - (board.countTotalPieces()[-1] + board.countTotalPieces()[-3])
|
||||
return (board.size**2) + piecesLeft
|
||||
|
||||
def winRoad(board, player=1):
|
||||
rd = road(board)
|
||||
if rd[0] and rd[1]:
|
||||
return player
|
||||
elif rd[0] == True:
|
||||
return 1
|
||||
elif rd[1] == True:
|
||||
return 2
|
||||
return False
|
||||
|
||||
def flatStones(board, player):
|
||||
flatCount = 0
|
||||
for i in range(board.size):
|
||||
for j in range(board.size):
|
||||
if isRoadPiece(board, [i,j], player):
|
||||
flatCount += 1
|
||||
return flatCount
|
||||
|
||||
def winFlat(board):
|
||||
if flatStones(board, 1) > flatStones(board, 2):
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
|
||||
def winner(board, player=1):
|
||||
if winRoad(board, player):
|
||||
return winRoad(board, player)
|
||||
else:
|
||||
return winFlat(board)
|
||||
13
README.md
|
|
@ -1,3 +1,12 @@
|
|||
# Tak
|
||||
**Implementation of Tak in Python**
|
||||
|
||||
Tak is an abstract strategy game designed by James Earnest and Patrick Rothfuss, taken from Rothfuss' book the Wise Man's Fear.
|
||||
|
||||
Rules can be found [here](https://cheapass.com/wp-content/uploads/2016/07/Tak-Beta-Rules.pdf)
|
||||
|
||||
This game needs python and pygame installed to run. It should be run from the TakGame.py file
|
||||
|
||||
If you enjoy this please consider buying the physical game.
|
||||
|
||||

|
||||
|
||||
My implementation of the game Tak from Wise Man's fear in python
|
||||
62
Tak.py
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
import collections
|
||||
import Board as boa, End, Actions as act
|
||||
from copy import deepcopy
|
||||
#initialize board and pies
|
||||
class TakGame(object):
|
||||
def __init__(self, boardsize):
|
||||
self.board = boa.Board(boardsize)
|
||||
self.pieces, self.capstones = self.board.getPieceCount(boardsize)
|
||||
self.turnCount = 1
|
||||
self.history = []
|
||||
|
||||
def logAction(self):
|
||||
self.history.append(deepcopy(self.board.board))
|
||||
|
||||
def undo(self):
|
||||
if len(self.history) > 0:
|
||||
self.board.board = self.history.pop()
|
||||
self.turnCount -= 1
|
||||
|
||||
def end(self):
|
||||
return End.end(self.board)
|
||||
|
||||
def getEndResults(self):
|
||||
player = 2-((self.turnCount+1)%2)
|
||||
winP = End.winner(self.board, player)
|
||||
pts = End.points(self.board, player)
|
||||
return (winP, pts)
|
||||
|
||||
def actPlace(self, player, loc, value):
|
||||
self.logAction()
|
||||
piece = (-1) * ((-1)**player) * value
|
||||
if self.turnCount <= 2:
|
||||
piece = piece * (-1)//abs(piece)
|
||||
act.place(self.board, loc, piece)
|
||||
self.turnCount += 1
|
||||
|
||||
def checkLegalPlacement(self, loc):
|
||||
return self.board.isEmpty(loc)
|
||||
|
||||
def actMove(self, start, end, dropArray):
|
||||
self.logAction()
|
||||
act.move(self.board, start, end, dropArray)
|
||||
self.turnCount += 1
|
||||
|
||||
def checkLegalMoveStart(self, player, loc):
|
||||
return (player == 1 and self.board.getTop(loc) > 0) or (player == 2 and self.board.getTop(loc) < 0)
|
||||
|
||||
def checkLegalDrop(self, loc, held):
|
||||
return (abs(self.board.getTop(loc)) < 2) or (held == 3 and self.board.getTop(loc) < 3)
|
||||
|
||||
def checkLegalPickup(self, loc, num):
|
||||
return num <= len(self.board.getLocation(loc))
|
||||
|
||||
def piecesLeft(self, player):
|
||||
piecesUsed = self.board.countTotalPieces()
|
||||
if player == 1:
|
||||
piecesLeft = self.pieces - (piecesUsed[1] + piecesUsed[2])
|
||||
capstonesLeft = self.capstones - piecesUsed[3]
|
||||
else:
|
||||
piecesLeft = self.pieces - (piecesUsed[-1] + piecesUsed[-2])
|
||||
capstonesLeft = self.capstones - piecesUsed[-3]
|
||||
return (piecesLeft, capstonesLeft)
|
||||
300
TakGame.py
Executable file
|
|
@ -0,0 +1,300 @@
|
|||
import pygame, os, sys, itertools
|
||||
import Tak
|
||||
|
||||
#display setup
|
||||
pygame.init()
|
||||
#basic settings to use
|
||||
resolution = (800, 1000)
|
||||
width, height = 800, 800
|
||||
colors = {'white':(255, 255, 255), 'black':(0, 0, 0), 'lightBrown':(251, 196, 117), 'darkBrown':(139, 69, 0),
|
||||
'lightGrey':(150, 150, 150), 'darkGrey':(100, 100, 100)}
|
||||
win = pygame.display.set_mode(resolution)
|
||||
pygame.display.set_caption("Tak")
|
||||
font = pygame.font.SysFont('Arial', 18)
|
||||
background = pygame.Surface(resolution)
|
||||
background.fill(colors['black'])
|
||||
pieceImages = {'lightflat':pygame.image.load('2D pieces/flat-light.png'), 'lightwall':pygame.image.load('2D pieces/wall-light.png'),
|
||||
'lightcapstone':pygame.image.load('2D pieces/capstone-light.png'), 'darkflat':pygame.image.load('2D pieces/flat-dark.png'),
|
||||
'darkwall':pygame.image.load('2D pieces/wall-dark.png'), 'darkcapstone':pygame.image.load('2D pieces/capstone-dark.png'),}
|
||||
|
||||
#board and button classes
|
||||
class board(object):
|
||||
def __init__(self, size):
|
||||
self.width, self.height = 800, 800
|
||||
self.size = size
|
||||
self.squareSize = self.width/size
|
||||
self.bd = pygame.Surface((self.width, self.height))
|
||||
self.squareCentres = []
|
||||
self.color = [colors['lightBrown'], colors['darkBrown']]
|
||||
self.index = 1
|
||||
for row in range(size):
|
||||
for column in range(size):
|
||||
Square = (row*self.squareSize, column*self.squareSize, self.squareSize, self.squareSize)
|
||||
if Square not in self.squareCentres:
|
||||
self.squareCentres.append(Square)
|
||||
pygame.draw.rect(self.bd, self.color[self.index], Square)
|
||||
if not (size%2 == 0 and column == size-1):
|
||||
self.index = (self.index+1)%2
|
||||
|
||||
def checkSquare(self, coordinate):
|
||||
for i in range(len(self.squareCentres)):
|
||||
square = self.squareCentres[i]
|
||||
if square[0] < coordinate[0] < square[0] + square[2] and square[1] < coordinate[1] < square[1] + square[3]:
|
||||
return [i//self.size, i%self.size]
|
||||
|
||||
class button(object):
|
||||
def __init__(self, x, y, text, width = 110, height = 40):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.text = text
|
||||
self.disp = renderStandard(text)
|
||||
|
||||
#move has to be built in multiple steps and needs the object to hold and output the data in the correct
|
||||
#format for the move command in game
|
||||
class buildMove(object):
|
||||
def __init__(self, start):
|
||||
self.start = start
|
||||
self.dropLocations = []
|
||||
self.hand = 0
|
||||
self.current = start
|
||||
self.direction = None
|
||||
|
||||
def pickup(self, loc):
|
||||
if self.same(self.start, loc) and game.checkLegalPickup(loc, self.hand+1):
|
||||
self.hand += 1
|
||||
|
||||
def next(self, loc):
|
||||
return loc[0] == self.current[0] + self.direction[0] and loc[1] == self.current[1] + self.direction[1]
|
||||
|
||||
def same(self, loc1, loc2):
|
||||
return loc1[0] == loc2[0] and loc1[1] == loc2[1]
|
||||
|
||||
def drop(self, loc):
|
||||
if game.board.isAdjacent(loc, self.start) and self.direction is None and game.checkLegalDrop(loc, game.board.getLocation(self.start)[-self.hand]):
|
||||
self.direction = [loc[0]-self.start[0], loc[1] - self.start[1]]
|
||||
self.dropLocations.append(loc)
|
||||
self.hand -= 1
|
||||
self.current = loc
|
||||
|
||||
elif self.direction is not None and (self.same(self.current, loc) or self.next(loc)) and self.hand > 0 and game.checkLegalDrop(loc, game.board.getLocation(self.start)[-self.hand]):
|
||||
self.dropLocations.append(loc)
|
||||
self.hand -= 1
|
||||
self.current = loc
|
||||
|
||||
def dropArray(self):
|
||||
array = []
|
||||
count = 0
|
||||
current = self.dropLocations[0]
|
||||
for location in self.dropLocations:
|
||||
if self.same(current, location):
|
||||
count += 1
|
||||
else:
|
||||
array.append(count)
|
||||
count = 1
|
||||
current = location
|
||||
array.append(count)
|
||||
return array
|
||||
|
||||
def getEnd(self):
|
||||
return self.dropLocations[-1]
|
||||
|
||||
#get correct image to draw onto the board for each piece
|
||||
def selectPieceImage(value):
|
||||
key = ''
|
||||
if value > 0:
|
||||
key += 'light'
|
||||
else:
|
||||
key += 'dark'
|
||||
if abs(value) == 3:
|
||||
key += 'capstone'
|
||||
elif abs(value) == 2:
|
||||
key += 'wall'
|
||||
else:
|
||||
key += 'flat'
|
||||
return pieceImages[key]
|
||||
|
||||
#render the board as a printable set to show pieces
|
||||
def renderPieces(game, board):
|
||||
for i in range(game.board.size):
|
||||
for j in range(game.board.size):
|
||||
pieceStack = game.board.getLocation([i, j])
|
||||
boardSquare = board.squareCentres[i*board.size+j]
|
||||
coordinate = boardSquare[:2]
|
||||
for x in range(len(pieceStack)):
|
||||
if pieceStack[x] != 0:
|
||||
if abs(pieceStack[x]) == 2:
|
||||
image = pygame.transform.scale(selectPieceImage(pieceStack[x]), (int(board.squareSize*0.2), int(board.squareSize*0.6)))
|
||||
else:
|
||||
image = pygame.transform.scale(selectPieceImage(pieceStack[x]), (int(board.squareSize*0.6), int(board.squareSize*0.6)))
|
||||
win.blit(image, (coordinate[0]+int(board.squareSize*(0.05*(x+1))), coordinate[1]+int(board.squareSize*(0.05*(x+1)))))
|
||||
|
||||
#check to see what button has been pressed
|
||||
def checkButtons(coordinate):
|
||||
for butt in buttons:
|
||||
if butt.x < coordinate[0] < butt.x + butt.width and butt.y < coordinate[1] < butt.y + butt.height:
|
||||
return butt.text
|
||||
|
||||
#render standard font
|
||||
def renderStandard(text):
|
||||
return font.render(text, True, colors['white'])
|
||||
|
||||
#display game results
|
||||
def displayResults():
|
||||
results = game.getEndResults()
|
||||
block = pygame.Surface((250, 160))
|
||||
block.fill(colors['white'])
|
||||
winText = pygame.font.SysFont('Arial', 40).render('Winner!', True, colors['black'])
|
||||
winnerText = pygame.font.SysFont('Arial', 30).render('Player ' + str(results[0]), True, colors['black'])
|
||||
pointText = font.render('Points scored: ' + str(results[1]), True, colors['black'])
|
||||
win.blit(block, (275, 300))
|
||||
win.blit(winText, (320, 310))
|
||||
win.blit(winnerText, (335, 370))
|
||||
win.blit(pointText, (320, 430))
|
||||
|
||||
#display current action
|
||||
def displayAction():
|
||||
actionText = [renderStandard("Current Action:")]
|
||||
if move is not None:
|
||||
actionText.append(renderStandard('Moving'))
|
||||
actionText.append(renderStandard('Holding ' + str(move.hand) + ' from ' + str(move.start)))
|
||||
if move.direction is not None:
|
||||
actionText.append(renderStandard('Dropping'))
|
||||
dropArray = move.dropArray()
|
||||
direction = move.direction
|
||||
for i in range(len(dropArray)):
|
||||
location = move.start[0] + (i+1)*direction[0], move.start[1] + (i+1)*direction[1]
|
||||
actionText.append(renderStandard(str(dropArray[i]) + ' at ' + str(location)))
|
||||
elif type != 0:
|
||||
actionText.append(renderStandard('Placing'))
|
||||
if type == 1:
|
||||
actionText.append(renderStandard('Flat stone'))
|
||||
elif type == 2:
|
||||
actionText.append(renderStandard('Wall'))
|
||||
elif type == 3:
|
||||
actionText.append(renderStandard('Capstone'))
|
||||
else:
|
||||
actionText.append(renderStandard('No current action'))
|
||||
start = (270, 820)
|
||||
for i in range(len(actionText)):
|
||||
win.blit(actionText[i], (start[0], start[1] + i*20))
|
||||
|
||||
#initialize components
|
||||
table = board(5)
|
||||
game = Tak.TakGame(5)
|
||||
pastGames = []
|
||||
|
||||
turnLabel = renderStandard('Current Turn: ')
|
||||
playerLabel = renderStandard('Current Player: ')
|
||||
sizeLabel = renderStandard('Select game size (will reset game):')
|
||||
piecesLabel = renderStandard('Pieces left:')
|
||||
capstonesLabel = renderStandard('Capstones left:')
|
||||
|
||||
flatButton = button(20, 820, 'Flat')
|
||||
wallButton = button(20, 880, 'Wall')
|
||||
capButton = button(20, 940, 'Capstone')
|
||||
moveButton = button(150, 820, 'Move')
|
||||
cancelButton = button(150, 880, 'Cancel')
|
||||
undoButton = button(150, 940, 'Undo')
|
||||
threeButton = button(500, 940, '3', 40, 40)
|
||||
fourButton = button(560, 940, '4', 40, 40)
|
||||
fiveButton = button(620, 940, '5', 40, 40)
|
||||
sixButton = button(680, 940, '6', 40, 40)
|
||||
eightButton = button(740, 940, '8', 40, 40)
|
||||
|
||||
buttons = [flatButton, wallButton, capButton, moveButton, undoButton, cancelButton, threeButton, fourButton,
|
||||
fiveButton, sixButton, eightButton]
|
||||
|
||||
#game loop and initilize game specific settings
|
||||
fps = 60
|
||||
clock = pygame.time.Clock()
|
||||
run = True
|
||||
type = 0
|
||||
location = None
|
||||
buildingMove = False
|
||||
move = None
|
||||
player = 1
|
||||
|
||||
while run:
|
||||
clock.tick(fps)
|
||||
player = 2-(game.turnCount%2)
|
||||
#draw out all the features
|
||||
win.blit(background, (0,0))
|
||||
win.blit(table.bd, table.bd.get_rect())
|
||||
win.blit(turnLabel, (480, 820))
|
||||
win.blit(renderStandard(str(game.turnCount)), (600, 820))
|
||||
win.blit(playerLabel, (640, 820))
|
||||
win.blit(renderStandard(str(player)), (780, 820))
|
||||
win.blit(piecesLabel, (480, 860))
|
||||
win.blit(renderStandard(str(game.piecesLeft(player)[0])), (580, 860))
|
||||
win.blit(capstonesLabel, (640, 860))
|
||||
win.blit(renderStandard(str(game.piecesLeft(player)[1])), (780, 860))
|
||||
win.blit(sizeLabel, (480, 900))
|
||||
renderPieces(game, table)
|
||||
|
||||
#actions on events
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
run = False
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
mouse = pygame.mouse.get_pos()
|
||||
selection = checkButtons(mouse)
|
||||
location = table.checkSquare(mouse)
|
||||
if selection == 'Flat':
|
||||
type = 1
|
||||
elif selection == 'Wall' and game.turnCount > 2:
|
||||
type = 2
|
||||
elif selection == 'Capstone' and game.turnCount > 2:
|
||||
type = 3
|
||||
elif selection == 'Cancel':
|
||||
if move is None:
|
||||
type = 0
|
||||
else:
|
||||
move = None
|
||||
buildingMove = False
|
||||
elif selection == 'Undo':
|
||||
if game.turnCount > 1:
|
||||
game.undo()
|
||||
elif len(pastGames) > 0:
|
||||
last = pastGames.pop()
|
||||
game = last[0]
|
||||
table = last[1]
|
||||
elif selection == 'Move':
|
||||
buildingMove = True
|
||||
elif selection is not None and selection.isdigit():
|
||||
pastGames.append((game, table))
|
||||
game = Tak.TakGame(int(selection))
|
||||
table = board(int(selection))
|
||||
elif type != 0 and location is not None and game.checkLegalPlacement(location):
|
||||
game.actPlace(player, location, type)
|
||||
location = None
|
||||
type = 0
|
||||
elif move is not None and buildingMove:
|
||||
if move.same(move.start, location):
|
||||
move.pickup(location)
|
||||
elif move.hand > 0:
|
||||
move.drop(location)
|
||||
else:
|
||||
game.actMove(move.start, move.getEnd(), move.dropArray())
|
||||
move = None
|
||||
buildingMove = False
|
||||
elif buildingMove and location is not None and game.checkLegalMoveStart(player, location):
|
||||
move = buildMove(location)
|
||||
move.pickup(location)
|
||||
|
||||
#track if we are hovering over buttons and draw them in the correct color
|
||||
mouse = pygame.mouse.get_pos()
|
||||
for butt in buttons:
|
||||
if butt.x < mouse[0] < butt.x + butt.width and butt.y < mouse[1] < butt.y + butt.height:
|
||||
pygame.draw.rect(win, colors['lightGrey'], [butt.x, butt.y, butt.width, butt.height])
|
||||
else:
|
||||
pygame.draw.rect(win, colors['darkGrey'], [butt.x, butt.y, butt.width, butt.height])
|
||||
win.blit(butt.disp, (butt.x + 10, butt.y + int(butt.height/4)))
|
||||
if game.end():
|
||||
displayResults()
|
||||
displayAction()
|
||||
pygame.display.update()
|
||||
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
BIN
images/board.png
Executable file
|
After Width: | Height: | Size: 27 KiB |
51
testActions.py
Executable file
|
|
@ -0,0 +1,51 @@
|
|||
import pytest, AuxiliaryTestingMethods as aux, Actions
|
||||
|
||||
def testPlace(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
Actions.place(takGame.board, [1, 1], 1)
|
||||
assert takGame.board.board[1][1][0] == 1
|
||||
|
||||
def testMove(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
Actions.place(takGame.board, [1, 1], 1)
|
||||
Actions.place(takGame.board, [1, 2], 1)
|
||||
Actions.move(takGame.board, [1, 1], [1, 2], [1])
|
||||
assert takGame.board.board[1][2][0] == 1
|
||||
assert takGame.board.board[1][2][1] == 1
|
||||
assert takGame.board.board[1][1][0] == 0
|
||||
Actions.move(takGame.board, [1, 2], [3, 2], [1,1])
|
||||
assert takGame.board.board[1][2][0] == 0
|
||||
assert takGame.board.board[2][2][0] == 1
|
||||
assert takGame.board.board[3][2][0] == 1
|
||||
|
||||
def testWall(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
Actions.place(takGame.board, [1, 1], 1)
|
||||
Actions.place(takGame.board, [1, 2], 2)
|
||||
with pytest.raises(ValueError):
|
||||
Actions.move(takGame.board, [1,1], [1,2], [1])
|
||||
|
||||
def testCapstone(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
Actions.place(takGame.board, [1, 1], 3)
|
||||
Actions.place(takGame.board, [1, 2], -2)
|
||||
Actions.move(takGame.board, [1, 1], [1, 2], [1])
|
||||
assert takGame.board.board[1][2][0] == -1
|
||||
assert takGame.board.board[1][2][1] == 3
|
||||
|
||||
def testCarryLimit(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
takGame.board.board[1][1] = [1,1,1,1,1,1,1,1,1,1]
|
||||
with pytest.raises(ValueError):
|
||||
Actions.move(takGame.board, [1,1], [1,2], [9])
|
||||
|
||||
def testPiecesLeft(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
Actions.place(takGame.board, [1,1], 3)
|
||||
with pytest.raises(ValueError):
|
||||
Actions.place(takGame.board, [0, 1], 3)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||
52
testBasics.py
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
import pytest
|
||||
|
||||
def testPieceCounts(takGame):
|
||||
size = takGame.board.size
|
||||
pieces = takGame.pieces
|
||||
capstones = takGame.capstones
|
||||
correct = False
|
||||
if size == 8 and pieces == 50 and capstones == 2:
|
||||
correct = True
|
||||
elif size == 7 and pieces == 40 and capstones == 2:
|
||||
correct = True
|
||||
elif size == 6 and pieces == 30 and capstones == 1:
|
||||
correct = True
|
||||
elif size == 5 and pieces == 21 and capstones == 1:
|
||||
correct = True
|
||||
elif size == 4 and pieces == 15 and capstones == 0:
|
||||
correct = True
|
||||
elif size == 3 and pieces == 10 and capstones == 0:
|
||||
correct = True
|
||||
assert correct
|
||||
|
||||
def testIsAdjacent(takGame):
|
||||
res = True
|
||||
size = takGame.board.size
|
||||
testLoc = [size//2, size//2]
|
||||
for i in range(size):
|
||||
for j in range(size):
|
||||
if (((i==size//2 and abs(j-size//2) ==1) or (j==size//2 and abs(i-size//2) == 1))
|
||||
is not takGame.board.isAdjacent(testLoc, [i, j])):
|
||||
res = False
|
||||
assert res
|
||||
|
||||
def testAdjacent(takGame):
|
||||
correct = True
|
||||
location = [1, 1]
|
||||
result = [[0, 1], [1, 0], [1, 2], [2, 1]]
|
||||
testRes = takGame.board.adjacent(location)
|
||||
for loc in result:
|
||||
if loc not in testRes:
|
||||
correct = False
|
||||
location = [0,0]
|
||||
result = [[0, 1], [1, 0]]
|
||||
testRes = takGame.board.adjacent(location)
|
||||
for loc in result:
|
||||
if loc not in testRes:
|
||||
correct = False
|
||||
assert correct
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||
70
testCore.py
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
import pytest, AuxiliaryTestingMethods as aux
|
||||
from copy import deepcopy
|
||||
|
||||
def testLogAction(takGame):
|
||||
board = deepcopy(takGame.board.board)
|
||||
takGame.logAction()
|
||||
assert(takGame.history[-1] == board)
|
||||
|
||||
def testUndo(takGame):
|
||||
board = deepcopy(takGame.board.board)
|
||||
takGame.actPlace(1, [0,0], 1)
|
||||
assert (board != takGame.board.board)
|
||||
takGame.undo()
|
||||
assert(board == takGame.board.board)
|
||||
|
||||
def testGetEndResults(takGame):
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
takGame.turnCount += 1
|
||||
assert(takGame.getEndResults() == (1, 42))
|
||||
|
||||
def testActPlace(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
takGame.actPlace(1, [1,1], 1)
|
||||
assert(takGame.turnCount == 2)
|
||||
assert(takGame.board.board[1][1][0] == -1)
|
||||
|
||||
def testCheckLegalPlacement(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
takGame.actPlace(1, [1,1], 1)
|
||||
assert(takGame.checkLegalPlacement([0,0]))
|
||||
assert(not takGame.checkLegalPlacement([1,1]))
|
||||
|
||||
def testActMove(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
takGame.actMove([0,0], [1,0], [1])
|
||||
assert(takGame.board.board[0][0][0] == 0)
|
||||
assert(takGame.board.board[1][0][0] == 1)
|
||||
assert(takGame.turnCount == 2)
|
||||
|
||||
def testCheckLegalMoveStart(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillSpace(takGame, [2,0], -1)
|
||||
assert(takGame.checkLegalMoveStart(2, [2,0]))
|
||||
assert(not takGame.checkLegalMoveStart(1, [2,0]))
|
||||
|
||||
def testCheckLegalDrop(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillSpace(takGame, [0,0], 3)
|
||||
aux.fillSpace(takGame, [0,1], 2)
|
||||
aux.fillSpace(takGame, [0,2], 1)
|
||||
assert(not takGame.checkLegalDrop([0,0], 1))
|
||||
assert(not takGame.checkLegalDrop([0,0], 2))
|
||||
assert(not takGame.checkLegalDrop([0,0], 3))
|
||||
assert(not takGame.checkLegalDrop([0,1], 1))
|
||||
assert(not takGame.checkLegalDrop([0,1], 2))
|
||||
assert(takGame.checkLegalDrop([0,1], 3))
|
||||
assert(takGame.checkLegalDrop([0,2], 1))
|
||||
|
||||
def testPiecesLeft(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
assert(takGame.piecesLeft(1) == (16, 1))
|
||||
aux.fillSpace(takGame, [1,1], 3)
|
||||
assert(takGame.piecesLeft(1) == (16, 0))
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||
31
testEndCondition.py
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
import pytest, AuxiliaryTestingMethods as aux, End
|
||||
|
||||
def testEndPieces(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
correct = True
|
||||
aux.fillBoardEndPiece(takGame)
|
||||
if not End.end(takGame.board):
|
||||
correct = False
|
||||
assert correct
|
||||
|
||||
def testEndFull(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
correct = True
|
||||
aux.fillBoardEndFull(takGame)
|
||||
if not End.end(takGame.board):
|
||||
correct = False
|
||||
assert correct
|
||||
|
||||
def testEndRoad(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillCol(takGame, 1, 1)
|
||||
assert End.end(takGame.board)
|
||||
|
||||
def testNotEnd(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
assert not End.end(takGame.board)
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||
33
testRoadCondition.py
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
import pytest, AuxiliaryTestingMethods as aux, End
|
||||
|
||||
def testNoRoad(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
ans = End.road(takGame.board)
|
||||
assert not ans[0] and not ans[1]
|
||||
|
||||
def testRoadVertical(takGame):
|
||||
correct = True
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillCol(takGame, 1, 1)
|
||||
ans = End.road(takGame.board)
|
||||
assert ans[0] and not ans[1]
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillCol(takGame, 1, -1)
|
||||
ans = End.road(takGame.board)
|
||||
assert ans[1] and not ans[0]
|
||||
|
||||
def testRoadHorizontal(takGame):
|
||||
correct = True
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 1, 1)
|
||||
ans = End.road(takGame.board)
|
||||
assert ans[0] and not ans[1]
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 1, -1)
|
||||
ans = End.road(takGame.board)
|
||||
assert ans[1] and not ans[0]
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||
45
testWinCondition.py
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
import pytest, AuxiliaryTestingMethods as aux, End
|
||||
|
||||
def testPoints(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
assert End.points(takGame.board, 1) == takGame.board.pieces + takGame.board.capstones + (takGame.board.size**2)
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
aux.fillSpace(takGame, [0, 0], 0)
|
||||
assert End.points(takGame.board, 1) == takGame.board.pieces + takGame.board.capstones + (takGame.board.size**2) - (takGame.board.size-1)
|
||||
aux.fillRow(takGame, 1, -1)
|
||||
aux.fillRow(takGame, 2, -1)
|
||||
assert End.points(takGame.board, 2) == takGame.board.pieces + takGame.board.capstones + (takGame.board.size**2) - (takGame.board.size*2)
|
||||
|
||||
def testWinnerRoad(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
assert End.winRoad(takGame.board, 1) == 1
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, -1)
|
||||
assert End.winRoad(takGame.board, 1) == 2
|
||||
aux.resetBoard(takGame)
|
||||
assert End.winRoad(takGame.board, 1) == False
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
aux.fillRow(takGame, 1, -1)
|
||||
assert End.winRoad(takGame.board, 1) == 1
|
||||
assert End.winRoad(takGame.board, 2) == 2
|
||||
|
||||
def testWinnerOther(takGame):
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
aux.fillRow(takGame, 1, 1)
|
||||
aux.fillCol(takGame, takGame.board.size-1, 0)
|
||||
assert End.winner(takGame.board) == 1
|
||||
aux.resetBoard(takGame)
|
||||
aux.fillRow(takGame, 0, -1)
|
||||
aux.fillRow(takGame, 1, -1)
|
||||
aux.fillCol(takGame, takGame.board.size-1, 0)
|
||||
assert End.winner(takGame.board) == 2
|
||||
aux.fillRow(takGame, 0, 1)
|
||||
aux.fillSpace(takGame, [0, takGame.board.size-1], 0)
|
||||
assert End.winner(takGame.board) == 2
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def takGame():
|
||||
import Tak
|
||||
return Tak.TakGame(5)
|
||||