Search for duplicates of items in list within list - python

Working on a basic project to simulate the life cycle of an organism using matplotlib. The organism's position is defined by list [x,y], and its position is randomly generated. Organism being the class
for i in range(numorganisms):
posX = random.randint(0,XMAX)
posY = random.randint(0,YMAX)
creatures.append(organism([posX,posY]))
There may be about 100 of these in the plot, meaning collisions will occur. I want to be able to search the list of creatures for instances where posX and posY are both equal, and then create a new list of those positions.

You may easily do this:
existing = set()
for i in range(numorganisms):
posX = random.randint(0,XMAX)
posY = random.randint(0,YMAX)
if (posX, posY) not in existing :
creatures.append(organism([posX,posY]))
existing.add( (posX, posY) )
else :
pass # do something else

This assumes you have some way to get the positions out of the instance of organism.
###############################
# This just recreates what I think you already have
import random
class organism:
def __init__(self, l):
self.l = l
XMAX = YMAX = 100
creatures = []
for i in range(100):
posX = random.randint(0,XMAX)
posY = random.randint(0,YMAX)
creatures.append(organism([posX,posY]))
print(creatures)
###############################
# Determine if there are redundancies
positions = [x.l for x in creatures]
print(positions)
collisions = [i for i in positions if positions.count(i) > 1]
print(collisions)

Related

Count number of steps of turtle in a list - python

I am now three weeks into learning python and I'm stuck.
This is my code: (after that comes my question)
from turtle import Screen, Turtle
from random import randint, choice
def person_characteristics(people):
"""
Gives the turtle 'person' all it's characteristics / values.
"""
for person in people:
person.shape('circle')
person.shapesize(0.2)
person.speed('fastest')
person.penup()
x = randint(-200, 200) #turtle gets a random position
y = randint(-200, 200)
person.setpos(x, y)
person.showturtle()
def population(population_size):
"""
Makes a population, by making a list of turtles (persons).
population_size = type(int)
"""
people = []
for _ in range(population_size):
people.append(Turtle(visible=False))
return people
def random_walk(person, step_size, area_size):
"""
Makes the person walk around randomly within the borders.
step_size = type(int) -> determines how big of a step each person takes.
area_size = type(int) -> determines how big the area is where the persons are in.
"""
if -area_size < person.xcor() < area_size and -area_size < person.ycor() < area_size: #if person is within the borders then it moves randomly
person.right(randint(0, 360))
person.forward(step_size)
else:
person.right(180) #if person is outside the borders it turns around
person.forward(step_size)
def infect_random(people):
"""
Random person gets infected (a red color)
people = a list of persons achieved from de function population()
"""
infected = choice(people)
infected.color('red')
return infected
screen = Screen()
people = population(100)
person_characteristics(people)
infected_people = []
initial_infected = infect_random(people)
infected_people.append(initial_infected)
counted_infections = 1
#count_steps = 0
#healed_people = []
for _ in range(10): # determines the number of steps = time
for person in people:
random_walk(person, 30, 400)
for infected_person in infected_people:
if person.pencolor() != 'red' and person.distance(infected_person) < 30: #if a person gets close to the initial infected person it also
person.color('red') #gets infected & added to the list of infected persons
infected_people.append(person)
#count_steps +=1
#if count_steps = 5:
#infected_person.color('green')
#healed_people.append(infected_person)
#infected_people.remove(infected_person)
break
count_susceptible = len(people) - len(infected_people) #counts number of susceptible people
count_infected = len(infected_people) #counts number of infected people
print(count_susceptible)
print(count_infected)
screen.exitonclick()
I want to turn the infected_person green (=healed) and at the turtle to the list healed_people (& remove from the list infected_people) after it made 5 steps. My idea was to do this with a if statement however this does not work. My idea is in the code above. I know why it doesn't work: now it counts the total number of steps of every infected_person, instead of separately.
I think there probably is a very simple solution but I am very new to python so I have no idea how to do this. Can anyone help?
Thanks in advance!
(I prefer not to use a Class since I didn't learn that yet :)
from turtle import Screen, Turtle
from random import randint, choice
def person_characteristics(people):
"""
Gives the turtle 'person' all it's characteristics / values.
"""
for person in people:
person.shape('circle')
person.shapesize(0.2)
person.speed('fastest')
person.penup()
x = randint(-200, 200) #turtle gets a random position
y = randint(-200, 200)
person.setpos(x, y)
person.showturtle()
def population(population_size):
"""
Makes a population, by making a list of turtles (persons).
population_size = type(int)
"""
people = []
for _ in range(population_size):
people.append(Turtle(visible=False))
return people
def random_walk(person, step_size, area_size):
"""
Makes the person walk around randomly within the borders.
step_size = type(int) -> determines how big of a step each person takes.
area_size = type(int) -> determines how big the area is where the persons are in.
"""
if -area_size < person.xcor() < area_size and -area_size < person.ycor() < area_size: #if person is within the borders then it moves randomly
person.right(randint(0, 360))
person.forward(step_size)
else:
person.right(180) #if person is outside the borders it turns around
person.forward(step_size)
def infect_random(people):
"""
Random person gets infected (a red color)
people = a list of persons achieved from de function population()
"""
infected = choice(people)
infected.color('red')
return infected
screen = Screen()
people = population(100)
person_characteristics(people)
infected_people = []
people_steps=[0 for _ in range (len(people))]
initial_infected = infect_random(people)
infected_people.append(initial_infected)
counted_infections = 1
for _ in range(10): # determines the number of steps = time
for person in people:
random_walk(person, 30, 400)
people_steps[people.index(person)]+=1
if people_steps[people.index(person)]==5 and person.pencolor()=='red':
person.color('green')
infected_people.remove(person)
for infected_person in infected_people:
if person.pencolor() != 'red' and person.distance(infected_person) < 30: #if a person gets close to the initial infected person it also
person.color('red') #gets infected & added to the list of infected persons
infected_people.append(person)
people_steps[people.index(person)]=0
break
count_susceptible = len(people) - len(infected_people) #counts number of susceptible people
count_infected = len(infected_people) #counts number of infected people
print(count_susceptible)
print(count_infected)
screen.exitonclick()
You can use an auxiliary array to save the number of people's steps. If you create it with the same size you can work with the indexes. For example:
people=[person1, person2, person3]
people_steps=[number_of_steps1, number_of_steps2, number_of_steps3]
This is just a graphical representation.
But it is better to do it with a class so that the number of steps is part of it as an attribute.
I hope this helps. If you have any suggestions or questions, please let me know.

Issue with updating list in snake game

So I've been programming a snake game using python mode for processing, but I have been having an issue with the list I have set up for keeping track of the body of the snake itself.
My current implementation uses a list of vectors to keep track of the location of each segment of the snake. I then loop through this list to display the squares for each segment. At the beginning of the game, the list only has 1 entry (the head), but upon eating a piece of food, I insert a new vector to the front of the list with the same value as the current head. I then update the list but looping through it and finally, I update the head by using a velocity vector.
scl = 10
dim = 20
def setup():
global s
global f
size(dim * scl, dim * scl)
s = Snake()
f = Food()
def draw():
background(201)
global s
global f
if s.eat(f):
f.location()
s.update()
s.display()
f.display()
delay(50)
class Snake:
def __init__(self):
self.body = [PVector(0, 0)]
self.v = PVector(1, 0)
self.total = 1
def update(self):
for i in range(self.total - 1):
self.body[self.total - 1 - i] = self.body[self.total - 2 - i]
print("Position")
print(self.body)
self.body[0].x += self.v.x * scl
print(self.body)
self.body[0].y += self.v.y * scl
print(self.body)
def display(self):
fill(101)
for i in range(self.total):
rect(self.body[i].x + 1, self.body[i].y + 1, scl - 2, scl - 2)
def eat(self, p):
tmp = self.body[:]
dis = dist(self.body[0].x, self.body[0].y, p.pos.x, p.pos.y)
if dis < 1:
self.total += 1
self.body.insert(0, tmp[0])
return True
else:
return False
I expect the output to be a list of differing vectors, each that draw a square next to the previous and next entries. Instead, after eating food, all the vectors are the same within the body list. Does anyone know how I can fix this?
You seem to misunderstood, how python's list handles it's values.
tmp = self.body[:]
makes shallow copy, not deep copy. And:
self.body[...] = self.body[...]
doesn't copy the value. It just passes the value from one place, to another. So when you move your values in self.body by one offset, the first and the second element will end pointing to the same value.
Try something like this:
def update(self):
for i in range(self.total - 1):
self.body[self.total - 1 - i] = self.body[self.total - 2 - i]
print("Position")
print(self.body)
self.body[0] = PVector(self.body[0].x + self.v.x * scl, self.body[0].y + self.v.y * scl)
print(self.body)
and in eat function:
self.body.insert(0, PVector(tmp[0].x, tmp[0].y))

How to sort a collection based on another collection in Python?

I'm very new to Python and I need help with the following problem. This definition that I have posted below will take in a collection of tuples that represent rectangles Ex. (width,height).
In the method, I first sort the rectangle collection so that the elements with the largest width are at the beginning of the list, I then use this collection later to assign UPPER_LEFT_X and UPPER_LEFT_Y coordinates for each rectangle.
My question is, how do I take this collection of coordinates and sort it in a way that it is in the exact same order as the original_rectangle_collection? The way that the Driver works, is that the determined coordinates have to be given in the same order as the original rectangle collection. Thanks! Let me know if more explanation is required.
def find_best_coordinates(rectangles):
placement = []
upper_left_x = 0
upper_left_y = 0
loop_count = 0
original_rectangle_collection = rectangles
#sort the rectangles according to width.
rectangles.sort(key=operator.itemgetter(0))
#reverse the list so the tallest rectanlgle is placed first
rectangles.reverse()
#set the max width to the tallest rectangle's width
max_width = rectangles[0][0]
#print("Max width",max_width)
#loop through and place the rectangles
for rectangle in rectangles:
if loop_count == 0:
max_width = rectangle[0]
height = rectangle[1]
coordinate = (upper_left_x, upper_left_y)
placement.insert(0, coordinate)
upper_left_y = upper_left_y - height - 990
loop_count = loop_count + 1
if loop_count == 50:
upper_left_x = upper_left_x + max_width + 990
# print("x = ", upper_left_x)
loop_count = 0
#print("y = ", upper_left_y)
upper_left_y = 0
#reverse the list before it gets returned
placement.reverse()
return placement
You could do it this way, by always passing the original index along with the rectangle, and keeping it with the generated coordinate.
# Store indexes
rdicts = [{'index': i, 'rectangle': r} for i, r in enumerate(rectangles)]
# Sort by width
rdicts.sort(key=lambda d: d['rectangle'][0], reverse=True)
placement = []
for rdict in rdicts:
rectangle = rdict['rectangle']
... # do the rest of your algorithm
# Add the calculated coordinate, along with the original index
placement.append({'index': rdict['index'], 'coordinate': coordinate})
# Sort by the original index
placement.sort(key=lambda p: p['index'])
# Return the coordinates without the indexes.
ordered_placement = [p['coordinate'] for p in placement]
You can go a little faster by just sorting the indexes:
processing_order = sorted(
range(len(rectangles)),
key=lambda i: rectangles[i][0]
)
for rect_i in processing_order:
r = rectangles[rect_i]
# ... blah blah with r as current rectangle
# Done processing, output them in original order:
for r in rectangles:
# Still in order!

Touring a chess board with multiple pieces [Python]

I have been trying to solve this for 2 days straight and I just can't find a valid algorithm. Given a Chess board, and a number of pieces, I have to check if said board can be toured by the pieces, with the condition that each piece can only visit an square once. I know it's some kind of multiple backtracking, but I can't get it to work. (I only have been able to implement a general knight's tour for individual pieces)
tablero is a class of the board, that holds a name, a list of pieces, a list with prohibited positions, a list with the free positions, and a tuple with the dimensions of the board.
ficha is the class of a piece, it holds a name (nombre), a tuple with its position (posicion), a list with its valid movements (movimientos) (For example, a pawn's list would be [ [0,1] ], meaning it can only move forward 1)
Any insight is welcome.
Here are the classes (Feel free to add/remove any method).
def legal(pos,dimensiones):
if pos[0] >= 0 and pos[0] < dimensiones[0] and pos[1] >= 0 and pos[1] < dimensiones[0]:
return True
else:
return False
class board:
def __init__(self,name,pieces,dimention,prohibited_positions):
self.name = name
self.pieces = pieces
self.dimention = dimention
self.prohibited_positions = prohibited_positions
self.free_positions = []
for x in range(dimention[0]):
for y in range(dimention[1]):
self.free_positions.append([x,y])
for x,y in self.prohibited_positions:
if [x,y] in self.free_positions:
self.free_positions.remove([x,y])
for piece in self.pieces:
if self.piece.position in self.free_positions:
self.free_positions.remove(piece.position)
def append(self,piece):
pos = piece.position
if pos in self.free_positions:
self.pieces.append(piece)
self.free_positions.remove(pos)
class piece:
def __init__(self,name,position,move_offsets):
self.name=name
self.position=position
self.move_offsets=move_offsets
self.possible_movements=move_offsets
def setPos(self,pos):
self.position=pos
def ValidMovements(self,dim,free_positions,prohibited_positions):
aux = []
for i in self.possible_movements:
newX = self.position[0] + i[0]
newY = self.position[1] + i[1]
newPos = [newX,newY]
if legal(newPos,dim):
aux.append(newPos)
for i in list(aux):
if i not in free_positions:
aux.remove(i)

Quickly counting particles in grid

I've written some python code to calculate a certain quantity from a cosmological simulation. It does this by checking whether a particle in contained within a box of size 8,000^3, starting at the origin and advancing the box when all particles contained within it are found. As I am counting ~2 million particles altogether, and the total size of the simulation volume is 150,000^3, this is taking a long time.
I'll post my code below, does anybody have any suggestions on how to improve it?
Thanks in advance.
from __future__ import division
import numpy as np
def check_range(pos, i, j, k):
a = 0
if i <= pos[2] < i+8000:
if j <= pos[3] < j+8000:
if k <= pos[4] < k+8000:
a = 1
return a
def sigma8(data):
N = []
to_do = data
print 'Counting number of particles per cell...'
for k in range(0,150001,8000):
for j in range(0,150001,8000):
for i in range(0,150001,8000):
temp = []
n = []
for count in range(len(to_do)):
n.append(check_range(to_do[count],i,j,k))
to_do[count][1] = n[count]
if to_do[count][1] == 0:
temp.append(to_do[count])
#Only particles that have not been found are
# searched for again
to_do = temp
N.append(sum(n))
print 'Next row'
print 'Next slice, %i still to find' % len(to_do)
print 'Calculating sigma8...'
if not sum(N) == len(data):
return 'Error!\nN measured = {0}, total N = {1}'.format(sum(N), len(data))
else:
return 'sigma8 = %.4f, variance = %.4f, mean = %.4f' % (np.sqrt(sum((N-np.mean(N))**2)/len(N))/np.mean(N), np.var(N),np.mean(N))
I'll try to post some code, but my general idea is the following: create a Particle class that knows about the box that it lives in, which is calculated in the __init__. Each box should have a unique name, which might be the coordinate of the bottom left corner (or whatever you use to locate your boxes).
Get a new instance of the Particle class for each particle, then use a Counter (from the collections module).
Particle class looks something like:
# static consts - outside so that every instance of Particle doesn't take them along
# for the ride...
MAX_X = 150,000
X_STEP = 8000
# etc.
class Particle(object):
def __init__(self, data):
self.x = data[xvalue]
self.y = data[yvalue]
self.z = data[zvalue]
self.compute_box_label()
def compute_box_label(self):
import math
x_label = math.floor(self.x / X_STEP)
y_label = math.floor(self.y / Y_STEP)
z_label = math.floor(self.z / Z_STEP)
self.box_label = str(x_label) + '-' + str(y_label) + '-' + str(z_label)
Anyway, I imagine your sigma8 function might look like:
def sigma8(data):
import collections as col
particles = [Particle(x) for x in data]
boxes = col.Counter([x.box_label for x in particles])
counts = boxes.most_common()
#some other stuff
counts will be a list of tuples which map a box label to the number of particles in that box. (Here we're treating particles as indistinguishable.)
Using list comprehensions is much faster than using loops---I think the reason is that you're basically relying more on the underlying C, but I'm not the person to ask. Counter is (supposedly) highly-optimized as well.
Note: None of this code has been tested, so you shouldn't try the cut-and-paste-and-hope-it-works method here.

Categories