I'm making chess in python. It was all working and I had the moves as a list of indexes but I decided to use a class instead as I thought this would be better. However, now the function to get all the legal moves doesn't seem to work and I've found that this is because for some reason it thinks it can move a pawn from a4 to a5 on the starting board and I think this could be because it doesn't change the position back to the normal position after checking a2 to a4 but does move it on the board which is made up of a list of lists however I cannot find why. The error is caused by the code in lines 379-387 which stops you making a move if it puts you in check because when I comment it out there's no error. I've been searching for hours so if someone could help then it would be much appreciated. Also any other feedback would be helpful.
Exceptions.py
# Base class for other exceptions
pass
class NoPieceThereError(Error):
# When there's no piece on the selected tile
pass
class InvalidFENError(Error):
# When the inputed FEN is invalid
pass
class WrongPieceColour(Error):
# Chose the wrong piece colour
pass
class InvalidMove(Error):
# Not a legal move
pass
class InvalidInput(Error):
pass
class KingNotFound(Error):
pass
Chess.py
import random
alphabet = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z".split()
def IsInt(number):
try:
int(number)
return True
except:
return False #returns True if the input is a number
def AddTuples(tuple1, tuple2):
return tuple([x + y for x, y in zip(tuple1, tuple2)])
def MultiplyTuple(tuple1, multiplyer):
return tuple([int(x * multiplyer) for x in tuple1])
def PositionToIndex(position):
try:
row = int(position[1]) - 1
column = alphabet.index(position[0].upper())
return (row, column) # Converts a position "e2" to an index "(1, 4)"
except:
raise Exceptions.InvalidInput
def IndexToPosition(index):
try:
row = str(index[0] + 1)
column = alphabet[index[1]].lower()
return column + row # Converts an index "(1, 4)" to a position "e2"
except:
raise Exceptions.InvalidInput
class FEN():
def __init__(self, passed_FEN):
passed_FEN = passed_FEN.split()
if len(passed_FEN) != 6:
raise Exceptions.InvalidFENError
self.board_FEN = passed_FEN[0]
self.turn = passed_FEN[1]
self.castling = passed_FEN[2]
self.en_passant = passed_FEN[3]
self.half_move_clock = passed_FEN[4]
self.full_move_clock = passed_FEN[5]
def __repr__(self):
return " ".join([
self.board_FEN,
self.turn,
self.castling,
self.en_passant,
self.half_move_clock,
self.full_move_clock
])
def ChangeTurn(self):
self.turn = "b" if self.turn == "w" else "w"
#property
def board_FEN_split(self):
return self.board_FEN.split("/")
class Move():
def __init__(self, start_row, start_column, end_row, end_column, capturing_piece, capturing_row, capturing_column, FEN_before):
self.start_row = start_row
self.start_column = start_column
self.end_row = end_row
self.end_column = end_column
self.capturing = capturing_piece
self.capturing_row = capturing_row
self.capturing_column = capturing_column
self.FEN_before = FEN_before
#property
def start(self):
return (self.start_row, self.start_column)
#property
def end(self):
return (self.end_row, self.end_column)
#property
def capturing_pos(self):
return (self.capturing_row, self.capturing_column)
def __repr__(self):
if self.capturing != None:
string = f" capturing {self.capturing.__repr__()} at {IndexToPosition(self.capturing_pos)}"
else:
string = ""
return f"Piece moved from {IndexToPosition(self.start)} to {IndexToPosition(self.end)}" + string + f", FEN before: {self.FEN_before}"
def __eq__(self, other):
return True if self.__repr__() == other.__repr__() else False
#property
def taking_equals_moved(self):
return True if None == self.capturing_row == self.capturing_column or self.capturing_row == self.end_row and self.capturing_column == self.end_column else False
"""
class Engine():
piece_values = {
"p": 1,
"n": 3,
"b": 3,
"r": 5,
"q": 9
}
#staticmethod
def EvaluatePosition(board):
total = 0
for row in board.board:
for cell in row:
if cell != None:
if cell.__repr__().lower() in Engine.piece_values:
if cell.__repr__().islower():
total -= Engine.piece_values[cell.__repr__()]
else:
total += Engine.piece_values[cell.__repr__().lower()]
return total
#staticmethod
def ChooseComputerMove(board):
move = random.choice(board.GetAllLegalMoves())
board.MovePiece(*move)
#staticmethod
def Search(board, depth=10, alpha=0, beta=0):
if depth == 0:
return Engine.EvaluatePosition(board)
moves = board.GetAllLegalMoves()
if len(moves) == 0:
if board.IsInCheck(board.FEN.turn):
return -10000
return 0
for move in moves:
board.MovePiece(*move)
evaluation = -Engine.Search(board, depth-1, -beta, -alpha)
board.UnmakeMove()
if evaluation >= beta:
# Move was too good so the opponent will avoid this position
return beta
alpha = max(alpha, evaluation)
return alpha
"""
class Board():
def __init__(self,
passed_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
extra_pieces = [],
board_height = 8,
board_width = 8
):
pieces = [
#default pieces
('p', 'Pawn', Pawn),
('r', 'Rook', Rook),
('n', 'Knight', Knight),
('b', 'Bishop', Bishop),
('q', 'Queen', Queen),
('k', 'King', King),
] + extra_pieces #any extra piece types
self.pieces_letters, self.pieces_names, self.pieces_classes = [tuple([piece[x] for piece in pieces]) for x in range(3)]
self.FEN = FEN(passed_FEN)
self.move_list = []
self.board = []
self.board_height = board_height
self.board_width = board_width
for row_index, row in enumerate(self.FEN.board_FEN_split[::-1]):
self.board.append([])
cell_index = 0
for cell in row:
if IsInt(cell):
[self.board[-1].append(None) for x in range(int(cell))]
cell_index += int(cell)
else:
self.board[-1].append(self.CreatePiece(cell, (row_index, cell_index)))
cell_index += 1
def CreatePiece(self, piece_code, position):
piece_name = self.pieces_classes[self.pieces_letters.index(piece_code.lower())]
colour = "w" if piece_code.upper() == piece_code else "b"
return piece_name(colour, position, self)
def DisplayBoard(self, debug = False):
print()
print()
for index, column in enumerate(self.board[::-1]):
if debug:
print(7 - index, end = " ")
else:
print(8 - index, end = " ")
print(" | ".join(" " if x == None else x.__repr__() for x in column))
print("-" * 4 * self.board_width)
print(" ", end = "")
if debug:
print(" | ".join([str(x) for x in range(self.board_width)]))
else:
print(" | ".join(alphabet[:self.board_width]))
def GetBoardValue(self, row, column):
return self.board[row][column]
def FindKing(self, colour):
for rowi, row in enumerate(self.board):
for celli, cell in enumerate(row):
if cell != None:
if cell.type == "King" and cell.colour == colour:
return (rowi, celli)
raise Exceptions.KingNotFound
def IsInCheck(self, colour):
for row in self.board:
for cell in row:
if cell != None:
if cell.colour != colour:
if cell.IsChecking():
return True
return False
def GetAllLegalMoves(self):
LegalMoves = []
for row in self.board:
for cell in row:
if cell != None:
if cell.colour == self.FEN.turn:
LegalMoves += cell.LegalMoves()
return LegalMoves
def FindMove(self, moves = None, start_row = "*", start_column = "*", end_row = "*", end_column = "*"):
if moves == None:
moves = self.GetAllLegalMoves()
for move in moves:
if (
(start_row == "*" or start_row == move.start_row) and
(start_column == "*" or start_column == move.start_column) and
(end_row == "*" or end_row == move.end_row) and
(end_column == "*" or end_column == move.end_column)
):
return move
raise Exceptions.InvalidInput
def MakeMove(self, move):
self.move_list.append(move)
# Changing en passant FEN
if self.board[move.start_row][move.start_column].__repr__().lower() == "p" and abs(move.start_row - move.end_row) == 2:
self.FEN.en_passant = IndexToPosition(((move.start_row + move.end_row) / 2, move.end_column))
else:
self.FEN.en_passant = "-"
# Move piece
print(move)
self.board[move.start_row][move.start_row].position = move.end
self.board[move.end_row][move.end_column] = self.board[move.start_row][move.start_column]
self.board[move.start_row][move.start_column] = None
# If taking a piece not at the location it moved to i.e. en passant
if not move.taking_equals_moved:
self.board[capturing_row][capturing_column] = None
def UnmakeMove(self, number_to_undo=1):
for x in range(number_to_undo):
if self.move_list == []:
print(f"No more moves to undo. Only undid {x} moves")
return
move = self.move_list.pop()
# Move piece back
self.board[move.end_row][move.end_column].position = move.start
self.board[move.start_row][move.start_column] = self.board[move.end_row][move.end_column]
self.board[move.end_row][move.end_column] = None
# Restore captured piece
if move.capturing != None:
self.board[move.capturing_row][move.capturing_column] = move.capturing
# Restore FEN
self.FEN = move.FEN_before
def OnBoard(self, row, column):
return True if 0 <= row < self.board_height and 0 <= column < self.board_width else False
class Piece():
def __init__(self, colour, position, board):
self.colour = colour
self.position = position
self.board = board
def SimilarMoves(self, directions, *args, **kwargs):
legal_moves = []
for direction in directions:
legal_moves += self.CheckForCollision(direction, *args, **kwargs)
return legal_moves
def CheckForCollision(self, direction, limit, must_capture = False, can_capture = True, can_capture_en_passant = False, current_turn = False):
legal_moves = []
checks = 1
current_pos = self.position
while checks <= limit or limit == 0:
current_pos = AddTuples(current_pos, direction)
#if off the board
if not self.board.OnBoard(*current_pos):
break
current_pos_piece = self.GetBoardValue(*current_pos)
#if moving to an empty square
if current_pos_piece == None:
#capturing en passant
#if there is an en passant somewhere and the piece is allowed to capture en passant
if can_capture_en_passant and self.board.FEN.en_passant != "-":
#if it's capturing the en passant square
if PositionToIndex(self.board.FEN.en_passant) == current_pos:
#if it not capturing it's own piece
en_passant_start = self.board.board_height - 4 if self.colour == "w" else 3
if self.position[0] == en_passant_start:
move = Move(
*self.position,
*current_pos,
self.GetBoardValue(en_passant_start, current_pos[1]),
en_passant_start, current_pos[1],
FEN(self.board.FEN.__repr__()))
legal_moves.append(move)
#moving to empty space
elif not must_capture:
legal_moves.append(Move(
*self.position,
*current_pos,
self.GetBoardValue(*current_pos),
None, None,
FEN(self.board.FEN.__repr__())))
#moving to own piece colour
elif self.colour == current_pos_piece.colour:
break
#moving to opponent piece colour
elif self.colour != current_pos_piece.colour:
if can_capture:
legal_moves.append(Move(
*self.position,
*current_pos,
self.board.GetBoardValue(*current_pos),
*current_pos,
FEN(self.board.FEN.__repr__())
))
break
checks += 1
if current_turn == True:
index = 0
while index < len(legal_moves):
self.board.MakeMove(legal_moves[index])
if self.board.IsInCheck(self.colour):
legal_moves.pop(index)
else:
index += 1
self.board.UnmakeMove()
return legal_moves
#property
def row(self):
return self.position[0]
#property
def column(self):
return self.position[1]
def __repr__(self):
letter = self.board.pieces_letters[self.board.pieces_names.index(self.type)]
return letter.upper() if self.colour == "w" else letter
def IsEmpty(self, row, column):
return True if self.GetBoardValue(row, column) == None else False
def GetBoardValue(self, row, column):
return self.board.GetBoardValue(row, column)
#property
def direction(self):
if self.colour == "w":
return 1
else:
return -1
#property
def enemy_colour(self):
if self.colour == "w":
return "b"
else:
return "w"
def CheckCorrectTurn(self):
return True if self.colour == self.board.FEN.turn else False
def IsChecking(self):
enemy_king_pos = self.board.FindKing(self.enemy_colour)
moves = self.LegalMoves(current_turn = False)
for move in moves:
if move == enemy_king_pos:
return True
return False
class Pawn(Piece):
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "Pawn"
def LegalMoves(self, current_turn = True):
legal_moves = []
print(self.position)
on_starting_row = self.row == 1 and self.colour == 'w' or self.row == self.board.board_height - 2 and self.colour == "b"
#forwards
limit = 2 if on_starting_row else 1
legal_moves += self.CheckForCollision((self.direction, 0), limit, can_capture = False, current_turn=current_turn)
#capturing
capturing_directions = ((self.direction, 1), (self.direction, -1))
legal_moves += self.SimilarMoves(capturing_directions, 1, must_capture = True, can_capture_en_passant = True, current_turn=current_turn)
return legal_moves
class Rook(Piece):
directions = ((1, 0), (0, 1), (-1, 0), (0, -1))
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "Rook"
def LegalMoves(self, current_turn = True):
legal_moves = self.SimilarMoves(self.directions, 0, current_turn=current_turn)
return legal_moves
class Knight(Piece):
directions = ((2, 1), (1, 2), (-1, 2), (-2, 1), (-2, -1), (-1, -2), (1, -2), (2, -1))
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "Knight"
def LegalMoves(self, current_turn = True):
legal_moves = self.SimilarMoves(self.directions, 1, current_turn=current_turn)
return legal_moves
class Bishop(Piece):
directions = ((1, 1), (-1, 1), (-1, -1), (1, -1))
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "Bishop"
def LegalMoves(self, current_turn = True):
legal_moves = self.SimilarMoves(self.directions, 0, current_turn=current_turn)
return legal_moves
class King(Piece):
directions = Rook.directions + Bishop.directions
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "King"
def LegalMoves(self, current_turn = True):
legal_moves = self.SimilarMoves(self.directions, 1, current_turn=current_turn)
return legal_moves
class Queen(Piece):
directions = Rook.directions + Bishop.directions
def __init__(self, colour, position, board):
super().__init__(colour, position, board)
self.type = "Queen"
def LegalMoves(self, current_turn = True):
legal_moves = self.SimilarMoves(self.directions, 0, current_turn=current_turn)
return legal_moves
def main():
entered_FEN_valid = False
while not entered_FEN_valid:
try:
player_FEN = input("Would you like to play with a custom FEN. If so put it here, or press enter for a default board: ")
if not player_FEN:
player_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
b = Board(player_FEN)
entered_FEN_valid = True
except Exceptions.InvalidFENError:
print("Invalid FEN")
#no longer needed as I added Smith --> print("Moves are entered in the form \"{row} {column}\" with row and column being numbers from 0-7. Bottom left is 0 0. Example input: \"1 4\"")
debug = False # True if input("Debug Mode? (Y/N): ").lower() == "y" else False
player_colour = "w"
player_won = False
apawn = b.board[1][0]
while not player_won:
#if len(b.GetAllLegalMoves()) == 0:
# player_won = True
# print(b.IsInCheck("b"))
# if b.IsInCheck(b.FEN.turn):
# player_who_won = "w" if b.FEN.turn == "b" else "b"
# else:
# player_who_won = "no one"
# break
try:
if True: #b.FEN.turn == player_colour:
b.DisplayBoard(debug)
#print(Engine.Search(b, depth = 20))
#print("\n".join([x.__repr__() for x in b.move_list]))
#print([[IndexToPosition(position) for position in move] for move in b.GetAllLegalMoves()])
#print(len(b.GetAllLegalMoves()))
start = input("\nEnter start: ")
if start.lower()[:4] == "undo":
b.UnmakeMove(int(start[-1]))
else:
start = PositionToIndex(start)
if b.GetBoardValue(*start) == None:
raise Exceptions.NoPieceThereError
moves = b.GetBoardValue(*start).LegalMoves()
if moves == []:
raise Exceptions.WrongPieceColour
print("Legal moves: \n" + str([IndexToPosition((x.end_row, x.end_column)) for x in moves]))
end = PositionToIndex(input("\nEnter end: "))
print(start, end)
b.MakeMove(b.FindMove(
moves = moves,
start_row = start[0],
start_column = start[1],
end_row = end[0],
end_column = end[1]))
else:
Engine.ChooseComputerMove(b)
except Exceptions.NoPieceThereError:
print("There is no piece there")
except Exceptions.WrongPieceColour:
print("That is not the correct piece colour")
except Exceptions.InvalidMove:
print("That is not a legal move")
#except Exceptions.InvalidInput:
# print("Invalid input")
#except:
# print("Unknown error")
print(player_who_won, "won!")
if __name__ == "__main__":
#main()
b = Board()
print(b.GetAllLegalMoves())
So I found that the positions of the pieces kept changing randomly so I just made it a property of the Piece class that finds it each time
class Piece():
#property
def position(self):
for rowi, row in enumerate(self.board.board):
for celli, cell in enumerate(row):
if cell == self:
return (rowi, celli)
I'm trying solve N Puzzle with Depth First Search using python 3.
With 3 x 3 puzzle it run good and fast but with 4 x 4 puzzle, it runs too slow and can't find solution with error: "MemoryError".
I also use "h(n) = depth + number of wrong tiles" to evaluate priority of each node.
I'm a newbie to python so hope you can help me with this
Here is my code:
import sys
import getopt
import random
import time
class State:
def __init__(self, parent, board, move, depth):
self.parent = parent
self.previousMove = move
self.board = board
self.map = ''.join(str(e) for e in board)
self.depth = depth
self.cost = self.calculateCost()
def calculateCost(self):
pos = 1
count = 0
for tile in self.board:
if tile == pos:
count += 1
pos += 1
return self.depth + 8 - count
class Puzzle:
def __init__(self, k, customBoard = None):
self.k = k
self.n = k*k - 1
self.sizeOfBoard = k*k
self.timeOfSolving = 0
self.timeOfGenerateSuccessors = 0
self.maxDeepSearch = 0
self.inititalState = State(None, self.createInitialBoard(customBoard), 'Start', 0)
self.goalBoard = self.createGoalBoard()
self.finalState = None
self.stateStorage = set() # Store states that have visited
self.path = [] # Store states that lead to goalstate
self.stack = []
def isSolvable(self, board):
# count invertion in puzzle's board
invCount = 0
for i in range(0, self.sizeOfBoard - 1):
if board[i] == 0:
continue
for j in range(i+1, self.sizeOfBoard):
if board[j] == 0:
continue
if board[i] > board[j]:
invCount += 1
# print(invCount)
if (invCount % 2 == 0):
return True
return False
def createInitialBoard(self, customBoard):
print("Creating initial state")
if customBoard is None:
board = []
lstAddSuccess = []
while 1:
board.clear()
lstAddSuccess.clear()
for count in range(0, self.k*self.k):
newTile = random.randint(0, self.n)
while newTile in lstAddSuccess:
newTile = random.randint(0, self.n)
lstAddSuccess += [newTile]
board += [newTile]
if self.isSolvable(board):
break
else:
board = [int(e) for e in customBoard]
if not self.isSolvable(board):
print("Cant find solution with this puzzle! Exiting...")
exit(-1)
return board
def createGoalBoard(self):
board = []
for count in range(1, self.n + 1):
board += [count]
board += [0]
return board
def printBoard(self, board):
for row in range(0, self.sizeOfBoard, self.k):
# for col in range(row, row + self.k):
print(board[row:row + self.k])
def generateSuccessors(self, currentState):
indexOfZero = currentState.board.index(0)
rowIndexOfZero = indexOfZero % self.k
colIndexOfZero = indexOfZero // self.k
lstSuccessors = []
# Slide to zero to up
if colIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - self.k]
newState[indexOfZero - self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'up', currentState.depth + 1))
# Slide zero to down
if colIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + self.k]
newState[indexOfZero + self.k] = 0
lstSuccessors.append(
State(currentState, newState, 'down', currentState.depth + 1))
# slide zero to left
if rowIndexOfZero != 0:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero - 1]
newState[indexOfZero - 1] = 0
lstSuccessors.append(
State(currentState, newState, 'left', currentState.depth + 1))
# Slide zero to right
if rowIndexOfZero != self.k - 1:
newState = currentState.board.copy()
newState[indexOfZero] = newState[indexOfZero + 1]
newState[indexOfZero + 1] = 0
lstSuccessors.append(
State(currentState, newState, 'right', currentState.depth + 1))
lstSuccessorsCost = [ele.cost for ele in lstSuccessors]
lstSuccessorsInOrderOfCost = []
for i in range(0, len(lstSuccessorsCost)):
lstSuccessorsInOrderOfCost.append(lstSuccessors[lstSuccessorsCost.index(min(lstSuccessorsCost))])
lstSuccessorsCost[lstSuccessorsCost.index(min(lstSuccessorsCost))] = 100
return lstSuccessorsInOrderOfCost
def solvePuzzle(self, currentState):
self.stack.append(currentState)
self.stateStorage.add(currentState.map)
while len(self.stack) > 0:
currentState = self.stack.pop()
if currentState.board == self.goalBoard:
# find path
# self.printBoard(currentState.board)
self.finalState = currentState
print("Solving " + str(self.n) + " puzzle done!")
return
start_time_gen = time.time()
lstSuccessor = self.generateSuccessors(currentState)
end_time_gen = time.time()
timeOfGen = end_time_gen - start_time_gen
self.timeOfGenerateSuccessors += timeOfGen
for successor in lstSuccessor[::-1]:
if successor.map not in self.stateStorage:
self.stack.append(successor)
self.stateStorage.add(successor.map)
if successor.depth > self.maxDeepSearch:
self.maxDeepSearch += 1
print("Cant solve puzzle! Exiting...")
exit(-1)
def solve(self):
start_time = time.time()
self.solvePuzzle(self.inititalState)
end_time = time.time()
self.timeOfSolving = end_time - start_time
print("Running time: " + str(self.timeOfSolving))
print("Max Search Dept: " + str(self.maxDeepSearch))
print("Final State Dept: " + str(self.finalState.depth))
def printInitialBoard(self):
self.printBoard(self.inititalState.board)
def printPath(self):
if self.finalState is None:
print("No solution found!")
return
path = []
state = self.finalState
while (state is not None):
if state.previousMove is not None:
path.append(state.previousMove)
state = state.parent
print("path: "),
print(path[::-1])
def main(argv):
# if (len(argv) != 1 or int(argv[0]) not in range(1, 10000)):
# print("Input must be k of integer, which is k*k matrix of puzzle")
# exit()
# eight_puzzle = Puzzle(int(argv[0]))
k = int(input("Enter size of k * k puzzle, k = "))
while k not in range(2, 100):
print("k must be in range 2 - 100")
k = int(input("Enter size of k * k puzzle, k = "))
print("""
Choose:
1. Randome puzzle
2. Custome puzzle
""")
file = input()
if int(file) == 1:
puzzle = Puzzle(k)
elif int(file) == 2:
board = input("Enter puzzle: ")
puzzle = Puzzle(k ,list(board.split(" ")))
puzzle.printInitialBoard()
puzzle.solve()
puzzle.printPath()
if __name__ == "__main__":
main(sys.argv[1:])
All code
import random
import time
class Enemy():
def __init__(self):
self.health = 100
self.power = random.randint(10,20)
def hit(self, player):
player.health -= self.power
class player():
def __init__(self):
self.health = 300
self.power = 50
def hit(self, Enemy):
Enemy.health -= self.power
player1 = player()
enemies = []
for i in range(5): # create 5 enemy
enemies.append(Enemy())
print("Play - Help - Quit")
action1 = input("Type 'hit' for enemies\n>>>> ")
while action1 != 'q':
print("---------------")
for i in range(len(enemies)):
print("#{}.enemy heatlh-->{}".format(i, enemies[i].health))
print("----------------")
random_enemy = random.randint(1, 5)
action = input(">>>> ")
if action == 'hit':
which = int(input("Which enemy? there are {} enemies\n>>>>".format(len(enemies))))
if enemies[which].health == 0:
enemies[which].health = 0
print("\nThis is a death enemy")
else:
player1.hit(enemies[which])
damage_enemy = random.randint(1,5)
if enemies[random_enemy].health == 0:
continue
else:
if damage_enemy == 1 or damage_enemy == 3 or damage_enemy == 4:
if enemies[which].health == 0 or enemies[which].health <= 0:
enemies[which].health = 0
print("{}. enemy death HP: {} ".format(which, enemies[which].health))
else:
enemies[random_enemy].hit(player1)
print("{}. enemy hit you {} damage, your HP: {} ".format(random_enemy,enemies[random_enemy].power,player1.health))
elif enemies[which].health != 0 or enemies[which].health >= 0:
print("{}. enemy HP: {} ".format(which, enemies[which].health))
elif action == 'q':
break
I get this error at random time, my list size is 5, enemies die and their healths are 0. They stay there, but for some reason sometimes I get this error.
#0.enemy heatlh-->100
#1.enemy heatlh-->100
#2.enemy heatlh-->0
#3.enemy heatlh-->0
#4.enemy heatlh-->100
if enemies[random_enemy].health == 0:
continue
The random.randint(1, 5) can return 5. Your list has 5 elements, but the indices are from 0 to 4.
P.S. Also, the minimum value that you get is 1. Not 0.
We are making this Black Jack program to test card counting methods. We are trying to get the auto play function working, and it does, but when we run it in a while loop the loop never finishes and exits.
"""
Eli Byers
Josh Rondash
Black_Jack.py
"""
import random
#---------- CLASSES -----------------------------------------------------------
class Card(object):
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
self.value = 0
if self.rank is "Ace":
self.value = 11
if self.rank.isdigit():
self.value = int(self.rank)
if self.rank in ["Jack", "Queen", "King"]:
self.value = 10
def __str__(self):
return "["+str(self.rank)+" "+str(self.suit)+"]"
class Deck(object):
def __init__(self, numofdecks):
self.deck = []
self.suit = [" Clubs", " Hearts", " Spades", " Diamonds"]
self.rank = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
self.numofdecks = numofdecks
for i in range(self.numofdecks):
for r in self.rank:
for s in self.suit:
self.deck.append(Card(r,s))
def __str__(self):
deck_str = ""
for card in self.deck:
deck_str += str(card)+" "
deck_str = deck_str[:-1]
return deck_str
def __len__(self):
return len(self.deck)
def __getitem__(self,i):
return self.deck[i]
def __delitem__(self, i):
del self.deck[i]
def draw(self):
top_card = self.deck[0]
del self.deck[0]
return top_card
def addcard(self,card):
self.deck.append(card)
def shuffle(self): #Random shuffle function
a = len(self.deck)
b = a-1
for d in range(b,0,-1):
e = random.randint(0,d)
if e == d:
continue
self.deck[d],self.deck[e] = self.deck[e],self.deck[d]
return self.deck
class Player(object):
def __init__(self, bankroll):
self.hand = []
self.bankroll = bankroll
self.score = 0
self.bet = 0
self.count = 0
self.aces = 0
self.dealer_hand = []
def __str__(self):
hand = ""
for card in self.hand:
hand += str(card)+" "
return "Hand: "+hand+" Bank: "+str(self.bankroll)+" Bet: "+str(self.bet)+" Ct: "+str(self.count)+" A: "+str(self.aces)
def __getitem__(self, i):
return self.hand[i]
def getcard(self,Card):
self.hand.append(Card)
self.score = 0
ace = 0
for card in self.hand:
if card.rank == "Ace":
ace += 1
self.score += 1
else:
self.score += card.value
for a in range(ace):
if (self.score + 10) <= 21:
self.score += 10
self.updateCount(Card,"P")
def placebet(self, b=0):
if b != 0:
self.bankroll -= b
self.bet += b
else:
self.bet += input("Bankroll: "+str(self.bankroll)+" Ct: "+str(self.count)+" A: "+str(self.aces)+" Place bet: ")
self.bankroll -= self.bet
def updateCount(self, card, player):
if card.value in range(2,6):
self.count += 1
elif card.value is 10:
self.count -= 1
elif card.rank is "Ace":
self.aces += 1
if player == "D":
self.dealer_hand.append(card)
def makeBet(self):
bet = 0.1*self.bankroll
if self.count > 3:
c = 0
for i in range(self.count):
c += 1
if c == 3:
bet += 0.5 * bet
c = 0
elif self.count < -3:
bet -= 0.5 * bet
return bet
def Play(self):
if self.score < 17:
choice = 1 #hit
else:
choice = 2 #stand
return choice
class Dealer(object):
def __init__(self, Deck, discardpile, Player):
self.deck = Deck
self.discardpile = discardpile
self.player = Player
self.hand = []
self.score = 0
def __str__(self):
hand = ""
for card in self.hand:
hand += str(card)+" "
return "Dealer Hand: "+hand
def __getitem__(self, i):
return self.deck[i]
def draw(self):
cardval = self.deck.draw()
self.hand.append(cardval)
self.score = 0
ace = 0
for card in self.hand:
if card.rank == "Ace":
ace += 1
self.score += 1
else:
self.score += card.value
for a in range(ace):
if (self.score + 10) <= 21:
self.score += 10
player.updateCount(cardval,"D")
def deal(self, Player):
for i in range(2):
self.player.getcard(self.deck.draw())
self.draw()
def burn(self):
self.discardpile.addcard(self.deck.draw())
def blackjack(self):
if self.score == 21:
return True
else:
return False
class Table(Dealer, Player):
def __init__(self, Dealer, Player, Deck , discardpile):
self.dealer = Dealer
self.player = Player
self.deck = Deck
self.discardpile = discardpile
self.betplaced = 0
def initGame(self):
self.clearTable()
Deck.shuffle(self.deck)
self.dealer.burn()
def clearTable(self):
for card in self.player.hand:
self.discardpile.addcard(card)
for card in self.dealer.hand:
self.discardpile.addcard(card)
self.player.hand = []
self.dealer.hand = []
def playGame(self):
self.betplaced = self.player.placebet()
self.dealer.deal(self.player)
print self.player
print self.dealer
if self.dealer.blackjack():
print("Dealer Black Jack!")
elif self.player.score <= 21:
stand = 0
while self.player.score < 21 and stand == 0:
print("Use number Keys> Hit: 1 Stand: 2")
choice = input()
if choice == 1: # Hit
self.player.getcard(self.deck.draw())
elif choice == 2: # Stand
stand = 1
print self.player
print ("Your score is "+str(self.player.score))
while self.dealer.score <= 17 and self.player.score <= 21:
if self.dealer.score == 17:
for card in self.dealer.hand:
if card.rank == "Ace":
self.dealer.draw()
else:
self.dealer.draw()
print self.dealer
print ("Dealer score is "+str(self.dealer.score))
if self.dealer.score <= 21:
if (self.player.score > self.dealer.score) and (self.player.score <= 21) :
if self.player.score == 21:
self.player.bankroll += self.player.bet*2.5
else:
self.player.bankroll += self.player.bet*2
print ("Win")
elif self.player.score == self.dealer.score:
self.player.bankroll += self.player.bet
print("Push")
else:
print("You Lose")
elif (self.dealer.score > 21) and (self.player.score <= 21):
if self.player.score == 21:
self.player.bankroll += self.player.bet*2.5
else:
self.player.bankroll += self.player.bet*2
print ("Win")
else:
print("You Lose.")
self.player.bet = 0
self.player.dealer_hand = []
print
def autoPlay(self):
self.betplaced = self.player.placebet(int(self.player.makeBet()))
self.dealer.deal(self.player)
if (self.dealer.blackjack() == False) and (self.player.score <= 21):
stand = 0
while self.player.score < 21 and stand == 0:
choice = player.Play()
if choice == 1: # Hit
self.player.getcard(self.deck.draw())
elif choice == 2: # Stand
stand = 1
while self.dealer.score <= 17 and self.player.score <= 21:
if self.dealer.score == 17:
for card in self.dealer.hand:
if card.rank == "Ace":
self.dealer.draw()
else:
self.dealer.draw()
if self.dealer.score <= 21:
if (self.player.score > self.dealer.score) and (self.player.score <= 21):
if self.player.score == 21:
self.player.bankroll += self.player.bet*2.5
else:
self.player.bankroll += self.player.bet*2
print ("Win")
elif self.player.score == self.dealer.score:
self.player.bankroll += self.player.bet
print("Push")
else:
print("Lose")
elif (self.dealer.score > 21) and (self.player.score <= 21):
if self.player.score == 21:
self.player.bankroll += self.player.bet*2.5
else:
self.player.bankroll += self.player.bet*2
print ("Win")
else:
print("Lose")
self.player.bet = 0
self.player.dealer_hand = []
print self.player.bankroll
#----------- MAIN -----------------------------------
deck = Deck(6)
player = Player(500)
discardpile = Deck(0)
dealer = Dealer(deck, discardpile, player)
table = Table(dealer, player, deck, discardpile)
table.initGame()
while (player.bankroll > 0) and (player.bankroll < 1000):
table.autoPlay()
table.clearTable()
print "Game Over."
Just add some debug statements. You have multiple while loops in your methods. I'm sure a simple print statement will catch the errors in your logic.
DUDE, I found the infinite loop within 1 minute. lucky i had python installed on my box.
LINE 251
if (self.dealer.blackjack() == False) and (self.player.score <= 21):
stand = 0
while self.player.score < 21 and stand == 0:
print "in player score"
choice = player.Play()
if choice == 1: # Hit
self.player.getcard(self.deck.draw())
elif choice == 2: # Stand
stand = 1
while self.dealer.score <= 17 and self.player.score <= 21:
print "in dealer score"
print self.dealer.score
if self.dealer.score == 17:
for card in self.dealer.hand:
if card.rank == "Ace":
self.dealer.draw()
else:
self.dealer.draw()
After completely failing the minimax implementation for tic tac toe, I fail to see what's wrong. Right now, my AI just goes around in a circle...
import collections
class InvalidLocationError(Exception): pass
import copy
class Board(object):
def __init__(self, board=None):
if board is None:
self.clear()
else:
self._board = board[:]
def place(self, i, row, column):
if not ((0 <= row <= 2) and (0 <= column <= 2)):
raise InvalidLocationError("Invalid Location.")
if self._board[row][column]:
raise InvalidLocationError("There's already a piece there")
self._board[row][column] = i
return self.checkVictory()
def check(self, row, column):
return self._board[row][column]
def checkVictory(self, board=None):
if board is None:
board = self._board
draw = True
for i in xrange(3):
r = self.rowcount(i)
c = self.colcount(i)
if i < 3:
d = self.diagcount(i)
else:
d = {0: 0, 1: 0, 2: 0}
for j in xrange(1, 3):
if d[j] == 3 or r[j] == 3 or c[j] == 3:
return j
if r[0] > 0 or c[0] > 0:
draw = False
if draw:
return -1
return 0
def rowcount(self, row):
return collections.Counter(self._board[row])
def colcount(self, col):
return collections.Counter([self._board[i][col] for i in xrange(3)])
def diagcount(self, left=True):
if left:
a = [self._board[0][0], self._board[1][1], self._board[2][2]]
else:
a = [self._board[0][2], self._board[1][1], self._board[2][0]]
return collections.Counter(a)
def clear(self):
self._board = ([0, 0, 0], [0, 0, 0], [0, 0, 0])
def __str__(self):
return "\n".join(map(lambda x: " ".join(map(lambda y : str(y), x)), self._board))
#staticmethod
def flipPiece(p):
return int(not (p - 1)) + 1
class AI(object):
class Node(object):
def __init__(self, board, nextMove):
self.board = board
self.nextMove = nextMove
self.paths = []
self.score = None
template = self.board._board[:]
for r, row in enumerate(template):
for c, val in enumerate(row):
if val == 0:
template[r][c] = nextMove
self.paths.append(copy.deepcopy(template))
template[r][c] = 0
def __init__(self, mypiece, depth=8):
self.mypiece = mypiece
self.enemypiece = Board.flipPiece(mypiece)
self.depth = depth
def decide(self, board):
startNode = self.Node(board, self.mypiece)
best = self.minimax(startNode, self.depth)
for node in startNode.paths:
if node.value == best:
break
found = False
for row in xrange(3):
for col in xrange(3):
if board.check(row, col) != node.board.check(row, col):
found = True
break
if found:
break
print row, col
return row, col
def minimax(self, node, depth):
victory = node.board.checkVictory()
if victory:
if victory == self.mypiece:
h = 1
elif victory == -1:
h = 0
else:
h = -1
node.value = h
return h
if depth <= 0:
# h = self.heuristic(node.board, node.nextMove) # This is to the heuristic, which uses nextMove to evalate.
node.value = 0
return 0
h = -1
flip = Board.flipPiece(node.nextMove)
for i, board in enumerate(node.paths):
node.paths[i] = self.Node(Board(board), flip) # This is to the Node, which takes the nextMove of itself (which translates to the next next move from the current node)
score = self.minimax(node.paths[i], depth-1)
h = max(h, score) if node.nextMove == self.mypiece else min(h, score)
node.value = h
return h
Why is this happening?