I'm currently working on a map editor for a game in pygame, using tile maps. The level is built up out of blocks in the following structure (though much larger):
level1 = (
(1,1,1,1,1,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,1,1,1,1,1))
where "1" is a block that's a wall and "0" is a block that's empty air.
The following code is basically the one handling the change of block type:
clicked = pygame.mouse.get_pressed()
if clicked[0] == 1:
currLevel[((mousey+cameraY)/60)][((mousex+cameraX)/60)] = 1
But since the level is stored in a tuple, I'm unable to change the values of the different blocks. How do I go about changing the different values in the level in an easy manner?
To convert tuples to list
(Commas were missing between the tuples in the given question, it was added to prevent error message)
Method 1:
level1 = (
(1,1,1,1,1,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,1,1,1,1,1))
level1 = [list(row) for row in level1]
print(level1)
Method 2:
level1 = map(list,level1)
print(list(level1))
Method 1 took --- 0.0019991397857666016 seconds ---
Method 2 took --- 0.0010001659393310547 seconds ---
Why don't you try converting its type from a tuple to a list and vice versa.
level1 = (
(1,1,1,1,1,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,0,0,0,0,1)
(1,1,1,1,1,1))
print(level1)
level1 = list(level1)
print(level1)
level1 = tuple(level1)
print(level1)
Just using the command list did not work for me.
if you have a tuple just iterate until you have the elements there are necessary and after that append to a list. And if you go to the element level you can change it easily.
input:
level1 = (
(1,1,1,1,1,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,0,0,0,0,1),
(1,1,1,1,1,1))
level1_as_list=[]
for i in level1:
inside_list=[]
for j in i:
inside_list.append(j)
level1_as_list.append(inside_list)
print(level1_as_list)enter code here
output:
[[1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1]]
You could dramatically speed up your stuff if you used just one list instead of a list of lists. This is possible of course only if all your inner lists are of the same size (which is true in your example, so I just assume this).
WIDTH = 6
level1 = [ 1,1,1,1,1,1,
1,0,0,0,0,1,
1,0,0,0,0,1,
1,0,0,0,0,1,
1,0,0,0,0,1,
1,1,1,1,1,1 ]
print level1[x + y*WIDTH] # print value at (x,y)
And you could be even faster if you used a bitfield instead of a list:
WIDTH = 8 # better align your width to bytes, eases things later
level1 = 0xFC84848484FC # bit field representation of the level
print "1" if level1 & mask(x, y) else "0" # print bit at (x, y)
level1 |= mask(x, y) # set bit at (x, y)
level1 &= ~mask(x, y) # clear bit at (x, y)
with
def mask(x, y):
return 1 << (WIDTH-x + y*WIDTH)
But that's working only if your fields just contain 0 or 1 of course. If you need more values, you'd have to combine several bits which would make the issue much more complicated.
You have a tuple of tuples.
To convert every tuple to a list:
[list(i) for i in level] # list of lists
--- OR ---
map(list, level)
And after you are done editing, just convert them back:
tuple(tuple(i) for i in edited) # tuple of tuples
--- OR --- (Thanks @jamylak)
tuple(itertools.imap(tuple, edited))
You can also use a numpy array:
>>> a = numpy.array(level1)
>>> a
array([[1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1]])
For manipulating:
if clicked[0] == 1:
x = (mousey + cameraY) // 60 # For readability
y = (mousex + cameraX) // 60 # For readability
a[x][y] = 1
You can have a list of lists. Convert your tuple of tuples to a list of lists using:
level1 = [list(row) for row in level1]
or
level1 = map(list, level1)
and modify them accordingly.
But a numpy array is cooler.
Both the answers are good, but a little advice:
Tuples are immutable, which implies that they cannot be changed. So if you need to manipulate data, it is better to store data in a list, it will reduce unnecessary overhead.
In your case extract the data to a list, as shown by eumiro, and after modifying create a similar tuple of similar structure as answer given by Schoolboy.
Also as suggested using numpy array is a better option
List to Tuple and back can be done as below
import ast, sys
input_str = sys.stdin.read()
input_tuple = ast.literal_eval(input_str)
l = list(input_tuple)
l.append('Python')
#print(l)
tuple_2 = tuple(l)
# Make sure to name the final tuple 'tuple_2'
print(tuple_2)
Convert tuple to list:
>>> t = ('my', 'name', 'is', 'mr', 'tuple')
>>> t
('my', 'name', 'is', 'mr', 'tuple')
>>> list(t)
['my', 'name', 'is', 'mr', 'tuple']
Convert list to tuple:
>>> l = ['my', 'name', 'is', 'mr', 'list']
>>> l
['my', 'name', 'is', 'mr', 'list']
>>> tuple(l)
('my', 'name', 'is', 'mr', 'list')
Since Python 3.5 (PEP 448 -- Additional Unpacking Generalizations) one can use the following literal syntax to convert a tuple to a list:
>>> t = (1,2,3)
>>> lst = [*t]
>>> lst
[1, 2, 3]
>>> *lst, # back to tuple
(1, 2, 3)
A list comprehension can be use to convert a tuple of tuples to a list of lists:
>>> level1 = (
... (1,1,1,1,1,1),
... (1,0,0,0,0,1),
... (1,0,0,0,0,1),
... (1,0,0,0,0,1),
... (1,0,0,0,0,1),
... (1,1,1,1,1,1))
>>> level1_list = [[*row] for row in level1]
>>> level1_list
[[1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1]]
>>> *((*row,) for row in level1_list),
((1, 1, 1, 1, 1, 1),
(1, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 1),
(1, 0, 0, 0, 0, 1),
(1, 1, 1, 1, 1, 1))
>>> _ == level1
True
Source: Stackoverflow.com