I am working on designing a bejeweled style game with a twist. Rather than trying to match all the blocks of the same shape, you are trying to match a pair of letters. The board will always have roughly 10 letters on the board and you are trying to get them together. There are three different color blocks. Each color has 1 blank block and then 5 blocks with different letters. The goal is to get say a red "T" block next to a red "A" block. This is where I am running into problems.
Right now, the code will clear from the board three or more of the same color and letter. So, if I can get three red "T" blocks next to each other they will clear. The code basically scans each line looking for a group of three (or more). I have tried to modify the code so it will clear even just the same color (regardless of letter combo) but I can't even get that working. I think it has to do with how I load the images. I have posted most of the code (without any of my crazy modifications to try and get this working since it just broke it) that deals with loading the images and finding matches. Can anybody help me modify the code so it can at least find one correct match. When a red "T" block is next to a red "A" block and a blank red block, it should be classified as a match and be removed from the board. It doesn't need to be anything that complex as long as it works. Thanks for any help!
Find matches code:
def find_matches(self):
def lines():
for j in range(self.h):
yield range(j * self.w, (j + 1) * self.w)
for i in range(self.w):
yield range(i, self.size, self.w)
def key(i):
return self.board[i].image
def matches():
for line in lines():
for _, group in itertools.groupby(line, key):
match = list(group)
if len(match) >= MINIMUM_MATCH:
yield match
return list(matches())
Image loading:
shapes = 'red blue yellow'
rareshapes = 'reda redc redg redt redu bluea bluec blueg bluet blueu yellowa yellowc yellowg yellowt yellowu'
self.shapes = [pygame.image.load('images/{}.png'.format(shape))
for shape in shapes.split()]
self.rareshapes = [pygame.image.load('rareimages/{}.png'.format(shape))
for shape in rareshapes.split()]
EDIT:
Since this post, a lot has changed and been updated with the game. It has sound and background music, the groundwork for a new scoring system, a new timer system, and I can specify which rare shape I want to appear in a specific spot on the grid when the game first starts. However, I am still having issues with the core gameplay. I hate to drag up and older post, but I am at a loss as to how to get this to work. I have messed around with the code dealing with matches with no luck.
Basically, the rareshapes are assigned numbers. So, a red A is 0, a red T is 3, all the way up to a yellow T which is 14. For the gameplay to work the way we intend, the user will need to get a red A (0), a red T(3), and 2 blank red squares next to each other for it to be a valid match and clear from the board. This is the ONLY correct way you can clear squares from the board. Getting 4 blank squares of the same color next to each other DOES NOT remove them.
However, the code needs to detect if they get an invalid pair as well. For example, if they get a red A(0), a red C(1), and two blank red squares, it will disappear but count as a strike against them.
The goal of the game is to remove all the letter blocks before time runs out without getting three strikes. Since we can specify how many and where letter blocks appear now, it just comes down to the matching. Does anybody have any idea how to make this work?
I was reading the code you posted, and I said to myself, that looks pretty good — one-dimensional board representation, well-named variables, use of itertools.groupby — that's pretty much how I would have written it myself. And then I remembered that I had written it myself. Still, I'm glad to see someone's making use of my code!
(Having said that, I notice that you removed the docstring. Why did you do that? Put it back right away!)
Anyway, this match finder uses itertools.groupby to find runs of identical items in a sequence. Or rather, since a key function is given, runs of items where the key function returns identical results.
You can see that the key function as written just returns the image at the board location. This means that board locations match so long as they contain identical images. But you want to relax that: you want board locations to match so long as they contain images of the same colour.
So you need to revise the key function so that it returns the colour of the image at the board location. For example, when you loaded the images you could create a dictionary mapping images to their colour:
self.image_colour = {}
self.shapes = []
self.rareshapes = []
colours = 'red blue yellow'
letters = 'acgtu'
for c in colours.split():
im = pygame.image.load('images/{}.png'.format(c))
self.shapes.append(im)
self.image_colour[im] = c
for l in letters:
im = pygame.image.load('rareimages/{}{}.png'.format(c, l))
self.rareshapes.append(im)
self.image_colour[im] = c
and then in the key function you could look up the image to find its colour:
def key(i):
return self.image_colour.get(self.board[i].image)
Related
I've been trying to make a board game of GO, in python with pygame and a numpy array for storing the board locations and stone colors (0, 1, 2). My issue is that I've been using a for loop to examine each index at a time, and examining the adjacent indexes by adding or taking away an int:
columns = 5
rows = 5
def create_board():
board = np.zeros((row,col))
return board
board = create_board()
def libertyCheck():
for c in range(columns):
for r in range(rows):
if board[c][r+1] == 0:
x = 1
(lots more ifs, then add x's to see if all spaces are occupied)
This method seems to be OK for capturing a single stone (as long as its not on the edges of the board, because it also starts causing out of bounds issues), but becomes very convoluted once several stones of the same color are next to each other and may or may not need to be captured.
There has to be a better way of searching these indexes without causing out of bounds? one that will allow me to keep track of all of the stones and their adjacent spaces?
I'm trying to create a game in which 100 rocks are scattered through a large series of coordinates randomly. The problem is that sometimes the rocks may overlap each other. The solution I came up with was to check if the rocks overlap each other, and if they do, create new randomly generate coordinates for the rock again and again until it collides with nothing. I'm not entirely sure how to do this; I've tried detecting collision between the rock and the rock list, but all that ends up happening is that it thinks that it collides with itself and always returns as True. The __init__ function generates the coordinates with random.randint(-2500,2500). When the rocks are created in the for loop, each rock is added to the list. In the update function it checks for rectangular collision between the rocks. How can I fix this? Thanks, an answer would be much appreciated. Ask me if you need more information.
Well, I guess there are a few ways you can approach this problem:
1) The first would be the one you already used, you would check for collisions each time you generate a rock and if a collision exist you would regenerate a position for the given rock
2) The second one would be to slice your "field" into rectangles of the size of the rock, just like a tilemap, therefore creating a list of possible positions, something like this:
possible_positions = [(i, j) for i in range(x_size_field//x_size_rock) for j in range(y_size_field//y_size_rock)]
for i in range(n_of_rocks):
rock_pos = random.choice(possible_positions)
possible_positions.remove(rock_pos)
But this approach would implicate in a given set of possible positions that make a "uniform" rock distribution
3) So if its really necessary to make put the rocks on absolute random positions you could create a list of possible positions like the following:
possible_positions = [[(i, j) for j in range(y_size_field-y_size_rock)] for i in range(x_size_field-x_size_rock)]
for i in range(n_of_rocks):
# X and Y represente positions on the list not on the field
x = random.randint(0, len(possible_positions))
y = random.randint(0, len(possible_positions[x]))
# The rock positions
rock_pos = possible_positions[x][y]
# Now we remove the positions on the region of the new rock
for i in range(x,x+x_size_rock):
possible_positions[i] = possible_positions[i][0:y] + possible_positions[i][y+y_size_rock:-1]
if [] in possible_positions:
possible_positions.remove([])
Of course this code may generate errors (its a rather simple code) and it needs some optimizations, but i think you may get the general ideia from this.
Sorry about my english
I'm a language teacher and green newbie to Python. I'm trying to write a program that converts text input into series of colored boxes. The end result should be something that looks a bit like a cubist painting. (The idea is to turn boring grammar and vocabulary into colorful patterns to motivate students.)
It's my first attempt to work with GUI and so far I haven't a real clue where to look for tutorials that help me realize the following:
1) Automatically assigning a different color to each letter of the alphabet (with the assignment open for later modification)
2) Display the assignment of all color-letter pairings so that the user which color means which.
3) Transform an input into chains of brightly colored squares.
As for the code, I've only come up with the following sketch before finding myself in a blind alley:
from tkinter import *
master = Tk()
b = 600
h = 400
w = Canvas(master,
width=b,
height=h)
w.pack()
# START POSITION
X = 1
Y = 1
# Width and height of the colored squares
width = 50
height = 50
w.create_rectangle(1, 1, 50, 50, fill="yellow")
w.create_rectangle(60, 1, 110, 50, fill="red")
I don't want to ask for free code, but maybe a pointer or two where I have to look for answers.
It sounds like you want to assign colors randomly. You could make a list of colors you like, and then use a random number to select an entry from that list, or you could just generate random RGB values for truly random colors (http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/colors.html). Also, Python's ord() method is useful for turning characters into numbers, if that's something you find you can make use of.
If you want to display and modify pairings, you could use a dictionary, e.g.:
{'a':"red", 'b':"blue", ... }
Then, to line up your rectangles, just use a loop and increment your coordinates each time. The modulo operator (%) could be used to help you wrap around onto each new row.
I've got an array of data filled with "#" and "." for example it display something like this :
...........#############..............................
.........################..................#######....
........##################................#########...
.......####################..............###########..
........##################................#########...
.........################..................#######....
...........#############..............................
I want to create an algorithm that find the bigger ball and erase the smaller one.
I was thinking of using the longest sequence of "#" to know what is the diameter.
So i've got something like this :
x = 0
longest_line = 0
for i in range(0, nbLine) :
for j in range(0, nbRaw) :
if data[i, j] = red :
x = x+1
if data[i, j+1] != red:
And i don't know what to do next..
I would use some sort of a segmentation algorithm, and then simply count the number of pixels in each object. Then simply erase the smaller one, which should be easy as you have a tag of the object.
The segmentation algorithms typically work like this.
Perform a raster scan, starting upper left, working towards bottom right.
As you see a #, you know you have an object. Check it's neighbors.
If the neighbors have a previously assigned value, assign that value to it
If there there are multiple values, put that into some sort of a table, which after you are done processing, you will simplify.
So, for a very simple example:
...##...
.######.
...##...
Your processing will look like:
00011000
02111110
00011000
With a conversion such that:
2=>1
Apply the look up table, and all objects will be tagged with a 1 value. Then simply count the number of pixels, and you are done.
I'll leave the implementation to you;-)
Get your data into a nicer array structure
Perform connected component labelling
Count the number of elements with each label (ignoring the background label)
Choose the label with the largest number of elements
Do you olways have only 2 shapes like this? Because in this case, you could also use the python regular expression library. This code seems to do the trick for your example (I copied your little drawing in a file and named it "balls.txt"):
import re
f = open("balls.txt", "r")
for line in f :
balls = re.search("(\.+)(#+)(\.+)(#*)(\.+)", line)
dots1 = balls.groups()[0]
ball1 = balls.groups()[1]
dots2 = balls.groups()[2]
ball2 = balls.groups()[3]
dots3 = balls.groups()[4]
if len(ball1) < len(ball2):
ball1 = ball1.replace('#', '.')
else:
ball2 = ball2.replace('#', '.')
print "%s%s%s%s%s" % (dots1, ball1, dots2, ball2, dots3)
And this is what I get:
...........#############..............................
.........################.............................
........##################............................
.......####################...........................
........##################............................
.........################.............................
...........#############..............................
I hope this can give you some ideas for the resolution of your problem
Assuming the balls don't touch:
Assuming exactly two balls
Create two ball objects, (called balls 0 and 1) each owns a set of points. Points are x,y pairs.
scan each row from top to bottom, left to right within each line.
When you see the first #, assign it to ball 0 (add it’s x,y cords to the set owned by the ball 0 object).
When you see any subsequent #, add it to ball 0 if it is adjacent to any point already in ball 0; otherwise add it to ball 1. (If the new # is at x, y we just test (x+1,y) is in set, (x-1, y) is in set, (x, y+1) is in set, (x, y-1) is in set, and the diagonal neighbors)
When the scan is complete, the list sizes reveal the larger ball. You then have a list of the points to be erased in the other ball’s points set.
A while back I wrote a simple python program to brute-force the single solution for the drive ya nuts puzzle.
(source: tabbykat.com)
The puzzle consists of 7 hexagons with the numbers 1-6 on them, and all pieces must be aligned so that each number is adjacent to the same number on the next piece.
The puzzle has ~1.4G non-unique possibilities: you have 7! options to sort the pieces by order (for example, center=0, top=1, continuing in clockwise order...). After you sorted the pieces, you can rotate each piece in 6 ways (each piece is a hexagon), so you get 6**7 possible rotations for a given permutation of the 7 pieces. Totalling: 7!*(6**7)=~1.4G possibilities. The following python code generates these possible solutions:
def rotations(p):
for i in range(len(p)):
yield p[i:] + p[:i]
def permutations(l):
if len(l)<=1:
yield l
else:
for perm in permutations(l[1:]):
for i in range(len(perm)+1):
yield perm[:i] + l[0:1] + perm[i:]
def constructs(l):
for p in permutations(l):
for c in product(*(rotations(x) for x in p)):
yield c
However, note that the puzzle has only ~0.2G unique possible solutions, as you must divide the total number of possibilities by 6 since each possible solution is equivalent to 5 other solutions (simply rotate the entire puzzle by 1/6 a turn).
Is there a better way to generate only the unique possibilities for this puzzle?
To get only unique valid solutions, you can fix the orientation of the piece in the center. For example, you can assume that that the "1" on the piece in the center is always pointing "up".
If you're not already doing so, you can make your program much more efficient by checking for a valid solution after placing each piece. Once you've placed two pieces in an invalid way, you don't need to enumerate all of the other invalid combinations.
If there were no piece in the centre, this would be easy. Simply consider only the situations where piece 0 is at the top.
But we can extend that idea to the actual situation. You can consider only the situations where piece i is in the centre, and piece (i+1) % 7 is at the top.
I think the search space is quite small, though the programming might be awkward.
We have seven choices for the centre piece. Then we have 6 choices for the
piece above that but its orientation is fixed, as its bottom edge must match the top edge of the centre piece, and similarly whenever we choose a piece to go in a slot, the orientation is fixed.
There are fewer choices for the remaining pieces. Suppose for
example we had chosen the centre piece and top piece as in the picture; then the
top right piece must have (clockwise) consecutive edges (5,3) to match the pieces in
place, and only three of the pieces have such a pair of edges (and in fact we've already
chosen one of them as the centre piece).
One could first off build a table with a list
of pieces for each edge pair, and then for each of the 42 choices of centre and top
proceed clockwise, choosing only among the pieces that have the required pair of edges (to match the centre piece and the previously placed piece) and backtracking if there are no such pieces.
I reckon the most common pair of edges is (1,6) which occurs on 4 pieces, two other edge pairs ((6,5) and (5,3)) occur on 3 pieces, there are 9 edge pairs that occur on two pieces, 14
that occur on 1 piece and 4 that don't occur at all.
So a very pessimistic estimate of the number of choices we must make is
7*6*4*3*3*2 or 3024.