moving an L-shaped piece on a grid - algorithm

i'm trying to code a small grid game, but i'm having trouble with coding piece movements.
I have a small 4x4 rgb pixels grid, initialized as np.zeros(4,4,3), full black. An update method to refresh objects position and free cells, a reset method, and a simple show function that uses cv2 to show the grid from a pixel matrix.
class Grid():
def __init__(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def update(self, c, l):
self.reset() #clear cells and free cells list
self.cells[c.x][c.y] = COIN_COL #set coin position
for i in range(len(l.coords)): #set L posiion
self.cells[l.coords[i][0]][l.coords[i][1]] = L_COL
for i in range(len(self.cells)): #calculate free cells
for j in range(len(self.cells)):
if np.amax(self.cells[i][j]) == 0:
self.free_cells.append((i, j))
def reset(self):
self.cells = np.zeros((SIZE, SIZE, 3), dtype=np.uint8)
self.free_cells = []
def show(self):
img = Image.fromarray(self.cells, "RGB")
img = img.resize((200,200))
cv2.imshow('img', np.array(img))
cv2.waitKey(0)
on the grid there are 2 pieces, an L-shaped one 3x2, and a coin 1x1.
they both have colors and coordinates
SIZE = 4
COIN_COL = (255,255,255)
L_COL = (0,0,255)
C_COORDS = np.array((0,0), dtype=np.uint8) #coin starting position
L_COORDS = np.array(((1,1),(2,1),(3,1),(3,2)), dtype=np.uint8) #L starting position
class Coin():
def __init__(self, coords):
self.x = coords[0]
self.y = coords[1]
class LShape():
def __init__(self, coords):
self.coords = coords
each piece can rotate, translate and move whenever he wants as long as it stays inside the grid, and does not overlap with other pieces.
moving the coin is straightforward: check empty cells, choose one, update coin coordinates, update grid.
Moving the L, doesn't look that simple. How can i check every possible legal move of such a piece? (there could be more than 1 coin on the grid). i started by calculating the empty cells, so that i have a layout of the free space, and i'm trying to come up with an algorithm to highlight legal moves by first removing isolated free cells (1x1), than removing isolated couples (2x1), and so on, but i got stuck halfway through.
I was also thinking about making a list of every possible position on an empty grid, and removing positions from the list if they require an occupied cell, but that doesn't seems elegant nor optimal.
Any idea on how to approach the problem?

Related

How do I programmatically create a grid of pixels given only the pixels neighbors

I'm trying to figure out an algorithm for building a grid, based on number of pixels and surrounding pixels. For instance let's say I have 200 random pixels. I have pixel a, and I can get references to each pixel surrounding it. This holds true for all the pixels. In essence each pixel is s puzzle piece, and each piece has a reference to all its neighbors. How do Programmatically creat the grid of pixels ( the finished puzzle ) given that information
Assuming your
Input is a list of pixels and each pixel has the attributes top, left, bottom and right (references to the surrounding pixels) and your
Output will be an 2D Array grid of pixels,
you can do as follows:
def pixel_graph_to_grid(pixels):
if len(pixels) == 0:
return [[]]
# (1) Finding the top left pixel.
p = pixels[0]
while p.top:
p = p.top
while p.left:
p = p.left
# (2) Go row-wise through the image.
grid = []
first_of_row = p
while True:
p = first_of_row
row = [p]
while p.right:
p = p.right
row.append(p)
grid.append(row)
if first_of_row.bottom:
first_of_row = first_of_row.bottom
else:
break
You can also do some counting similar to (1) to know how much memory you have to allocate for the grid.
This algorithm has linear runtime and requires constant extra space, so it should be optimal.

Animating Pygame Rects to move up the Screen

the endeavor is to draw clusters of rects [bubbles] moving up the screen at varying rates of speed. i've hit a roadblock when it comes to rendering the moving rects.
the way i've gone about it thus far is to populate a list with class instances of my Bubble class. from there i've iterated through the list of instances and called their blow_bubble method, effectively drawing each bubble at a different location on the screen and initializing each with its own value for its speed of movement. these bubbles are then appended to a separate list entitled "drawn", to signify that they have indeed been drawn (though not rendered).
the next part is where it gets bumpy.
i have a while loop that accepts the length of the drawn list being greater than zero as its condition for running. as per the form in this article: http://programarcadegames.com/index.php?chapter=introduction_to_animation
the screen surface is set to fill at the beginning of the loop and at the end of it i've updated the screen surface via pygame.display.flip(). in the middle of the while loop i'm iterating through class instances in the drawn list and decrementing the attribute that represents their y value by the instance's attributed rate of movement.
somehow this doesn't work.
i've checked to make sure the y value is actually decrementing; in a print statement the output is what would be expected: the y value descends into the negative numbers. yet the rects remain drawn statically.
as always, any insights are greatly appreciated.
#colors, screen, clock, etc defined above but omitted
pygame.init()
class Bubble():
def __init__(self, screenheight, screenwidth):
self.w = self.h = 0
self.x, self.y = 0, 0
self.moverate = 0
def reset_bubble(self):
self.w = self.h = random.randrange(2, int(screenwidth*1/4))
self.x = random.randrange(0, (screenwidth-self.w))
self.y = screenheight-self.w
self.moverate = 1
def blow_bubble(self):
self.reset_bubble()
pygame.draw.rect(screen, WHITE, (self.x, self.y, self.w, self.h), 10)
bubbles = []
drawn = []
i = 0
for i in range(10): #creates list of bubble objects
bubble = Bubble(screenheight, screenwidth)
bubbles.append(bubble)
for i in range(len(bubbles)): #draws bubbles without rendering them
bubbles[i].blow_bubble()
drawn.append(bubbles[i]) #appends objects to a new list (drawn)
while len(drawn) > 0:
screen.fill((BLACK))
drawn[i].y -= drawn[i].moverate #moves the bubble up the screen
pygame.display.flip() #updates the screen
if i >= 0: #counts up til len(drawn) then counts down [then up again]
i+=1 #to make sure we move every bubble a little each iteration
if i ==len(drawn):
i-= 1
clock.tick(FPS)
pygame.quit()
Unless I'm very much mistaken about how pygame works, you've misunderstood how it works. For oygamr to work it needs a 'render loop', a loop of code in which you repeatedly move the object, draw it with something like pygame.draw.rect, and then flip the display with pygame.display.flip. You keep doing this until you're done animating.
So, you need to make a bunch of changes.
your 'blow bubble' function needs to not reset the position of the bubble, just increment its position and call pygame.draw.rect
you don't need a 'dawn' list, just the first bubble list. Inside your while loop, you need to iterate through the bubble list calling 'blow bubble' on each.
you need to move the 'pygame.display.flip' inside the while loop, but after all the bubbles have been blown.
Your index out of range error is because I is not magically reset after the for loop exits, it leaves I as whatever it was when the for loop finished.

Generate paths on n*n grid

I have n*n grid, where for example n=10. I have to fill it with black and white elements. Every black element has to have one, two or three black neighbors. It is not allowed to contain black elements with four or zero neighbors.
How should I build this kind of grid ?
Edit:
To be more specific, it is two-dimensional array built for example with two for loops:
n = 10
array = [][];
for ( x = 0; x < n; x++ ) {
for ( y = 0; y < n; y++ ) {
array[x][y] = rand(black/white)
}
}
This pseudo code builds somethind like:
And what I expect is:
Obviously, you're trying to generate "black path" shapes on a write grid.
So let's just do it.
Start with a white grid.
Randomly position some turtles on it.
Then, while your grid doesn't meet a proper white/black cell ratio, do the following
Move each turtle one cell in a random direction and paint it black unless doing so break the "no more than three black neighbors" rule.
Maybe this python code could be of some use. Its basic idea is to do some sort of breadth first traversal of the grid, ensuring that the blackened pixels respect the constraint that they have no more than 3 black neighbours. The graph corresponding to the blackened part of the grid is a tree, as your desired result seemed to be.
import Queue
import Image
import numpy as np
import random
#size of the problem
size = 50
#grid initialization
grid = np.zeros((size,size),dtype=np.uint8)
#start at the center
initpos = (size/2,size/2)
#create the propagation queue
qu = Queue.Queue()
#queue the starting point
qu.put((initpos,initpos))
#the starting point is queued
grid[initpos] = 1
#get the neighbouring grid cells from a position
def get_neighbours(pos):
n1 = (pos[0]+1,pos[1] )
n2 = (pos[0] ,pos[1]+1)
n3 = (pos[0]-1,pos[1] )
n4 = (pos[0] ,pos[1]-1)
return [neigh for neigh in [n1,n2,n3,n4]
if neigh[0] > -1 and \
neigh[0]<size and \
neigh[1] > -1 and \
neigh[1]<size \
]
while(not qu.empty()):
#pop a new element from the queue
#pos is its position in the grid
#parent is the position of the cell which propagated this one
(pos,parent) = qu.get()
#get the neighbouring cells
neighbours = get_neighbours(pos)
#legend for grid values
#0 -> nothing
#1 -> stacked
#2 -> black
#3 -> white
#if any neighbouring cell is black, we could join two branches
has_black = False
for neigh in neighbours:
if neigh != parent and grid[neigh] == 2:
has_black = True
break
if has_black:
#blackening this cell means joining branches, abort
grid[pos] = 3
else:
#this cell does not join branches, blacken it
grid[pos] = 2
#select all valid neighbours for propagation
propag_candidates = [n for n in neighbours if n != parent and grid[n] == 0]
#shuffle to avoid deterministic patterns
random.shuffle(propag_candidates)
#propagate the first two neighbours
for neigh in propag_candidates[:2]:
#queue the neighbour
qu.put((neigh,pos))
#mark it as queued
grid[neigh] = 1
#render image
np.putmask(grid,grid!=2,255)
np.putmask(grid,grid<255,0)
im = Image.fromarray(grid)
im.save('data.png')
Here is a result setting size = 50
and another one setting size = 1000
You can also play with the root of the tree.
With the size that you show here, you could easily go for a bit of a brute force implementation.
Write a function that checks if you meet the requirements, simply by iterating through all cells and counting neighbors.
After that, do something like this:
Start out with a white grid.
Then repeatedly:
pick a random cell
If the cell is white:
make it black
call the grid checking routine.
if the grid became invalid:
color it gray to make sure you don't try this one again
do this until you think it took long enough, or there are no more white cells.
then make all gray cells white.
If your grid is large (thousands of pixels), you should probably look for a more efficient algorithm, but for a 10x10 grid this will be calculated in a flash.

Minimum area enclosing rectangles?

I need an idea for an algorithm to solve the following problem (I already tried some personal
solutions but they don't seem to be optimal)
If given a surface with marked and unmarked zones (in matrix form), and 2 rectangles
that you can manipulate in any form or position, find the possible shape and position
of the rectangles such that they cover all the marked zones while keeping the minimum
surface area possible.
This answer is assuming you can not rotate the rectangles and the sides are always parallel to the x and y axis.
First, find the rectangle that encloses the complete area. An algorithm for that goes like this (assuming the origin is at the topleft):
For each marked spot in the matrix:
if spot.x < rectangle.left:
rectangle.left = spot.x
if spot.x > rectangle.right:
rectangle.left = spot.x
if spot.y < rectangle.top:
rectangle.left = spot.x
if spot.y < rectangle.bottom:
rectangle.left = spot.x
Then, find the largest horizontal gap like this:
largest_gap = -1
For each column in matrix:
last_marked_spot = 0, 0
For each spot in column:
if spot.marked:
if spot.x - last_marked_spot.x > largest_gap:
largest_gap = spot.x - last_marked_spot.x
last_marked_spot = spot
Same goes for vertical gap. Then check which gap is the biggest.
Then divide the all-including rectangle in two parts using the biggest gap as seperator. The final step is to collapse the two rectangles (using the reverse of the algorithm on the top).

Hole in a Polygon

I need to create a 3D model of a cube with a circular hole punched at the center of one face passing completely through the cube to the opposite side. I am able to generate the vertices for the faces and for the holes.
Four of the faces (untouched by the hole) can be modeled as a single triangle strip. The inside of the hole can also be modeled as a single triangle strip.
How do I generate the index buffer for the faces with the holes? Is there a standard algorithm(s) to do this?
I am using Direct3D but ideas from elsewhere are welcome.
To generate the index-buffer you want, you could do like this. Thinking in 2D with the face in question as a square with vertices (±1, ±1), and the hole as a circle in the middle.
You walk along the edge of the circle, dividing it into some number of segments.
For each vertex, you project it onto the surrounding square with (x/M,y/M), where M is max(abs(x),abs(y)). M is the absolute value of the biggest coordinate, so this will scale (x,y) so that the biggest coordinate is ±1.
This line you also divide into some number of segments.
The segments of two succeeding lines you join pairwise as faces.
This is an example, subdividing the circle into 64 segments, and each ray into 8 segments. You can choose the numbers to match your requirements.
alt text http://pici.se/pictures/AVhcssRRz.gif
Here is some Python code that demonstrates this:
from math import sin, cos, pi
from itertools import izip
def pairs(iterable):
"""Yields the previous and the current item on each iteration.
"""
last = None
for item in iterable:
if last is not None:
yield last, item
last = item
def circle(radius, subdiv):
"""Yields coordinates of a circle.
"""
for angle in xrange(0,subdiv+1):
x = radius * cos(angle * 2 * pi / subdiv)
y = radius * sin(angle * 2 * pi / subdiv)
yield x, y
def line(x0,y0,x1,y1,subdiv):
"""Yields coordinates of a line.
"""
for t in xrange(subdiv+1):
x = (subdiv - t)*x0 + t*x1
y = (subdiv - t)*y0 + t*y1
yield x/subdiv, y/subdiv
def tesselate_square_with_hole((x,y),(w,h), radius=0.5, subdiv_circle=64, subdiv_ray=8):
"""Yields quads of a tesselated square with a circluar hole.
"""
for (x0,y0),(x1,y1) in pairs(circle(radius,subdiv_circle)):
M0 = max(abs(x0),abs(y0))
xM0, yM0 = x0/M0, y0/M0
M1 = max(abs(x1),abs(y1))
xM1, yM1 = x1/M1, y1/M1
L1 = line(x0,y0,xM0,yM0,subdiv_ray)
L2 = line(x1,y1,xM1,yM1,subdiv_ray)
for ((xa,ya),(xb,yb)),((xc,yc),(xd,yd)) in pairs(izip(L1,L2)):
yield ((x+xa*w/2,y+ya*h/2),
(x+xb*w/2,y+yb*h/2),
(x+xc*w/2,y+yc*h/2),
(x+xd*w/2,y+yd*h/2))
import pygame
def main():
"""Simple pygame program that displays the tesselated figure.
"""
print('Calculating faces...')
faces = list(tesselate_square_with_hole((150,150),(200,200),0.5,64,8))
print('done')
pygame.init()
pygame.display.set_mode((300,300))
surf = pygame.display.get_surface()
running = True
while running:
need_repaint = False
for event in pygame.event.get() or [pygame.event.wait()]:
if event.type == pygame.QUIT:
running = False
elif event.type in (pygame.VIDEOEXPOSE, pygame.VIDEORESIZE):
need_repaint = True
if need_repaint:
print('Repaint')
surf.fill((255,255,255))
for pa,pb,pc,pd in faces:
# draw a single quad with corners (pa,pb,pd,pc)
pygame.draw.aalines(surf,(0,0,0),True,(pa,pb,pd,pc),1)
pygame.display.flip()
try:
main()
finally:
pygame.quit()
You want to look up Tessellation which is the area of math that deals with what MizardX is showing.Folks in 3D Graphcs have to deal with this all the time and there are a variety of tessellation algorithms to take a face with a hole and calculate the triangles needed to render it.
Modern hardware usually can't render concave polygons correctly.
Specifically, there usually isn't even a way to define a polygon with a hole.
You'll need to find a triangulation of the plane around the hole somehow. The best way is probably to create triangles from a vertex of the hole to the nearest vertices of the rectangular face. This will probably create some very thin triangles. if that's not a problem then you're done. if it is then you'll need some mesh fairing/optimization algorithm to create nice looking triangles.
Is alpha blending out of the question? If not, just texture the sides with holes using a texture that has transparency in the middle. You have to do more rendering of polygons since you can't take advantage of drawing front-to-back and ignoring covered faces, but it might be faster than having a lot tiny triangles.
I'm imagining 4 triangle fans coming from the 4 corners of the square.
Just a thought -
If you're into cheating (as done many times in games), you can always construct a regular cube but have the texture for the two faces you desire with a hole (alpha = 0), you can then either clip it in the shader, or blend it (in which case you need to render with Z sort).
You get the inside hole by constructing an inner cylinder facing inwards and with no caps.
Of course this will only work if the geometry is not important to you.

Resources