I'm trying create custom shapes using the Tetris technique. For now I have 2 approaches:
L = [['.....',
'...0.',
'.000.',
'.....',
'.....'],
['.....',
'..0..',
'..0..',
'..00.',
'.....'],
['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'.00..',
'..0..',
'..0..',
'.....']]
L = [[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]]
Is there any more efficient way to create grid? Since I got more than 10 of those and I'll have to create at most 80 of nested lists(10 * 4directions * 2 mirrored)
I prefer to use matrices as follows. It will contain a list of all the rotations of a tetris block.
I_Tetromino = [
[
[1, 1, 1, 1]
],
[
[1],
[1],
[1],
[1]
]
]
J_Tetromino = [
[
[0, 1],
[0, 1],
[1, 1]
],
[
[1, 0, 0],
[1, 1, 1]
],
[
[1, 1],
[1, 0],
[1, 0]
],
[
[1, 1, 1],
[0, 0, 1]
]
]
You could make a class of block, then draw the block on the grid by its color.
Then you can render it on your screen.
This may not be the most efficient method but I prefer to use a method which is not very complicated and readable.
Edit: You can make a function also to rotate it.
def rot90(matrix):
return list(zip(*matrix[::-1]))
def rot180(matrix):
return rot90(rot90(matrix))
def rot270(matrix):
return rot90(rot180(matrix))
you could start with the basic shapes and build a list by applying rotations and flips to them and keeping only distinct resulting shapes:
def rot(M,n):
return rot(list(map(list,zip(*reversed(M)))),n-1) if n else M
L = [ [1,1,1],
[0,0,1] ]
I = [ [1,1,1,1] ]
S = [ [0,1,1],
[1,1,0] ]
T = [ [1,1,1],
[0,1,0] ]
B = [ [1,1],
[1,1] ]
blocks = [ rot(fb,r) for b in (L,I,S,T,B)
for fb in (b,b[::-1])
for r in range(4) ]
blocks = [ b for i,b in enumerate(blocks) if blocks.index(b)==i ] # distincts
output:
def printShape(M):
for r in M: print(r)
for block in blocks:
printShape(block)
print()
[1, 1, 1]
[0, 0, 1]
[0, 1]
[0, 1]
[1, 1]
[1, 0, 0]
[1, 1, 1]
[1, 1]
[1, 0]
[1, 0]
[0, 0, 1]
[1, 1, 1]
[1, 0]
[1, 0]
[1, 1]
[1, 1, 1]
[1, 0, 0]
[1, 1]
[0, 1]
[0, 1]
[1, 1, 1, 1]
[1]
[1]
[1]
[1]
[0, 1, 1]
[1, 1, 0]
[1, 0]
[1, 1]
[0, 1]
[1, 1, 0]
[0, 1, 1]
[0, 1]
[1, 1]
[1, 0]
[1, 1, 1]
[0, 1, 0]
[0, 1]
[1, 1]
[0, 1]
[0, 1, 0]
[1, 1, 1]
[1, 0]
[1, 1]
[1, 0]
[1, 1]
[1, 1]
Note that defining these blocks as variable size 2D masks should make it much easier to implement block rendering, movements and collision detection in the game later on.
Related
From the following array of shape (6, 3):
>>> arr
[
[1, 0, 1],
[0, 0, 2],
[1, 2, 0],
[0, 1, 3],
[2, 2, 1],
[2, 0, 2]
]
I'd like to repeat the values according to a sliding window of n=4, giving a new array of shape (6-n-1, n, 3):
>>> new_arr
[
[
[1, 0, 1],
[0, 0, 2],
[1, 2, 0],
[0, 1, 3]
],
[
[0, 0, 2],
[1, 2, 0],
[0, 1, 3],
[2, 2, 1]
],
[
[1, 2, 0],
[0, 1, 3],
[2, 2, 1],
[2, 0, 2]
]
]
It is relatively straightforward using a loop, but it gets extremely slow with several million values (instead of 6 in this example) in the initial array.
Is there a faster way to get to new_arr using Numpy primitives?
You can use NumPy, specifically this function (only NumPy >= 1.20.0):
from numpy.lib.stride_tricks import sliding_window_view
new_arr = sliding_window_view(arr, (n, arr.shape[1])).squeeze()
I need to find all the possible combinations of a list with a defined length and numbers of defined size, but subject to a restriction that does not allow having the same repeated number in the list (except 0).
Currently I have a recursive code that generates all the combinations, but when trying to create the constraints I lose many options.
I have tried the options that appear commented to solve it, but it still does not work for me. Thank you in advance for your help.
size=3
l=[0 for x in range(size)]
def recursive(l, index, num, final):
if index == len(l) or num == final:
return
# if num!=0 and num in l:
# return
l[index]=num
print(l)
recursive(l, index+1, 0, final)
recursive(l, index, num+1, final)
recursive(l, 0, 0, 4)
the expected output for a list of size 3 and final number 3 would be something like this
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]
Start with the powerset of the non-zero values (a function for computing the powerset of a list can be found in the itertools documentation.)
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
(You could compute the power set including 0, but you would still need to zero-pad the shorter elements, as well as discard (0,1,2,3)).
Each element of the powerset should next be padded with zeros so that they are all the same length.
Finally, you want the list of permutations (using itertools.permutations) of each 0-padded permutation of the original input.
Use itertools.combinations_with_replacement(), and then filter out the elements with duplicates.
def has_duplicates(l):
'''Return True if list has duplicate elements other than 0'''
l = [x in l if x != 0]
return len(l) != len(set(l))
result = [comb for comb in itertools.combinations_with_replacement(l, 3) if not has_duplicates(comb)]
You can make this lazy by using itertools.filterfalse(); this way you won't fill up memory with all combinations of a large list.
result = itertools.filterfalse(has_duplicates, itertools.combinations_with_replacement(l, 3))
Here is a solution based on counters, I am using a base 4 counter:
def charcnt(s, a):
ctr = [1 if x == a else 0 for x in s ]
return sum(ctr)
def my_range(start,end,base,step=1):
def Convert(n,base):
string = "0123"
if n < base:
return string[n]
else:
return Convert(n//base,base) + string[n%base]
return (Convert(i,base) for i in range(start,end,step))
# base-10 58 will produce base-4 321
counter = [x.zfill(3) for x in my_range(0, 58, 4)]
result = []
for s in counter:
if charcnt(s, '1') > 1 or charcnt(s, '2') > 1 or charcnt(s, '3') > 1:
continue
else:
result.append(s)
result = [[int(n) for n in list(s)] for s in result]
#print(len(result))
for i in result:
print(i)
Will produce:
[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]
I have a numpy Ndarray of dimensions (N * N * M) and want to mirror it over the main diagonal efficiently.
For N=1 I did the following:
A = np.array([[1, 0, 6, 5], [0, 2, 0, 0], [1, 0, 2, 0], [0, 1, 0, 3]])
A = np.tril(A) + np.triu(A.T, 1)
'''
From:
array([[1, 0, 6, 5],
[0, 2, 0, 0],
[1, 0, 2, 0],
[0, 1, 0, 3]])
To:
array([[1, 0, 1, 0],
[0, 2, 0, 1],
[1, 0, 2, 0],
[0, 1, 0, 3]])
'''
However this (np.tril and np.triu) doesn’t work for higher dimensions e.g.
A = np.array([[[1], [0], [6], [5]], [[0], [2],[0], [0]], [[1], [0], [2], [0]], [[0], [1], [0], [3]]]) # (4,4,1)
A = np.array([[[1,2], [0,3], [6,5], [5,6]], [[0,3], [2,2],[0,1], [0,3]], [[1,5], [0,2], [2,1], [0,9]], [[0,1], [1,2], [0,2], [3,4]]]) # (4,4,2)
Any ideas to do this efficiently (without for loops)? I don’t mind if you mirror the bottom or the top triangle of the matrix
This is a simple way to do that:
import numpy as np
# Example data, shape (4, 4, 2)
a = np.array([[[1, 2], [0, 3], [6, 5], [5, 6]],
[[0, 3], [2, 2], [0, 1], [0, 3]],
[[1, 5], [0, 2], [2, 1], [0, 9]],
[[0, 1], [1, 2], [0, 2], [3, 4]]])
# Lower triangle of ones, shape (4, 4, 1)
tril = np.tril(np.ones(a.shape[:-1], a.dtype))[..., np.newaxis]
# Eye matrix with extra dimension, shape (4, 4, 1)
eye = np.eye(a.shape[0], dtype=a.dtype)[..., np.newaxis]
# Lower triangle
atril = a * tril
# Add upper triangle and remove diagonal that was added twice
result = atril + atril.swapaxes(0, 1) - a * eye
# Check result
print(result[..., 0])
# [[1 0 1 0]
# [0 2 0 1]
# [1 0 2 0]
# [0 1 0 3]]
print(result[..., 1])
# [[2 3 5 1]
# [3 2 2 2]
# [5 2 1 2]
# [1 2 2 4]]
I have a list which contains lists,
testList = [[1, 0, 1], [1, 1, 1], [0, 0, 0], ...]
What I want to do is that add the list in groups of n, so if n is 2, the first two lists will be added together and the second two lists will be added together, it will be like [1, 0, 1] + [1, 1, 1] = [2, 1, 2].
I tried the following code,
group_len = 3
sumResultList = [[sum(x) for x in zip(*testList)] for group in [testList[i:i+group_len] for i in range(0, len(testList), group_len)]]
But the above code does not work, how do I solve this?
l = [[1, 0, 1], [1, 1, 1],
[0, 0, 0], [1, 0, 1],
[1, 1, 1], [1, 0, 1],
[1, 1, 1], [1, 1, 1]]
n = 2
print [[sum(x) for x in zip(*l[a:a+n])] for a in range(0,len(l),n)]
Output:
[[2, 1, 2], [1, 0, 1], [2, 1, 2], [2, 2, 2]]
Try this:
testList = [[1, 0, 1], [1, 1, 1], [0, 0, 0], [2,3,4], [2,3,4], [2,3,4]]
group_len = 2
res = [list(map(sum, zip(*testList[k:k+group_len]))) for k in range(0, len(testList), group_len)]
print(res)
output:
[[2, 1, 2], [2, 3, 4], [4, 6, 8]]
I'd like to enumerate the solution with a specific order. Currently, with the below code:
def balls_in_baskets(balls=1, baskets=1):
if baskets == 1:
yield [balls]
elif balls == 0:
yield [0]*baskets
else:
for i in range(balls+1):
for j in balls_in_baskets(balls-i, 1):
for k in balls_in_baskets(i, baskets-1):
yield j+k
x=[t for t in balls_in_baskets(3,3)][::-1]
for i in x:
print(i)
I get this:
[0, 0, 3]
[0, 1, 2]
[0, 2, 1]
[0, 3, 0]
[1, 0, 2]
[1, 1, 1]
[1, 2, 0]
[2, 0, 1]
[2, 1, 0]
[3, 0, 0]
However, I would like this order:
[0, 0, 3]
[0, 1, 2]
[1, 0, 2]
[0, 2, 1]
[1, 1, 1]
[2, 0, 1]
[0, 3, 0]
[1, 2, 0]
[2, 1, 0]
[3, 0, 0]
How can I achieve this correct order?
You already lose the memory-efficiency of your generator by consuming it in a list comprehension so you could also sort the result:
x = sorted(balls_in_baskets(3,3), key=lambda x: x[::-1], reverse=True)
which then prints the expected output:
[0, 0, 3]
[0, 1, 2]
[1, 0, 2]
[0, 2, 1]
[1, 1, 1]
[2, 0, 1]
[0, 3, 0]
[1, 2, 0]
[2, 1, 0]
[3, 0, 0]