Python how to pick item from list containing lists - python

I have a problem with generating map. It uses several lists which contain list of vectors. There is also list of lists of wall set(which set represent maze in place pointed by vector). So I have problem with random. When I pick random item from list of mazes. Program is going crazy, and creates something which doesn't make much sense. I tried to pick manually each maze and it worked perfectly. I tried to find solution to this problem but there wasn't answer for this kind of problem. There is definitelly something wrong with taking random item from list of mazes in this loop.`
EDIT: Here is program which can be run to see results.
import pygame, random, sys
WIDTH= 640
HEIGHT = 480
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
clock = pygame.time.Clock()
screen= pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(WHITE)
wall_list = pygame.sprite.Group()
all_sprite_list = pygame.sprite.Group()
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
def ran_map():
walls_1 = [ [0, 0, 40, 20],
[60, 0, 30, 20],
[0, 40, 40, 10],
[60, 40, 30, 10]
]
walls_2 = [ [0, 0, 60, 10],
[40, 10, 20, 10],
[0, 30, 20, 20],
[20, 40, 70, 10],
[80, 0, 10, 40]
]
walls_3 = [ [0, 0, 10, 50],
[10, 0, 80, 10],
[80, 10, 10, 40],
[30, 30, 30, 20]
]
s_maze = [walls_1, walls_2, walls_3]
vectors = [[60, 60], [170, 60], [380, 60], [490, 60], [60, 370], [170, 370], [380, 370], [490, 370]]
for item in vectors:
v1 = item[0]
v2 = item[1]
random_item = random.choice(s_maze)
for item in random_item:
w1 = item[0]
w2 = item[1]
s1 = w1+ v1
s2 = w2+ v2
wall = Wall(s1, s2, item[2], item[3])
wall_list.add(wall)
all_sprite_list.add(wall)
def xz():
done = False
while not done:
pygame.init()
clock.tick(45)
ran_map()
all_sprite_list.draw(screen)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
def main():
xz()
main()

The "going crazy" is most likely due to this duplicated iteration variable:
for *item* in vectors:
...
for *item* in random_item:
I suggest you simplify the middle section of your code as follows:
...
mazes = { # a dictionary of mazes
'walls_1': [ [0, 0, 40, 20],
[60, 0, 30, 20],
[0, 40, 40, 10],
[60, 40, 30, 10]
],
'walls_2': [ [0, 0, 60, 10],
[40, 10, 20, 10],
[0, 30, 20, 20],
[20, 40, 70, 10],
[80, 0, 10, 40]
],
'walls_3': [ [0, 0, 10, 50],
[10, 0, 80, 10],
[80, 10, 10, 40],
[30, 30, 30, 20]
]
}
vectors = [[60, 60], [170, 60], [380, 60], [490, 60], [60, 370], [170, 370], [380, 370], [490, 370]]
for v1, v2 in vectors:
random_item = random.choice(list(mazes.values()))
for w1, w2, w3, w4 in random_item:
s1 = w1 + v1
s2 = w2 + v2
wall = Wall(s1, s2, w3, w4)
wall_list.add(wall)
all_sprite_list.add(wall)
...

Related

How to rotate the shapes in the picture unclockwise?

enter image description hereI am new through tkinter and I have creates two shapes each of them consist if a square and two ovals. I would like to be able to rotate them using keywords.
Thank you for your consideration.
Here is my code:
import sys
if sys.version[0] < '3':
from Tkinter import *
else:
from tkinter import *
import math
left_corners = [(0, 0), (200, 0)]
colors = ['white', 'white']
root = Tk()
canvas = Canvas(root, width=400, height=200)
canvas.grid()
squares = []
for left_corner, color in zip(left_corners, colors):
x1, y1 = left_corner
x2, y2 = x1 + 200, y1 + 200
square = canvas.create_rectangle(x1, y1, x2, y2, fill=color)
squares.append(square)
'''points1 = [[50, 50], # First point of the rectangle
[50, 70], [40, 75], [50, 80], # first pickup point
[50, 120], [60, 125], [50, 130], # delivery point
[50, 150], [150, 150], [150, 50]]
#points2 = [[250, 50], # First point of the rectangle
[250, 70], [240, 75], [250, 80], # first pickup point
[250, 120], [260, 125], [250, 130], # delivery point
[250, 150], [350, 150], [350, 50]]'''
points1 = [[50, 50], [50, 150], [150, 150], [150, 50]]
points2 = [[250, 50], [250, 150], [350, 150], [350, 50]]
# Creates a polygon
machine1 = canvas.create_polygon(points1, outline="black",
fill="red", width=2)
pickup1 = canvas.create_oval(45, 80, 55, 70, width=0, fill='black')
delivery1 = canvas.create_oval(45, 130, 55, 120, width=0, fill='black')
machine2 = canvas.create_polygon(points2, outline="black",
fill="red", width=2)
pickup2 = canvas.create_oval(245, 80, 255, 70, width=0, fill='black')
delivery2 = canvas.create_oval(245, 130, 255, 120, width=0, fill='black')
root.title("Rotating test")
root.mainloop()

Generate K random numpy arrays given N variables and ranges

I have N variables (defining N-dimensional space), with their defined ranges (normally or uniformly distributed in the given range):
each variable is defined by a list containing its possible integer values.
v1_range = [1, 2, 3, 4, 5, 6]
v2_range = [10, 20, 30, 40, 50, 60]
v3_range = [100, 200, 300, 400, 500]
v4_range = [15, 16, 17, 18]
i want to generate K lists (numpy arrays/vectors..), each list contains one random number from the given ranges, with no duplicates.
so i-th element in each list, is selected from i-th list of ranges.
example (K = 6, from given ranges):
output = [
[1, 20, 300, 15],
[5, 10, 200, 15],
[3, 60, 100, 18],
[4, 30, 200, 16],
[4, 40, 100, 17],
[2, 30, 400, 15],
]
What is the best way to do so,using numpy.random() or scipy assuming the N-dimensional space could be very large (~13 lists of ranges, each containing ~20 values) and no duplicates are allowed ?
[EDIT]
duplicate entries in the ranges lists are fine, but i don't want to have two duplicate/exact same lists in the resulting list of lists e.g.:
indices 0, 2 are duplicated...
res = [[ 4, 40, 400, 18],
[ 4, 60, 400, 17],
[ 4, 40, 400, 18]]
Will simple iteration work? I think for 13 lists x 20 values it will work just fine.
import random
d = {
"v1_range" : [1, 2, 3, 4, 5, 6],
"v2_range" : [10, 20, 30, 40, 50, 60],
"v3_range" : [100, 200, 300, 400, 500],
"v4_range" : [15, 16, 17, 18]
}
def give(k):
out = [[] for i in range(k)]
for l in out:
for i in d.keys():
l.append(random.choice(d[i]))
return out
Which gives, for example:
>>> give(6)
[[5, 50, 500, 15], [1, 60, 400, 16], [5, 20, 200, 15], [1, 40, 400, 18], [2, 20, 100, 15], [6, 20, 400, 16]]
Or, with numpy
>>> import numpy as np
>>> np.array(give(6))
array([[ 4, 40, 400, 18],
[ 4, 60, 400, 17],
[ 5, 20, 400, 17],
[ 4, 10, 300, 16],
[ 5, 10, 300, 16],
[ 4, 30, 500, 18]])

Adding rects in list for displaying in 7-segment digits in pygame

I had two python files one for all the data that made previously and the other file of functions to display the data properly on screen using pygame.
--Functioning--
My idea is that the display of the segments is named alphabetically A,B,C,D,E,F,G
Here, till now every segment is displaying but if you see in my data.py code you can see there is a dictionary called 'final_data' where each number has it's binary code which simply means "How many segments had to glow..." Note:- '1' means to glow and '0' means to not glow, you can say these are buttons. each button has a list of [x,y,width,height] to get display on the screen. I also give the binaries and there positions. The dictionary is working properly the problem is in it's implementation in my second file 'functions.py'.
--Code--
My first file is data.py and the code is......
nums = (0,1,2,3,4,5,6,7,8,9)
binaries = ([1,1,1,1,1,1,0],[1,1,0,0,0,0,0],[1,0,1,1,0,1,1],[1,1,1,0,0,1,1],
[1,1,0,0,1,0,1],[0,1,1,0,1,1,1],[0,1,1,1,1,0,1],[1,1,0,0,0,1,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1])
positions = ([200,110,10,50],[200,170,10,50],[150,220,50,10],[140,170,10,50],[140,110,10,50],[150,100,50,10],[150,160,50,10])
final_data = {'0':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10]], "0": [[150, 160, 50, 10]]},
'1':{"1": [[200, 110, 10, 50], [200, 170, 10, 50]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]]},
'2':{"1": [[200, 110, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[200, 170, 10, 50], [140, 110, 10, 50]]},
'3':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[140, 170, 10, 50], [140, 110, 10, 50]]},
'4':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [150, 100, 50, 10]]},
'5':{"1": [[200, 170, 10, 50], [150, 220, 50, 10], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]],"0": [[200, 110, 10, 50], [140, 170, 10, 50]]},
'6':{"1": [[200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]],"0": [[200, 110, 10, 50], [150, 100, 50, 10]]},
'7':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 100, 50, 10]], "0": [[150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 160, 50, 10]]},
'8':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 170, 10, 50], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]]},
'9':{"1": [[200, 110, 10, 50], [200, 170, 10, 50], [150, 220, 50, 10], [140, 110, 10, 50], [150, 100, 50, 10], [150, 160, 50, 10]], "0": [[140, 170, 10, 50]]}
}
"""
A,B,C,D,E,F,G
1,1,1,1,1,1,0
1,1,0,0,0,0,0
1,0,1,1,0,1,1
1,1,1,0,0,1,1
1,1,0,0,1,0,1
0,1,1,0,1,1,1
0,1,1,1,1,0,1
1,1,0,0,0,1,0
1,1,1,1,1,1,1
1,1,1,0,1,1,1
"""
My second file functions.py
import pygame, sys
pygame.init()
size = width,height = 400,400
running = True
segments = []
screen = pygame.display.set_mode(size)
def draw_rect(x,y,width,height):
pygame.draw.rect(screen,(0,0,0),(x,y,width,height))
def digits():
#A
draw_rect(200,110,10,50)
#B
draw_rect(200,170,10,50)
#C
draw_rect(150,220,50,10)
#D
draw_rect(140,170,10,50)
#E
draw_rect(140,110,10,50)
#F
draw_rect(150,100,50,10)
#G
draw_rect(150,160,50,10)
while running:
screen.fill((148,241,251))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
if key[pygame.K_q]:
run = False
sys.exit()
digits()
pygame.display.update()
**please tell me in comments do you like my idea? and is the format of asking question is correct. **
You don't need final_data at all. Just write a function draw_digit:
def draw_digit(surf, color, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, positions[j])
And call it like this:
draw_digit(screen, "black", 0)
Add an additional offset argument to display multiple digits in a row:
def draw_digit(surf, color, offset, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, pygame.Rect(positions[j]).move(offset, 0))
draw_digit(screen, "black", 0, 2)
draw_digit(screen, "black", 100, 3)
Minimal example:
repl.it/#Rabbid76/PyGame-7SegementDisplay
data.py
binaries = ([1,1,1,1,1,1,0],[1,1,0,0,0,0,0],[1,0,1,1,0,1,1],[1,1,1,0,0,1,1],
[1,1,0,0,1,0,1],[0,1,1,0,1,1,1],[0,1,1,1,1,0,1],[1,1,0,0,0,1,0],[1,1,1,1,1,1,1],[1,1,1,0,1,1,1])
positions = ([200,110,10,50],[200,170,10,50],[150,220,50,10],[140,170,10,50],[140,110,10,50],[150,100,50,10],[150,160,50,10])
functions.py
import pygame, sys
from data import *
pygame.init()
size = width,height = 400,400
run = True
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
def draw_digit(surf, color, offset, i):
for j, on in enumerate(binaries[i]):
if on:
pygame.draw.rect(surf, color, pygame.Rect(positions[j]).move(offset, 0))
count = 0
while run:
clock.tick(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((148,241,251))
draw_digit(screen, "black", 0, count // 10)
draw_digit(screen, "black", 100, count % 10)
count += 1
if count >= 100:
count = 0
pygame.display.update()

Python combination with a twist

Assume I have following:
arr = [0, 0, 0], [20, 20, 90], [30, 30, 50], [40, 40, 80], [10, 75, 10], [100, 100, 0]
I build a combination from it
print(list(itertools.combinations(arr, 2)))
So I get a nice all combinations - only moving "forward" which is great:
[([0, 0, 0], [20, 20, 90]), ([0, 0, 0], [30, 30, 50]), ([0, 0, 0], [40, 40, 80]), ([0, 0, 0], [10, 75, 10]), ([0, 0, 0], [100, 100, 0]), ([20, 20, 90], [30, 30, 50]), ([20, 20, 90], [40, 40, 80]), ([20, 20, 90], [10, 75, 10]), ([20, 20, 90], [100, 100, 0]), ([30, 30, 50], [40, 40, 80]), ([30, 30, 50], [10, 75, 10]), ([30, 30, 50], [100, 100, 0]), ([40, 40, 80], [10, 75, 10]), ([40, 40, 80], [100, 100, 0]), ([10, 75, 10], [100, 100, 0])]
BUT there is a trick - I have to add all additional costs for the points I've skipped.
Say in the case of ([0, 0, 0], [40, 40, 80])
I have skipped these ones [20, 20, 90], [30, 30, 50]
For which have the additional accumulated cost of distance from 0,0,0 until current which is 140, which is adding the skipped's third values which is (50+90). These distances individually I would like to put into a list of tuples. Accessing the previous items in the list I've done below, but accumulating for each combination gave me the headache.
What data structure or evtl. hijacked combination algorithm would maintain the skipped previous additional costs still creating the combination for an n list?
So I thought about a more manual approach as well:
`def combination(given_list, possibilities):
penalty = 0
final_list = []
if possibilities == 0: return [[]]
for item in range(0, len(given_list)):
current_item = given_list[item]
remaining_from_given_list = given_list[item + 1:]
for prev in combination(remaining_from_given_list, possibilities -1):
penalty += previous_item[2]
final_list.append([current_item] + prev)
penalty = 0
return final_list
`
But this only gave me the previous penalties which then is not true for all cases (0 if I don't miss the previous, all the previous additional cost(s) which I have missed)
But not sure how to hijack the above to measure distance and get the accumulation for all previous values.
The final result would look like:
ways = [("0", "1", 0), ("0", "2", 90), ("0", "3", 140), ("0", "4", 220), ("0", "5", 230), ("1", "2", 0), ("1", "3", 50), ("1", "4", 130), ("1", "5", 140), ("2", "3", 0), ("2", "4", 80), ("2", "5", 900), ("3", "4", 0), ("3", "5", 10), ("4", "5", 0)]
The optimal path I am using a dijkstra to calculate, I have that part already and if I create the list of tuples manually like this, it works as expected.
I feel like I am missing something obvious - maybe I should use a dictionary to achieve this? I thought about a double linked list as well but that's likely not the best approach either.
Try an iterative approach:
arr = [[0, 0, 0], [20, 20, 90], [30, 30, 50], [40, 40, 80], [10, 75, 10], [100, 100, 0]]
ways = []
total = len(arr)
for i in range(total):
for j in range(i + 1, total):
ways.append((i, j, sum(i[-1] for i in arr[i+1:j])))
print(ways)
Returns:
[(0, 1, 0), (0, 2, 90), (0, 3, 140), (0, 4, 220),
(0, 5, 230), (1, 2, 0), (1, 3, 50), (1, 4, 130),
(1, 5, 140), (2, 3, 0), (2, 4, 80), (2, 5, 90),
(3, 4, 0), (3, 5, 10), (4, 5, 0)]

Python list to tuple

I have this :
(([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
that come from this :
[(array([75, 0]), array([100, 0]), array([100, 370])), (array([75, 0]), array([100, 370]), array([ 75, 370]))]
and I want to have :
[(x1, y1, x2 , y2 ,x3 ,y3), (x1, y1, x2 , y2 ,x3 ,y3), ...]
or
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 0, 100, 370),.....]
Thanks for the help!
You can use itertools.chain:
import itertools
s = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
final_s = [list(itertools.chain.from_iterable(i)) for i in s]
Output:
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]
or using reduce in Python2:
s = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
new_s = [reduce(lambda x, y:list(x)+list(y), i) for i in s]
Output:
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]
You could use a list comprehension:
>>> t = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
>>> [tuple(sub for el in l for sub in el) for l in t]
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]
Starting with this example:
from operator import add
from functools import reduce
reduce(add, (x for x in [[1, 2], [3, 4]]))
Outputs:
[1, 2, 3, 4]
Now just do this for each element in the tuple:
[tuple(reduce(add, x)) for x in data]
Outputs:
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]
Easy to understand version:
original = (([75, 0], [100, 0], [100, 370]), ([75, 0], [100, 370], [75, 370]))
final = []
for each_tuple in original:
final_child_list = []
for each_list in each_tuple:
final_child_list.extend(each_list)
final.append(final_child_list)
You'll get:
>>> final
[[75, 0, 100, 0, 100, 370], [75, 0, 100, 370, 75, 370]]
# if you prefer the inside element to be tuples
>>> [tuple(x) for x in final]
[(75, 0, 100, 0, 100, 370), (75, 0, 100, 370, 75, 370)]
There might be shorter versions using list comprehension, but less readability.

Categories