from math import dist
def distance(pos1,pos2):
return dist(pos1,pos2)
def find_closest(location, centroids):
dista=centroids
start=0
for i in range(len(centroids)):
dista[start]=distance(location, centroids[start])
start+=1
end=0
for i in range(len(centroids)):
if min(dista)==dista[end]:
break
end+=1
return centroids[end]
This function will loop over a list called centroids and find the closest one to a specific location. However my list centroids is changing along with our new list dista. PS I want to return the centroid not the distance.
dista=centroids
That means you’re declaring a new name to the list, not a new list, you should make a new list,try for loop
dista=[]
for i in centroids:
dista.append(i)
To prevent falling in the same mistake again, understand how vars work
Echo=print
Echo(“hello”)
#output : hello
Related
Currently attempting the Travelling Salesman Problem with a simulated annealing solution. All points are stored in a dictionary with the point name as the key and co-ordinates as the value. Having trouble writing a for loop(path_tour function) that goes through every key in a a given path(randomly shuffled dictionary of locations), calculates distances and adds the value to a list to retrun a total length. The current function I have below returns a KeyError, I cant figure out why.
#Calculate distances between points
def point_distance(point_a, point_b):
return math.sqrt((point_a[0] - point_b[0])**2 + (point_a[1] - point_b[1])**2)
def get_distance_matrix(points):
distance_matrix = {}
for location_a in points:
distance_matrix[location_a] = {}
for location_b in points:
distance_matrix[location_a][location_b] = point_distance(
points[location_a], points[location_b])
return distance_matrix
#Calculate length of path
def path_tour(tour):
path_length = 0
distances = get_distance_matrix(tour)
for key, value in tour.items():
path_length += distances[key][key[1:]]
return path_length
how the get_distance_matrix is called
example of a path
error message
As you can see from the error, it was trying to look up the key "tudent Information Desk". I assume the location name was "Student Information Desk", so key[1:] removed the first letter. That's obviously not the correct location to look up.
I guess you want the distance from the current to the next location in the tour. That would be something like
locations = list(tour.keys())
for first, second in zip(locations[:-1], locations[1:]):
path_length += distances[first][second]
I don't get why your tour is a dictionary, though. Shouldn't it be a list to begin with? I know that dictionaries in Python-3 keep their insertion order but this usage seems counter-intuitive.
List item
I'm working on a code that calculates the 'distance' between two configurations of a Flip Cube, The distance between two configurations x and y is the minimum number of steps required to go from x to y, or conversely.
To make that I've created a simpler version that makes something different, this code takes two integer numbers ci and cf. with ci returns an iterable called main_level through the generator called multi, then, it iterates through it searching for the parameter cf, whenever cf is not in main_level the variable steps is increased by 1 and for each element in main_level we repeat the same process done for ci. Finally, when cii==cf the program ends and returns the steps variable, which counts the number of "levels" that we have to go down to find the given parameter cf. This code doesn't have any practical purpose is just a base for the problem I mentioned above.
If I call the distance(ci, cf) function with ci=5, the first two levels are:
{0,3,6,9,12} <-- first level (steps is initialized with 1)
if cf is any of the numbers in the set, the program should end and return steps=1,
if cf is not in that set, the programs form the second level:
{15,18,21,24,27,30,33} and search cf, if cf is there, the program ends and should return steps=2, if not, it forms the third level, and so on. But there is a problem, actually, when I call the distance function with ci=5 and cf= any natural number, and print its value, anything is output, only for cf=0, it outputs step=1. I don't really know what's going on. I would appreciate your help.
Here is the code:
#Base solution to FlipCube problem
def multi(par):
for i in range(par):
yield i*3
steps=1
def distance(ci,cf):
main_level =set(multi(ci))
global steps
def check_main_level(cf):
global steps
nonlocal main_level
def lower_level(config_list):
sett=set()
for i in config_list:
sett.update(q for q in multi(i) if q not in config_list)
nonlocal main_level
main_level=sett
check_main_level(cf)
for i in main_level:
if i==cf:
break
else:
steps+=1
lower_level(main_level)
check_main_level(cf)
return steps
#testing
e= distance(5,0)
print(e)# prints 1, very good
e2= distance(5,9)
print(e2)# should print 1, but doesn't print anything :(
e3= distance(5,27)
print(e3)# should print 2, but doesn't print anything :(
The program does not terminate recursion under all circumstances. The culprit seems to be the for loop in check_main_level. Change the code after your definition of lower_level to:
# code portion of check_main_level
if cf > max(main_level):
steps+=1
lower_level(main_level)
# end of code portion check_main_level (replacing for-loop)
you have an infinity loop, that's why nothing is printed.
You can see it easyly by adding a print :
for i in config_list:
print(i)
sett=set()
sett.update(q for q in list(multi(i)) if q not in config_list)
I am trying to calculate a moving average of a list called 'temp_data' in the function below. The moving average data should be stored in a list called 'moving_average'. The code below works in the sense that list 'temp_mov' is printed inside the function (line 12), but not when I call the function later on (in the last line of the code). In that case, I get an empty list. What mistake do I make?
# calculate moving average of a list of weather data
def make_moving(temps, temp_mov):
''' Create moving average from list weather data'''
cumsum, temp_mov = [0], []
for i, x in enumerate(temps, 1):
cumsum.append(cumsum[i-1] + x)
if i>=N:
moving_ave = round((cumsum[i] - cumsum[i-N])/N, 1)
temp_mov.append(moving_ave)
print(temp_mov)
return temp_mov
make_moving(temp_data, moving_average)
print(moving_average)
You assign a new list to temp_mov here:
cumsum, temp_mov = [0], []
Therefore, moving_average is not updated when temp_mov changes.
Changing make_moving(temp_data, moving_average) to moving_average = make_moving(temp_data) and removing the temp_mov parameter will solve the problem.
Im writing an algorithm in Python which plays this game.
The current state of the board of tiles in the game is a dictionary in the form of:
{
<tile_id>: {
'counters': <number of counters on tile or None>,
'player': <player id of the player who holds the tile or None>,
'neighbours': <list of ids of neighbouring tile>
},
...
}
I have another dictionary which stores all of my tiles which are 'full' (i.e. a tile which has one less counter than its number of neighbours and where the player is me) This dictionary, full_tiles, is in the same form as the board dictionary above.
I am now trying to create a list, chains, where each element in the list is a dictionary of my full tiles that are neighbouring at least one other full tile (i.e a chain of full tiles). So this will be a list of all my seperate chains on the board.
Here is my code so far:
for tile_id, tile in full_tiles.items(): #iterates through all full tiles
current_tile = {tile_id : tile} #temporarily stores current tile
if not chains: #if chains list is empty
chains.append(current_tile) #begin list
else: #if list is not empty
for index, chain in enumerate(chains): #iterate though list of chains
if not (current_tile in chain): #if current tile is not in current chain
for tile_id2, tile2 in chain.items(): #iterate through tiles in current chain
for neighbour in tile2["neighbours"]: #iterate through each neighbour of current tile
#neighbour is in the form of tile_id
if neighbour in chain: #if current tile's neighbour is in chain
chain[tile_id] = tile #add tile to chain
It is very difficult for me to test and debug my code and check if it is working correctly as the code can only be run in an application that simulates the game. As you can see, there is quite a lot going on in this block of code with all of the nested loops which are difficult to follow. I cannot seem to think straight at the minute and so I cannot determine if this mess, in all honesty, will function as I hope.
While I am writing this, I have just realised that - on line 7 of this code - I am only checking if the current tile is not in the current chain and so there will be intersecting chains which, of course, will be a mess. Instead of this, I need to first check if the current tile is in not in any of the chains, not just one.
Apart from this error, will my code achieve what I am attempting? Or can you recommend a simpler, neater way to do it? (There has to be!)
Also, let me know if I have not given enough information on how the code is run or if I need to explain anything further, such as the contents of the board dictionary.
Thank you for any help in advance.
EDIT: Unfortunately, I was under a time constraint to complete this project, and as it was my first time ever working with Python, I currently lack the knowledge in the language to optimise my solution using the sources given below. Here is my final extremely ugly and messy solution to this problem which, in the end, worked fine and wasn't terribly inefficient given the small data set that the code works on.
for x in range(0, len(my_hexplode_chains) - 1):
match_found = False
for y in range(x + 1, len(my_hexplode_chains)):
for tile_id_x, tile_x in my_hexplode_chains[x].items(): #compare each chain in list
for tile_id_y, tile_y in my_hexplode_chains[y].items(): #to every other chain
for neighbour in tile_x["neighbours"]: #if tiles in different lists
if neighbour == tile_id_y: #are neighbours
match_found = True
my_hexplode_chains[x].update(my_hexplode_chains[y]) #append one chain to the other
del my_hexplode_chains[y] #delete appended chain
if match_found: #continue loop at next chain
break #very ugly way to do this
if match_found:
break
if match_found:
break
if match_found:
break
How about this optimization?
def find_match (my_hexplode_chains):
x = 0
len_chain = len(my_hexplode_chains)
while x <= len_chain:
y = x + 1
for tile_id_x, tile_x in my_hexplode_chains[x].items():
for tile_id_y, tile_y in my_hexplode_chains[y].items():
if tile_id_y in tile_x["neighbours"]:
my_hexplode_chains[x].update(my_hexplode_chains[y])
del my_hexplode_chains[y]
return True
x += 1
return False
You could pass this function after each move in your game and trace the output.
I am currently working on a project for one of my classes where I have to implement an AI opponent to play tic-tac-toe using minmax and Alpha-Beta minmax algorithms to determine the moves.
The problem I am having however is attempting to generate a list of possible moves for a board.
My problem code is as follows
def genMoves(genBoard, turnNumber):
moveList = []
print "inMovesList"
#Figure out if X or O go now
if turnNumber % 2 == 0:
moveChar = "O"
else:
moveChar = "X"
i = 0;
while i < 9:
tempBoard = genBoard
if tempBoard[i] == "*":
#set tempBoard[i] to X or O
tempBoard[i] = moveChar
#append move, new board
moveList.append((i, tempBoard))
i+=1
print "MovesList: "
print moveList
return moveList
My board is represented as a list of 9 strings initialized to ["*", "*", "*", "*", "*", "*", "*", "*", "*"].
My goal is to have move list return a list of tuples with the first element of the tuple being i (Where the X or O was inserted) and the second element being the resulting board.
The problem I have is that I will recieve a list with the correct number of possible moves (Eg: If I manually play the first 4 moves for both sides it will only give me 5 possible moves) however it will place the same move in each location that contains a *. (So it ends up generating something like X,O,O,O,O,O,O,O,O for possible second moves)
This is not the first time I have had to use minmax but it is the first time I've had to do it in python.
Any suggestions for how to get around this issue would be helpful!
Thanks!
This line is a problem:
tempBoard = genBoard
After this line, you seem to think that you have two lists -- the original, still referenced
by genBoard, and a new one, now referenced by tempBoard. This is not the case.
This line does not create a copy of the list. Instead, it binds the name tempBoard to refer to the same object that genBoard is bound to.
Consequently, subsequent references to tempBoard[i] also affect genBoard[i].
Try one of these instead:
tempBoard = list(genBoard)
tempBoard = genBoard[:]
tempBoard = copy.copy(genBoard)
Each of these lines creates a new list, the initial contents of which is the same as genBoard. tempboard is bound to this new list, while genboard remains bound to the old list.
If the object in question were more complicated than a list of strings, you might need to do this:
tempBoard = copy.deepcopy(genBoard)
I belive Python does not create a copy of your Board but just points to the original version. therefore your printout is:
"MovesList: "
[[0,(X,O,O,O,O,O,O,O,O)],[1,(X,O,O,O,O,O,O,O,O)],[2,(X,O,O,O,O,O,O,O,O)], etc.
and your genBoard, variable is changed.
to test that add
print genBoard
directly before the end of your method
if that was indeed the problem try to google how to create a copy of your Board instead of referencing to it.