Hey i am tring to make a chess engine but when i run the code it plays fine, the problem is sometimes it does not set the best move and it shows an error becuase the search did not return a move to play. My negamax includes AB pruning, MD Pruning, QSearch, ID, and TT Tables. Here is my implementation.
Entry=namedtuple('Entry', 'score depth flag')
class Search():
def __init__(self):
self.nodes=0
self.tt_score={}
def search(self,position,api):
self.nodes=0
for depth in range(1,1000):
ret=self.negamax(position,api,-INFINITY,INFINITY,depth,ply=1)
yield ret
def negamax(self,position,api,alpha,beta,depth=3,ply=1):
best,bmove=-INFINITY,()
for move in position.moves():
score=self.negasearch(position.move(move),-beta,-alpha,depth-1,ply+1)
if score>=beta: return [move,score,self.nodes]
if score>best:
best,bmove=score,move
#api.arrow("clear")
#api.arrow(coordinates[move[0]]+coordinates[move[1]])
if score>alpha: alpha=score
return [bmove,best,self.nodes]
def negasearch(self,position,alpha,beta,depth,ply):
best,aorig=-INFINITY,alpha
self.nodes+=1
if MATE-ply<beta:
beta=MATE-ply
if alpha>=MATE-ply: return MATE-ply
if -MATE+ply>alpha:
alpha=-MATE+ply
if beta<=-MATE+ply: return -MATE+ply
entry=self.tt_score.get(position.hash(),Entry(0,-1,'exact'))
if entry.depth>=depth:
if entry.flag=='exact': return entry.score
elif entry.flag=='lower': alpha=max(alpha,entry.score)
elif entry.flag=='upper': beta=min(beta,entry.score)
if alpha>=beta: return entry.score
if depth<=0: return self.qsearch(position,alpha,beta,ply+1)
for move in position.moves():
score=self.negasearch(position.move(move),-beta,-alpha,depth-1,ply+1)
if score>=beta:
best=score
break
if score>best:
best=score
if score>alpha: alpha=score
if best<=aorig: self.tt_score[position.hash()]=Entry(best,depth,'upper')
elif best>=beta: self.tt_score[position.hash()]=Entry(best,depth,'lower')
else: self.tt_score[position.hash()]=Entry(best,depth,'exact')
return best
def qsearch(self,position,alpha,beta,ply):
stand_pat=position.score
if stand_pat>=beta: return beta
if alpha<stand_pat: alpha=stand_pat
self.nodes+=1
for move in position.moves():
if move[2]==0: continue
score=self.qsearch(position.move(move),-beta,-alpha,ply+1)
if score>=beta: return beta
if score>alpha: alpha=score
return alpha
You probably have already noticed i did not negate the score each turn as it should be. Reason why is because when you call the move function it return the position with the score already negated. For example,
def move(self,move):
# copy the current position board, turn, and score
# if move is a capture then preform:
# score+=pvs[pieceBeingCaptured]
# preform move
# if the next player is mated after this move then set score to MATE
return Position(board,-score,self.turn*-1)
It is not the move generation because it returns the correct moves each position state. With the best value being -INFINITY and negamax it should always set the best move. Any help would be helpful.
Related
In a program I am working on, whenever the player attacks an enemy, a little if statement runs to check the health of the target:
def attack(self, target):
target.stats.health = target.stats.health - self.stats.damage
if target.stats.health <= 0:
if isinstance(target, Enemy) == True:
print(target.name, "has died")
del #Something here to delete the target from the list of enemies
#For example, in myPlayer.attack(enemies[0])
#The target is enemies[0]
else:
pass
else:
print(target.name, "has", target.stats.health, "health left")
In my code, Instances of the Enemy class are created to create enemies, and those are all put into a list. What I want to do is delete the list entry if the target's health goes below. I know target itself is a reference to the instance of my Enemy, so using del target would just delete that reference. Is there a way that I can actually call the parameter entry or something and delete that? So if i type in myPlayer.attack(enemies[x]), the del function will run as del enemies[x].
I'm trying to implement Monte Carlo tree search to play tic-tac-toe in Python. My current implementation is as follows:
I have a Board class that handles alterations to the tic-tac-toe board. The state of the board is represented by a 2x3x3 numpy array, where each of the 2 3x3 matrices are binary matrices individually representing the presence of X's and the presence of O's.
class Board:
'''
class handling state of the board
'''
def __init__(self):
self.state = np.zeros([2,3,3])
self.player = 0 # current player's turn
def copy(self):
'''
make copy of the board
'''
copy = Board()
copy.player = self.player
copy.state = np.copy(self.state)
return copy
def move(self, move):
'''
take move of form [x,y] and play
the move for the current player
'''
if np.any(self.state[:,move[0],move[1]]): return
self.state[self.player][move[0],move[1]] = 1
self.player ^= 1
def get_moves(self):
'''
return remaining possible board moves
(ie where there are no O's or X's)
'''
return np.argwhere(self.state[0]+self.state[1]==0).tolist()
def result(self):
'''
check rows, columns, and diagonals
for sequence of 3 X's or 3 O's
'''
board = self.state[self.player^1]
col_sum = np.any(np.sum(board,axis=0)==3)
row_sum = np.any(np.sum(board,axis=1)==3)
d1_sum = np.any(np.trace(board)==3)
d2_sum = np.any(np.trace(np.flip(board,1))==3)
return col_sum or row_sum or d1_sum or d2_sum
I then have a Node class, which handles properties of nodes as the search tree is being built:
class Node:
'''
maintains state of nodes in
the monte carlo search tree
'''
def __init__(self, parent=None, action=None, board=None):
self.parent = parent
self.board = board
self.children = []
self.wins = 0
self.visits = 0
self.untried_actions = board.get_moves()
self.action = action
def select(self):
'''
select child of node with
highest UCB1 value
'''
s = sorted(self.children, key=lambda c:c.wins/c.visits+0.2*sqrt(2*log(self.visits)/c.visits))
return s[-1]
def expand(self, action, board):
'''
expand parent node (self) by adding child
node with given action and state
'''
child = Node(parent=self, action=action, board=board)
self.untried_actions.remove(action)
self.children.append(child)
return child
def update(self, result):
self.visits += 1
self.wins += result
Finally, I have UCT function which pulls everything together. This function takes a Board object and builds the Monte Carlo search tree to determine the next best possible move from the given board state:
def UCT(rootstate, maxiters):
root = Node(board=rootstate)
for i in range(maxiters):
node = root
board = rootstate.copy()
# selection - select best child if parent fully expanded and not terminal
while node.untried_actions == [] and node.children != []:
node = node.select()
board.move(node.action)
# expansion - expand parent to a random untried action
if node.untried_actions != []:
a = random.choice(node.untried_actions)
board.move(a)
node = node.expand(a, board.copy())
# simulation - rollout to terminal state from current
# state using random actions
while board.get_moves() != [] and not board.result():
board.move(random.choice(board.get_moves()))
# backpropagation - propagate result of rollout game up the tree
# reverse the result if player at the node lost the rollout game
while node != None:
result = board.result()
if result:
if node.board.player==board.player:
result = 1
else: result = -1
else: result = 0
node.update(result)
node = node.parent
s = sorted(root.children, key=lambda c:c.wins/c.visits)
return s[-1].action
I've scoured this code for hours and simply can't find the error in my implementation. I've tested numerous board states and pitted two agents against each other, but the function returns poor actions for even the most simple of board states. What am I missing and/or what is wrong with my implementation?
edit: here is an example of how two agents might be implemented to play:
b = Board() # instantiate board
# while there are moves left to play and neither player has won
while b.get_moves() != [] and not b.result():
a = UCT(b,1000) # get next best move
b.move(a) # make move
print(b.state) # show state
The problem appears to be as follows:
Your get_moves() function does not check if the game is already over. It can generate a non-empty list of moves for states where someone has already won.
When creating a new Node, you also don't check if the game state is already over, so a non-empty list of untried_actions is created.
In the Selection and Expansion phases of the algorithm, you also don't check for terminal game states. Once the Expansion phase hits a node that contains a game state where someone already won, it will happily apply an extra action and create a new node for the tree again, which subsequent Selection phases will also happily keep going through.
For these nodes where the game continues being played after someone already won, result() can return an incorrect winner. It simply checks if the most recent player to make a move won, which is correct if you stop playing as soon as someone wins, but can be incorrect if you keep playing after someone already won. So, you propagate all kinds of incorrect results through the tree.
The simplest way to fix this will be to modify get_moves() such that it returns an empty list when the game is already over. Then, these nodes will always fail the if node.untried_actions != [] check, which means the expansion phase gets skipped altogether, and you move straight on to the Play-out phase where there is a proper check for terminal game states. This can be done as follows:
def get_moves(self):
"""
return remaining possible board moves
(ie where there are no O's or X's)
"""
if self.result():
return []
return np.argwhere(self.state[0] + self.state[1] == 0).tolist()
I recently created a small game using tkinter (python version 3.6.1) and froze it using cx_Freeze. The game has four buttons: an undo button, a restart button, a "find legal moves" button, and a "find best move button". The "find best move" button uses a shelve database to find the best move for the first three turns and a recursive function that traverses the move tree on the fly for the fourth turn and up. My code disables the buttons when they should not be used.
I made sure to include the necessary DLLs in the setup script and I was able to run the executable without errors. However, three of the buttons are disabled until the fourth turn (when the recursive function begins to be used) and the application is extremely buggy in many other ways. However, it works perfectly when I run the unfrozen version.
I honestly don't know what code snippets I would need to provide to you guys, as this issue has me utterly at a loss. The only clue I have is that the pyc files in the build differ in size from the unfrozen app. I know this is rather vague, but I do not know what specifics would be useful to give. Any help, if possible, would be greatly appreciated.
"Find best move" method:
def _find_best_move(self):
"""Finds best move possible for current game."""
if len(self.game.moves) <= 3:
with shelve.open("paths") as db:
best_paths = db[str(self.game.moves)]
best_path = choice(best_paths)
else:
self.path_finder(self.game)
best_path = self.path_finder.best_path
best_move = best_path[len(self.game.moves)]
best_move = (__class__._add_offset(best_move[0]), best_move[1])
return best_move
Updates Button State:
def update_gui(self):
"""Updates GUI to reflect current game conditions."""
legal_moves = self.game.find_legal_moves()
if self.game.moves:
self.undo_btn["state"] = "!disabled"
self.restart_btn["state"] = "!disabled"
self.best_move_btn["state"] = "!disabled"
else:
self.undo_btn["state"] = "disabled"
self.restart_btn["state"] = "disabled"
if legal_moves:
self.show_moves_btn["state"] = "!disabled"
else:
self.show_moves_btn["state"] = "disabled"
if legal_moves and self.game.moves:
self.best_move_btn["state"] = "!disabled"
else:
self.best_move_btn["state"] = "disabled"
My __init__ file:
initpath = os.path.dirname(__file__)
os.chdir(os.path.join(initpath, "data"))
PathFinder class (traverses move tree on the fly):
class PathFinder:
"""Provides methods to find move paths that meet various criteria.
Designed to be called after the player makes a move.
"""
_game = None
best_path = None
best_score = None
def __call__(self, game):
"""Call self as function."""
if not game:
self._game = DummyGame()
elif not isinstance(game, DummyGame):
self._game = DummyGame(game)
else:
self._game = game
moves = self._game.moves
self.possible_paths = dict.fromkeys(range(1,9))
root = Node(moves[-1])
self._find_paths(root)
self._find_paths.cache_clear()
found_scores = [score for score in self.possible_paths.keys() if
self.possible_paths[score]]
self.best_score = min(found_scores)
self.best_path = self.possible_paths[self.best_score]
#lru_cache(None)
def _find_paths(self, node):
"""Finds possible paths and records them in 'possible_paths'."""
legal_moves = self._game.find_legal_moves()
if not legal_moves:
score = self._game.peg_count
if not self.possible_paths[score]:
self.possible_paths[score] = self._game.moves.copy()
else:
children = []
for peg in legal_moves:
for move in legal_moves[peg]:
children.append(Node((peg, move)))
for child in children:
self._game.move(*child.data)
self._find_paths(child)
try:
self._game.undo()
except IndexError:
pass
Peg class:
class Peg(RawPen):
"""A specialized 'RawPen' that represents a peg."""
def __init__(self, start_point, graphics):
"""Initialize self. See help(type(self)) for accurate signature."""
self.graphics = graphics
self.possible_moves = []
super().__init__(self.graphics.canvas, "circle", _CFG["undobuffersize"],
True)
self.pen(pendown=False, speed=0, outline=2, fillcolor="red",
pencolor="black", stretchfactor=(1.25,1.25))
self.start_point = start_point
self.goto(start_point)
self.ondrag(self._remove)
self.onrelease(self._place)
def _remove(self, x, y):
"""Removes peg from hole if it has moves."""
if self.possible_moves:
self.goto(x,y)
def _place(self, x, y):
"""Places peg in peg hole if legal."""
if self.possible_moves:
target_holes = [tuple(map(add, self.start_point, move)) for move in
self.possible_moves]
distances = [self.distance(hole) for hole in target_holes]
hole_distances = dict(zip(distances, target_holes))
nearest_hole = hole_distances[min(hole_distances)]
if self.distance(nearest_hole) <= 0.45:
self.goto(nearest_hole)
peg = self.graphics._subtract_offset(self.start_point)
move = tuple(map(sub, self.pos(), self.start_point))
move = tuple(map(int, move))
self.graphics.game.move(peg, move)
self.start_point = self.pos()
else:
self.goto(self.start_point)
The frozen application is going to have a different value for __value__ then the unfrozen application. You will have to deal with that accordingly! This is a common issue that bites a lot of people. Anything that assumes that the module is found in the file system is going to stop working properly when frozen. The other gotcha is dynamic importing of modules.
The documentation covers this and other topics that will hopefully help you out!
I've got some issues with this simple chess code in python. It is part of a weekly assignment; this is what I got so far:
from math import sqrt
from random import randint,shuffle,seed
def rand_pos():
return [randint(0,7),randint(0,7)]
#first, classes defining the kings and the rook;
#their only attribute is a randomly generated position on the chessboard.
#Each of them has its special print method that will be used in the Chessboard (Scacchiera) class.
class W_king:
def __init__(self,coord=rand_pos()):
self.coord=coord
self.x=coord[1]
self.y=coord[0]
def __repr__(self):
return "R"
class B_king:
def __init__(self,coord=rand_pos()):
self.coord=coord
self.x=coord[1]
self.y=coord[0]
def __repr__(self):
return "r"
class Rook:
def __init__(self,coord=rand_pos()):
self.coord=coord
self.x=coord[1]
self.y=coord[0]
def __repr__(self):
return "T"
#the following will be used to calculate the distance between the kings and between a king and the rook;
#I'll use it in the while statements later in the Scacchiera class to check if the kings are generated too near or stuff
def distance(n1,n2):
return sqrt(sum((n1.coord[i]-n2.coord[i])**2 for i in [0,1]))
class Scacchiera:
def __init__(self,w_king=W_king(),b_king=B_king(),rook=Rook(),boxes=[[" " for y in range(8)] for x in range(8)]):
self.w_king=w_king
self.b_king=b_king
self.rook=rook
self.boxes=boxes
#here it is: while the two kings are generated too near,
#get the black king new coordinates
while distance(self.b_king,self.w_king)<2:
self.b_king.coord=[randint(0,7),randint(0,7)]
#...and, while the white king (or the black king) and the rook have the same coordinates
#or the black king is in the rook's sight,
#get a new pair of coordinates for the rook:
while self.w_king.coord==self.rook.coord or self.b_king.coord==self.rook.coord or self.rook.x==self.b_king.x or self.rook.y==self.b_king.y:
self.rook.coord=[randint(0,7),randint(0,7)]
print distance(self.b_king,self.w_king) #to check, just for me
#the function conv switches to the chessboard's coordinates e.g. e4, h5, etc
print conv(self.w_king.coord),conv(self.b_king.coord),conv(self.rook.coord)
def __repr__(self):
#self.boxes is an array of blank spaces " ",
#and in the right place the kings and the rook are placed
scacchiera=self.boxes[:]
scacchiera[self.w_king.x][self.w_king.y]=self.w_king
scacchiera[self.b_king.x][self.b_king.y]=self.b_king
scacchiera[self.rook.x][self.rook.y]=self.rook
return "\n".join([str(8-i)+" "+" ".join(str(scacchiera[i][j]) for j in range(8)) for i in range(8)])+"\n "+" ".join([chr(97+k) for k in range(8)])
def check(self,king):
#no need for this for now
return self.rook.x==king.x or self.rook.y==king.y
def black_legal_moves(self,mossa):
future_king=B_king([self.b_king.y+mossa[0],self.b_king.x+mossa[1]])
if distance(self.w_king,future_king)<2 or self.check(future_king):
return False
else:
return True
def new_mossa_random(self):
#this method chooses randomly a new position for the black king from the list of adjacent cells
#and tests if it's legal with the method above. If it's not, it deletes it from the list and re-tries
moves_list=[[self.b_king.y+hor,self.b_king.x+ver] for ver in [-1,0,1] for hor in [-1,0,1] if not hor==ver==0]
shuffle(moves_list)
move=moves_list[0]
#while it's not legal or the coordinates are out of the board:
while not self.black_legal_moves(move) or not 0<=move[0]<=7 or not 0<=move[1]<=7:
del moves_list[0]
if not moves_list:
return None
move=moves_list[0]
return move
def conv(coord):
return [chr(coord[0]+97),8-coord[1]]
#you just need to run it:
seed()
scacchiera=Scacchiera()
print scacchiera
print conv(scacchiera.new_mossa_random())
The issues are two:
My code, though incomplete, seems correct to me in the chessboard generation section. Nonetheless, often (nearly three times out of ten) the kings are next to each other or the rook and a king are placed one over the other, or the random move for the black king isn't even near of his box.
Very often, the code keeps running and won't print any chessboard; it seems like it sticks on the two whiles at the beginning of Scacchiera.
NB: F5-ing the script on your PC will print, in the following order:
The distance between the two kings,
The coordinates on the chessboard of: the white king, the black king, and then the rook
The chessboard with the pieces on the board
The coordinates of a new random move for the black king.
Let me know if I should add some other info.
In case of collision, you're changing the coord member on the pieces. But the positions are also stored in x and y, which are not updated.
I'd suggest that you keep only x and y or only coord in your classes. if you want to get fancy, you could keep coord and make x and y into properties by using #property.
Your problems most likely stem from an incorrect use of default parameters.
Short answer, do this:
def __init__(self, coord=None):
coord = coord or rand_pos()
Explanation: Common gotcha with Python default args
Thank you for your help! Finally I removed the classes for the kings and the rook; they were pointless, all I needed was just a dictionary, just like in the code here.
Here is the solution I went through
from random import randint,shuffle,choice
def rand_pos():
return [randint(0,7),randint(0,7)]
def dist(n1,n2):
return (sum([(n1[i]-n2[i])**2 for i in [0,1]]))**(0.5)
def invconv(coord):
return [ord(coord[0])-97,8-coord[1]]
#the core of the game is here; Scacchiera means Checkboard, and it basically generates coordinates
#for the kings and the rook while they are in illegal positions.
#then there's a bunch of methods to determine wether a move is legal or not
#and, just for black, a random move is chosen.
#finally, all the stuff is gathered in the Partita (=Game) function.
class Scacchiera:
def __init__(self,w_king=rand_pos(),b_king=rand_pos(),rook=rand_pos()):
self.w_king=w_king
self.b_king=b_king
self.rook=rook
while dist(self.b_king,self.w_king)<=1.5:
self.b_king=rand_pos()
while self.w_king==self.rook or self.b_king==self.rook or self.rook[0]==self.b_king[0] or self.rook[1]==self.b_king[1]:
self.rook=rand_pos()
self.pezzi={"R":self.w_king,"r":self.b_king,"T":self.rook}
self.mosse=[self.pezzi[item] for item in ["r","R","T"]]
def __repr__(self):
griglia=[["." for j in range(8)] for i in range(8)]
for item in self.pezzi:
griglia[self.pezzi[item][0]][self.pezzi[item][1]]=item
return "\n".join([str(8-j)+" "+" ".join(str(griglia[i][j]) for i in range(8)) for j in range(8)])+"\n "+" ".join([chr(97+k) for k in range(8)])
def move(self,pezzo,end):
if not end:
return
end=[end[0]-self.pezzi[pezzo][0],end[1]-self.pezzi[pezzo][1]]
self.pezzi[pezzo][0]+=end[0]
self.pezzi[pezzo][1]+=end[1]
if self.pezzi["r"]==self.pezzi["T"]:
del self.pezzi["T"]
self.mosse.append(self.pezzi.values())
return
def check(self):
return self.pezzi["T"][0]==self.pezzi["r"][0] or self.pezzi["T"][1]==self.pezzi["r"][1]
def black_legal_move(self,end):
kings_dist=dist(self.pezzi["R"],end)
rook_king_dist=dist(self.pezzi["T"],self.pezzi["R"])
if kings_dist<=1.5:
return False
elif self.pezzi["T"]==end and rook_king_dist>1.5:
return True
elif self.pezzi["T"][0]==end[0] or self.pezzi["T"][1]==end[1] or end[0] not in range(8) or end[1] not in range(8):
return False
return True
def mosse_legali_b(self):
moves_list=[[self.pezzi["r"][0]+hor,self.pezzi["r"][1]+ver] for ver in [-1,0,1] for hor in [-1,0,1] if not hor==ver==0]
shuffle(moves_list)
elle=[]
for i in range(len(moves_list)):
if self.black_legal_move(moves_list[i]):
elle.append(moves_list[i])
if not elle:
return None
return elle
def mossa_random_black(self):
print "Tocca al nero.\n"
end=choice(self.mosse_legali_b())
if not end:
return None
self.move("r",end)
print self
return
def scacco_matto(self):
return self.check() and self.mosse_legali_b()==None
def stallo(self):
return self.mosse_legali_b()==None
def ripetizione(self):
return 3 in [self.mosse.count(item) for item in self.mosse]
def white_king_lmove(self,beg,end):
return dist(beg,end)<=1.5 and dist(self.pezzi["r"],end)>1.5 and beg!=end
def white_rook_lmove(self,beg,end):
return (beg[0]==end[0] or beg[1]==end[1]) and beg!=end
def white_legal_move(self,beg,end):
if self.pezzi["R"]==beg:
return self.white_king_lmove(beg,end)
else:
return self.white_rook_lmove(beg,end)
def mossa_white(self):
print "\n**Tocca al bianco**"
mossa=raw_input("Inserisci la prossima mossa:\n")
beg=invconv([mossa[0],int(mossa[1])])
end=invconv([mossa[2],int(mossa[3])])
if not self.white_legal_move(beg,end):
print "\nMossa non valida."
return self.mossa_white()
if self.pezzi["R"]==beg:
pezzo="R"
elif self.pezzi["T"]==beg:
pezzo="T"
self.move(pezzo,end)
if self.check():
print "Scacco!\n",self
else:
print self
return
There is a while loop which constantly allows user input using the raw_input keyword, that input is then passed to a function called commands() which then routes the input to the command that the user specified. In this instance, Whenever I call function movement in my code, it makes the user press enter in the function and won't process the data until the user does hit enter.
Furthermore, it appears the program is returning part of code in function movement() back to the commands() function and thus is gives me the following glitch:
target leo2
Successful lock on Leo2
launch
Your mobile suit shifts as you begin moving towards Leo2 at coordinates [300, 100, 100]Invalid command
Type 'commands' for a list of valid commands
Distance from suit is: 200
As you can see, in the middle of the function it is trying to run the main whileloop from the main module, but it then goes back to running the function in the middle. Why does this occur, and how can I fix it?
My code:
Gundam2.py
import math
class Mobilesuits:
#class global variables/methods here
instances = [] #grid cords here
names=[]
def __init__(self,armor,speed,name,description,cockpit_description,\
radar_range, coordinates):
Mobilesuits.instances.append(self)
Mobilesuits.names.append(name)
self.armor=armor
self.speed=speed
self.name=name
self.description=description
self.cockpit_description=cockpit_description
self.radar_range=radar_range
self.coordinates=coordinates
#Intrinsically links mobile suits objects to their names.
#I want to be able to access each object directly through the name
def update_names(self):
Mobilesuit_names_instances_dictionary={}
for i in range(len(Mobilesuits.instances)):
Mobilesuit_names_instances_dictionary[Mobilesuits.names[i]] =Mobilesuits.instances[i]
return Mobilesuit_names_instances_dictionary
def can_detect(self, other):
for own_coord, other_coord in zip(self.coordinates, other.coordinates):
if abs(own_coord - other_coord) > self.radar_range:
return False
return True
def radar(self):
for other in Mobilesuits.instances:
if other is not self and self.can_detect(other):
print "%s detected at %s" % (other.description, other.coordinates)
def movement(self, target, official_target, currentmobilesuit):
print("Your mobile suit shifts as you begin moving towards %s at coordinates %s" %(target,official_target.coordinates))
distance = (currentmobilesuit.coordinates[0] - official_target.coordinates[0],\
currentmobilesuit.coordinates[1] - official_target.coordinates[1], \
currentmobilesuit.coordinates[2]-official_target.coordinates[2])
calculation=0
for i in distance:
calculation += abs(i)
print("Distance from suit is: %s" % (calculation))
#Make speed calculation based on distance away and speed of suit
#Errors:
#target without a suit gives error
maingundam.py
from Gundam2 import Mobilesuits
import thread
import time
#Main Variable/Object declarations:
Leo1=Mobilesuits(100,100,"Leo1","leo desc","dockpit desc",100,[100,100,100])
Leo2=Mobilesuits(100,100,"Leo2","leo desc","dockpit desc",100,[300,100,100])
Leo3=Mobilesuits(100,100,"Leo3","leo desc","dockpit desc",100,[100,150,100])
currentmobilesuit=Leo1
mobile_suit_names_list=currentmobilesuit.update_names()
#Main Function declarations
def commands(user_input,currentmobilesuit, mobile_suit_names_list):
#radar
if user_input == "radar":
currentmobilesuit.radar()
#Commands overview
elif user_input == "commands":
print("Command list:\nradar\ntarget (object)")
#Target objects
elif user_input.startswith("target"):
try:
global target
target=user_input.split()[1].title()
if mobile_suit_names_list[target]:
global official_target
official_target=mobile_suit_names_list[target]
print("Successful lock on %s" % (target))
except:
print("space object '%s' not detected" %(target))
elif user_input=="launch":
# try:
if official_target:
thread.start_new_thread(currentmobilesuit.movement, (target, official_target, currentmobilesuit))
# except:
# print("No target is selected")
#command not found
else:
print("Invalid command\nType 'commands' for a list of valid commands")
def active_delay(action, delay):
time.sleep(delay)
action()
#Main execution: paused
while True:
mobile_suit_names_list=currentmobilesuit.update_names()
commands(raw_input(),currentmobilesuit,mobile_suit_names_list)
Your second problem is that, if your user just hits Return, the return from raw_input is an empty string "", which is not handled by command(). You could fix this by adding the lines:
elif user_input == "":
pass
Your first problem is due to the way raw_input works; it always waits for user input followed by Return and is not designed for being used for continuous control input. This is trickier to fix. You might be better using a library designed for this sort of thing (continuous keyboard control), like pygame.