I'm making a minesweeper game using python. I have the game working in a text only form and I'm adding a GUI now.
I have three difficulty options with different dimensions. Is there any way to generate a grid without having to make it manually. This is how I generated a square matrix in text form:
for count in range(side):
count2 = 0
temp1 = []
temp2 = []
for count2 in range(side):
temp1.append(0)
temp2.append("x")
grid.append(temp1)
field.append(temp2)
count+=1
Is there any way to automatically generate a grid like this in pygame? I am also using custom sprites and every cell needs to be clickable. Will I just have to make the grids manually and use them according to the difficulty?
I came across a similar issue, here is the solution I found worked well and is fairly simple to implement.
gridstate = {}
class Button:
def __init__(self, x, y, w, h, *get_co, action=False):
self.x = x
self.y = y
self.w = w
self.h = h
self.get_co = get_co
self.colour = (255, 255, 255)
self.clicked = False
self.box = py.draw.rect(screen, self.colour, (x, y, w, h))
self.action = action
def draw(self):
pos = py.mouse.get_pos()
if self.box.collidepoint(pos):
if py.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
if self.action == False:
self.action = True
self.colour = (255, 0, 0)
elif self.action == True:
self.action = False
self.colour = (255, 255, 255)
if py.mouse.get_pressed()[0] == 0:
self.clicked = False
self.box = py.draw.rect(screen, self.colour,
(self.x, self.y, self.w, self.h))
gridstate.update({self.get_co: self.action})
return self.action
I created the class for the button as above, this accepts the argument "get_co" to which I put the 'co ordinate' relative to the rest of the grid so I am able to identify which button was pressed. I pass in the data in like so - This creates a 10x10 grid
resx = 10
resy = 10
buttonsize = 25
grid = []
for x in range(resx):
for y in range(resy):
grid.append(Button((x*buttonsize), (y*buttonsize),
buttonsize, buttonsize, x, y))
Within the loop of game I simply run
activecells = []
for key, value in gridstate.items():
if value == True:
activecells.append(key)
To find the clicked buttons and add them to a list to reference later.
for row in grid:
row.draw()
To draw the grid to the screen.
This seemed to do the trick for me. Apologies ahead of time for any actual programmers who will probably be horrified by my variable naming!
There is no simple solution to draw a grid. You have to loop over each cell as you did in your example. You can find all functions to draw in the pygame wiki.
Example for grid creation:
size = (100, 100)
cell_width = 10
cell_height = 10
grid_surface = pygame.Surface(size) # here you draw
grid = [] # simple list to save your data
for x in range(side):
grid.append([]) # new column for the list
for y in range(side):
# save data to grid
grid[x][y] = "x"
# draw something
# e.g.: this draws a red rectangle in each cell
pygame.draw.rect(grid_surface, (200, 0, 0), (x * cell_width, y * cell_height, cell_width, cell_height)
Potential event loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = (event.pos[0] // cell_width, event.pos[1] // cell_height)
# do something
print(grid[x][y])
grid[x][y] = "a"
pygame.draw.rect(grid_surface, (0, 200, 0), (x * cell_width, y * cell_height, cell_width, cell_height)
I will give you a very simple start. You should create a class that represents a cell in the grid. Create a matrix of cells to represent your board:
class Cell:
def __init__(self):
self.clicked = False
grid_size = 10
board = [[Cell() for _ in range(grid_size)] for _ in range(grid_size)]
Calculate the index of a cell when the mouse button is clicked and change the attributes in the cell:
for event in pygame.event.get():
# [...]
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
row = event.pos[1] // 20
col = event.pos[0] // 20
board[row][col].clicked = True
Draw the board in 2 nested loops:
for iy, rowOfCells in enumerate(board):
for ix, cell in enumerate(rowOfCells):
color = (64, 64, 64) if cell.clicked else (164, 164, 164)
pygame.draw.rect(window, color, (ix*20, iy*20, 20, 20))
Minimal example:
import pygame
class Cell:
def __init__(self):
self.clicked = False
grid_size = 10
board = [[Cell() for _ in range(grid_size)] for _ in range(grid_size)]
pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
row = event.pos[1] // 20
col = event.pos[0] // 20
board[row][col].clicked = True
window.fill(0)
for iy, rowOfCells in enumerate(board):
for ix, cell in enumerate(rowOfCells):
color = (64, 64, 64) if cell.clicked else (164, 164, 164)
pygame.draw.rect(window, color, (ix*20+1, iy*20+1, 18, 18))
pygame.display.flip()
pygame.quit()
exit()
Related
Right now, my game blits all the images in random positions correctly and also gets the rect of the images correctly, but I can´t figure out how to use colliderect to make sure the images don´t overlap. How could it work for my code?
Also I´m trying to make the first text fade out and I don´t know why it doesn´t work for me.
Here is the code:
class GAME1:
def __init__(self, next_scene):
self.background = pygame.Surface(size)
# Create an array of images with their rect
self.images = []
self.rects = []
self.imagenes1_array = ['autobus.png','coche.png','barco.png','autobus2.png','grua.png','bici.png']
for i in self.imagenes1_array:
# We divide in variables so we can then get the rect of the whole Img (i2)
i2 = pygame.image.load(i)
self.images.append(i2)
s = pygame.Surface(i2.get_size())
r = s.get_rect()
# Trying to use colliderect so it doesnt overlap
if pygame.Rect.colliderect(r,r) == True:
x = random.randint(300,1000)
y = random.randint(200,700)
self.rects.append(r)
def start(self, gamestate):
self.gamestate = gamestate
for rect in self.rects:
# Give random coordinates (we limit the dimensions (x,y))
x = random.randint(300,1000)
y = random.randint(200,700)
rect.x = x
rect.y = y
def draw(self,screen):
self.background = pygame.Surface(size)
font = pygame.font.SysFont("comicsansms",70)
# First half (Show image to remember)
text1 = font.render('¡A recordar!',True, PURPLE)
text1_1 = text1.copy()
# This surface is used to adjust the alpha of the txt_surf.
alpha_surf = pygame.Surface(text1_1.get_size(), pygame.SRCALPHA)
alpha = 255 # The current alpha value of the surface.
if alpha > 0:
alpha = max(alpha-4, 0)
text1_1 = text1.copy()
alpha_surf.fill((255, 255, 255, alpha))
text1_1.blit(alpha_surf, (0,0), special_flags = pygame.BLEND_RGBA_MULT)
screen.blit(text1_1, (600,50))
# Second half (Show all similar images)
text2 = font.render('¿Cuál era el dibujo?',True, PURPLE)
#screen.blit(text2, (500,50))
for i in range(len(self.images)):
#colliding = pygame.Rect.collidelistall(self.rects)
screen.blit(self.images[i], (self.rects[i].x, self.rects[i].y))
def update(self, events, dt):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
for rect in self.rects:
if rect.collidepoint(event.pos):
print('works!')
Use collidelist() to test test if one rectangle in a list intersects:
for i in self.imagenes1_array:
s = pygame.image.load(i)
self.images.append(s)
r = s.get_rect()
position_set = False
while not position_set:
r.x = random.randint(300,1000)
r.y = random.randint(200,700)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in self.rects]
if len(self.rects) == 0 or r.collidelist(rl) < 0:
self.rects.append(r)
position_set = True
See the minimal example, that uses the algorithm to generate random not overlapping rectangles:
import pygame
import random
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
def new_recs(rects):
rects.clear()
for _ in range(10):
r = pygame.Rect(0, 0, random.randint(30, 40), random.randint(30, 50))
position_set = False
while not position_set:
r.x = random.randint(10, 340)
r.y = random.randint(10, 340)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in rects]
if len(rects) == 0 or r.collidelist(rl) < 0:
rects.append(r)
position_set = True
rects = []
new_recs(rects)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
new_recs(rects)
window.fill(0)
for r in rects:
pygame.draw.rect(window, (255, 0, 0), r)
pygame.display.flip()
pygame.quit()
exit()
I am a beginner programmer trying to build tetris in Python using Pygame. The problem is that I am unable to make my test shape fall. Only go up. When I attempt to make the shape fall, the program gives me an
IndexError: list assignment index out of range
I was wondering if I could please get help? The code is listed as follows.
import pygame, sys
from pygame.locals import *
import base64
from TetrisFont import Tetrisfont
from RGBTitle import RGBTitle
from TetrisLogo import logo
from BSOD import Cancer
from BSODFont import Death
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
DOWN = pygame.USEREVENT
class Game:
def __init__(self):
self.running = True
def run(self):
# The main gameplay loop
self.load_assets()
self.initialize_game()
clock = pygame.time.Clock()
while self.running:
self.handle_events()
self.update(clock.tick())
self.draw()
def handle_events(self):
for event in pygame.event.get():
if event.type == DOWN:
for ix, x in enumerate(self.grid):
for iy, y in enumerate(self.grid[0]):
print (y, end='')
print('') # create a new line
for x in range(len(self.grid)):
for y in range(len(self.grid[0])):
if self.grid[x][y] == True:
self.grid[x][y]= False
self.grid[x][y+1] = True
# print(x, y+1)
if event.type == QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
def draw(self):
# Handle game rendering
self.windowSurface.fill(BLACK)
pygame.draw.rect(self.windowSurface,WHITE,(550,0, 250, 600), 2)
for x in range(0,600,50):
pygame.draw.line(self.windowSurface,WHITE,(1,x),(550,x), 2)
pygame.draw.line(self.windowSurface,WHITE,(x,1),(x,550), 2)
self.title.render(self.windowSurface)
for x in range(len(self.grid)):
for y in range(len(self.grid[0])):
if self.grid[x][y] == True:
# draw a block in the right place
# render_rect(X * 50, Y * 50, )
pygame.draw.rect(self.windowSurface, RED, (x*50+2, y*50+2, 48, 48))
pygame.display.update()
def update(self, deltaTime):
pass
def load_assets(self):
# Load assets needed for the game. This should only be called once.
pygame.init()
pygame.time.set_timer(DOWN, 500)
with open('Tetrisfont.ttf', 'wb') as imagef:
imagef.write(base64.b64decode(Tetrisfont))
self.Font = pygame.font.Font('Tetrisfont.ttf', 48)
with open('Logo.png', 'wb') as imagef:
imagef.write(base64.b64decode(logo))
with open('BSODFont.ttf', 'wb') as imagef:
imagef.write(base64.b64decode(Death))
self.BSODFont = pygame.font.Font('BSODFont.ttf', 48)
with open('BSOD.png', 'wb') as imagef:
imagef.write(base64.b64decode(Cancer))
self.windowSurface = pygame.display.set_mode((800, 600), 0, 32)
pygame.display.set_caption('Tetris')
self.a = pygame.image.load('Logo.png')
pygame.display.set_icon(self.a)
def initialize_game(self):
# Set up the board for play. This can happen multiple times to restart the game.
self.score = 0
self.title = RGBTitle(self.Font, "Tetris", (200, 550), [WHITE, RED, GREEN, BLUE, GREEN, RED])
grid_width = 11
grid_height = 11
self.grid = [[0 for x in range(grid_width)] for y in range(grid_height)]
# self.grid = []
# for x in range(11):
# self.grid.append([False] * 11)
self.grid[5][5] = True
# print(self.grid)
# print(len(self.grid))
# print(len(self.grid[0]))
if __name__ == '__main__':
g = Game()
g.run()
Thank you.
The error is caused, by self.grid[x][y+1] in
for x in range(len(self.grid)):
for y in range(len(self.grid[0])):
if self.grid[x][y] == True:
self.grid[x][y]= False
self.grid[x][y+1] = True
If y is equal self.grid[0]-1, then y+1 is out of range.
Add an additional condition if y+1 < len(self.grid[0]). Furthermore, I recommend to iterate through the grid in reversed() order from the bottom to the top:
for x in range(len(self.grid)):
for y in reversed(range(len(self.grid[0]))):
if self.grid[x][y] == True:
self.grid[x][y] = False
if y+1 < len(self.grid[0]):
self.grid[x][y+1] = True
I am having trouble sorting out a loop in my program which does not behave a I would expect. This program lets you play "Connect Four". I included the full (runnable code) and the excerpt that troubles me at the end.
import numpy as np
import random
import pygame
import time
BOARD_SIZE = 6
BOARD_BOX_NUM = BOARD_SIZE ** 2
GIVEN_IDS = 0
# ------------------------------- setting up pygame --------------------------------------------
pygame.init()
display_height = 600
display_width = 600
game_display = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
# ------------------------------- colours ----------------------------------------------------
white = (255, 255, 255)
black = (0, 0, 0)
blue = (0,0,255)
light_blue = (30, 144, 255)
red = (200, 0, 0)
light_red = (255, 0, 0)
yellow = (200, 200, 0)
light_yellow = (255, 255, 0)
green = (34, 177, 76)
light_green = (0, 255, 0)
# ------------------------------- methods for the game algorythm ------------------------------
def rolling_window(a, size):
# This method is required for the algorythm that broadcasts the board for a win
shape = a.shape[:-1] + (a.shape[-1] - size + 1, size)
strides = a.strides + (a. strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)
class Chip:
def __init__(self, colour):
if colour == "Blue":
self.colour = colour
if colour == "Red":
self.colour = colour
global GIVEN_IDS
self.iD = GIVEN_IDS
GIVEN_IDS += 1
def get_iD(self):
return self.iD
class Game:
def __init__(self, player_colour="Blue", comp_colour="Red"):
self.board = np.empty(BOARD_BOX_NUM, dtype=Chip)
self.board = self.board.reshape(BOARD_SIZE, BOARD_SIZE)
self.player_colour = player_colour
self.comp_colour = comp_colour
def get_comp_colour(self):
return self.comp_colour
def get_player_colour(self):
return self.player_colour
def give_str_board(self):
"""Returns a copy of the board array and replaces the Chip objects with the str with the colour of the chips."""
this_board = np.copy(self.board)
for x, y in np.ndindex(this_board.shape):
if this_board[x, y] is not None:
if this_board[x, y].colour == "Blue":
this_board[x, y] = "Blue"
else:
this_board[x, y] = "Red"
return this_board
def print_board_in_console(self):
"""This function holds the board which is a 8x8 matrix."""
this_board = self.give_str_board()
print(this_board)
print("-"*40)
def insert_chip(self, chip, col):
"""Method for making a new entry to the board. For the player and enemy.
The column has to be parametrised in the pythonic way. i.e. cols from 0-7."""
# slices the entries of the column into a new array
col_entries = self.board[:, col:col+1]
# checks for all unoccupied pos in this column(entries are None)
# double array of indexes with the form (array([row_i, ...]), array([column_i, ...]))
# checking the condition with "is" is here not possible, because "is" operator cannot be overloaded
none_indexes = np.where(col_entries == None)
# check whether the column cannot contain an extra chip and function has to be aborted
if len(none_indexes[0]) == 0:
print("This column is full. Chose again.")
return False
# the pos where the chip will fall is the one with the highest index
self.board[len(none_indexes[0]) - 1, col] = chip
return True
def get_chip(self, x, y):
"""This function can return the information about a chip in a pos of the board."""
chip = self.board[x, y]
return chip
def is_won(self):
"""This function can be used to check the board on whether the game has been decided.
The function differentiates between player and enemy and returns..."""
winning_chip = None
# get a copy of the board which only contains str and None
this_board = self.give_str_board()
flipped_board = np.fliplr(this_board)
# in order to check the entire board for 4 Chips in a formation individual rows and cols are examined
# use for loops to isolate rows and cols
for this_ax in range(0, 2):
for index in range(0, BOARD_SIZE):
# the stack will contain the row[index] when this_ax = 0 and the col[index] when this_ax = 1
stack = this_board.take(index, axis=this_ax)
# this will be the patterns, that are searched for
winning_formations = [['Blue', 'Blue', 'Blue', 'Blue'], ['Red', 'Red', 'Red', 'Red']]
for i in winning_formations:
bool_array = rolling_window(stack, 4) == i
if [True, True, True, True] in bool_array.tolist():
# the stack_index is the index of the first chip in the 4xChip formation in the row/col
stack_index_tuple, = np.where(np.all(bool_array == [True, True, True, True], axis=1))
stack_index = stack_index_tuple[0]
loop_index = index
# this_ax = 0 means loop_index is row and stack_index is col
if this_ax == 0:
winning_chip = self.get_chip(loop_index, stack_index)
break
else:
winning_chip = self.get_chip(stack_index, loop_index)
break
# This next part of the algorythm checks whether diagonal patterns of the array
# contain a winning formation
# if this bit is problematic: change the 0 in range()!!!
for index in range(0, BOARD_SIZE - 2):
for board in [this_board, flipped_board]:
diag_elements = board.diagonal(index)
for i in winning_formations:
bool_array = rolling_window(diag_elements, 4) == i
if [True, True, True, True] in bool_array.tolist():
# the stack_index is the index of the first chip in the 4xChip formation in the row/col
diag_el_index_tuple, = np.where(
np.all(bool_array == [True, True, True, True], axis=1))
diag_index = diag_el_index_tuple[0]
loop_index = index
# this_ax = 0 means loop_index is row and stack_index is col
if board == this_board:
winning_chip = self.get_chip(loop_index, diag_index)
break
else:
winning_chip = self.get_chip(diag_index, loop_index)
break
if winning_chip is not None:
return winning_chip.colour
return None
def get_comp_move(self):
"""This method generates the computer's move (the column) based on INTELLIGENCE!!!!
Returns the column of the move"""
c_colour = self.get_comp_colour()
p_colour = self.get_player_colour()
# check, if the comp can win in the next move
for i in range(0, BOARD_SIZE):
board = self.give_str_board()
chip = Chip(c_colour)
self.insert_chip(chip, i)
if self.is_won() == c_colour:
return i
# check, if the player can win in the next move and block that position
for i in range(0, BOARD_SIZE):
board = self.give_str_board()
chip = Chip(p_colour)
self.insert_chip(chip, i)
if self.is_won() == p_colour:
return i
# accumulate preferable positions for the next move
good_spots = []
board = self.give_str_board()
for axis in range(0, 2):
for index in range(0, BOARD_SIZE):
# the stack will contain the row[index] when this_ax = 0 and the col[index] when this_ax = 1
stack = board.take(index, axis=axis)
# this will be the patterns, that are searched for
for i in [c_colour, c_colour]:
bool_array = rolling_window(stack, 2) == i
if [True, True] in bool_array.tolist():
# the stack_index is the index of the first chip in the 4xChip formation in the row/col
stack_index_tuple, = np.where(np.all(bool_array == [True, True], axis=1))
stack_index = stack_index_tuple[0]
# this_ax = 0 means loop_index is row and stack_index is col
if axis == 0:
# "- 1" because this if-statement is called when broadcasting a row. i.e. column before
good_spots.append(stack_index - 1)
else:
good_spots.append(index)
# The pick is the x-coo of the first of a series of two chips (column) or the x before (row).
print(good_spots)
pick = random.randint(0, len(good_spots))
return pick
# make a move, "better than nothing"
flag = True
while flag is True:
rnd = random.randint(0, BOARD_SIZE)
if self.board[rnd, 0] is None:
return rnd
# ------------------------------- this part will take care of the visualisation in pygame ------------------------
# buttons = []
#
# def button(self, text, x, y, radius, inactive_colour, active_colour, action=None, size=" "):
# cur = pygame.mouse.get_pos()
# if x + radius > cur[0] > x - radius and y + radius > cur[1] > y - radius:
# pygame.draw.circle(game_display, active_colour, (x, y), radius)
#
# ix = None
# iy = None
# for event in pygame.event.get():
# if event.type == pygame.MOUSEBUTTONDOWN:
# ix, iy = event.pos
#
# if ix is not None and iy is not None:
# if x + radius > ix > x - radius and y + radius > iy > y - radius and action is not None:
# if action == "quit":
# pygame.quit()
# quit()
#
# if action == "move":
# col = int(x / 80 - 90)
# self.insert_chip(Chip(self.get_player_colour()), col)
# else:
# pygame.draw.circle(game_display, inactive_colour, (x, y), radius)
def draw_board(self):
board = self.give_str_board()
pygame.draw.rect(game_display, green, (60, 60, 80*BOARD_SIZE, 80*BOARD_SIZE))
for y in range(0, BOARD_SIZE):
for x in range(0, BOARD_SIZE):
dx = 90 + x * 80
dy = 90 + y * 80
if board[x, y] is None:
pygame.draw.circle(game_display, white, (dy, dx), 30)
elif board[x, y] == "Blue":
pygame.draw.circle(game_display, blue, (dy, dx), 30)
elif board[x, y] == "Red":
pygame.draw.circle(game_display, red, (dy, dx), 30)
# draw the selector square
pygame.draw.rect(game_display, yellow, (self.selector_pos * 80 + 80, 60, 20, 20))
selector_pos = 0
def move_selector(self, dir):
selector_pos = self.selector_pos
if dir == 'left' and selector_pos >= 0:
new_x = selector_pos * 80 - 80
pygame.draw.rect(game_display, yellow, (new_x, 60, 20, 20))
self.selector_pos -= 1
if dir == 'right' and selector_pos <= BOARD_SIZE - 1:
new_x = selector_pos * 80 + 80
pygame.draw.rect(game_display, yellow, (new_x, 60, 20, 20))
self.selector_pos += 1
def intro(self):
return
def game_loop(self, comp_goes_first=False):
game_over = False
while game_over is not True:
# here comes the computer's move
if comp_goes_first is True:
col = self.get_comp_move()
chip = Chip(self.get_comp_colour())
self.insert_chip(chip, col)
# This will be the player move
move_over = False
while move_over is not True:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.move_selector('right')
pygame.draw.rect(game_display, yellow, (50, 50, 50, 50))
if event.key == pygame.K_LEFT:
self.move_selector('left')
if event.key == pygame.K_RETURN:
# the selector position indicates the column which the player has chosen.
col = self.selector_pos
chip = Chip(self.get_player_colour())
move_over = self.insert_chip(chip, col)
game_display.fill(white)
self.draw_board()
pygame.display.update()
comp_goes_first = True
clock.tick(15)
game = Game()
game.game_loop()
Now to the part that particularly leaves me in doubt.
As the following loop runs, I can make the Player's move in the game as expected with the use of arrow keys and return, however then the program goes crazy. It will do multiple moves for the computer and sometimes the player as well. This is a picture of the GUI after the loop has run once (player's move and then the computer's move and now it would be the players move again).
At this point I am wondering whether I got something fundamentally wrong with the while loop construction here and I cannot figure it out. What is the issue?
game_over = False
while game_over is not True:
# here comes the computer's move
if comp_goes_first is True:
col = self.get_comp_move()
chip = Chip(self.get_comp_colour())
self.insert_chip(chip, col)
# This will be the player move
move_over = False
while move_over is not True:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.move_selector('right')
if event.key == pygame.K_LEFT:
self.move_selector('left')
if event.key == pygame.K_RETURN:
# the selector position indicates the column which the player has chosen.
col = self.selector_pos
chip = Chip(self.get_player_colour())
move_over = self.insert_chip(chip, col)
game_display.fill(white)
self.draw_board()
pygame.display.update()
comp_goes_first = True
clock.tick(15)
Your problem looks to me to be in your AI logic. You're making a copy of the board for the AI to experiment on, but then you're not using it, and instead inserting chips into the real board.
# check, if the comp can win in the next move
for i in range(0, BOARD_SIZE):
# Never used.
board = self.give_str_board()
chip = Chip(c_colour)
# inserting onto the real board.
self.insert_chip(chip, i)
print("insert check", board, self)
if self.is_won() == c_colour:
return i
I've recently written a program with a list, but now I need to change the list into a matrix. I programmed a grid by drawing rectangles. Now I want to change the color of the rectangle when I click on it. In my program with the list everything worked just fine, but now I have to use a matrix, because I need a matrix for the rest of my program. I've already got a matrix with all zeros, but now I want to change the 0 in to a 1 when I click on a rectangle.
x = 5
y = 5
height = 30
width = 50
size = 20
color = (255,255,255)
new_color = (0,255,0)
screen.fill((0,0,0))
def draw_grid():
for y in range(height):
for x in range(width):
rect = pygame.Rect(x * (size + 1),y * (size + 1),size,size)
pygame.draw.rect(screen,color,rect)
x += 20
y += 20
rects = [[0 for i in range(width)] for j in range(height)]
draw_grid()
while 1:
clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if menu == 'start':
if pygame.mouse.get_pressed()[0]:
mouse_pos = pygame.mouse.get_pos()
for i,(rect,color) in enumerate(rects):
if rect.collidepoint(mouse_pos):
rects[i] = (rect,new_color)
for rect,color in rects:
pygame.draw.rect(screen,color,rect)
pygame.display.flip()
This is the code I used with the list, but I've already replaced the list with a matrix. When I run this code it gives an error:
ValueError: too many values to unpack
What is the best way to solve this problem?
To draw the rects you can iterate over the matrix and depending on the value (0 or 1) draw a white rect or a green rect. (You could also store the colors directly in the matrix, but I don't know if you want to do something else with it.)
To change the color of the clicked cells, you can easily calculate the indexes of the cells by floor dividing the mouse coords by (size+1), e.g. x = mouse_x // (size+1). Then just set matrix[y][x] = 1.
import sys
import pygame
WHITE = pygame.Color('white')
GREEN = pygame.Color('green')
def draw_grid(screen, matrix, size):
"""Draw rectangles onto the screen to create a grid."""
# Iterate over the matrix. First rows then columns.
for y, row in enumerate(matrix):
for x, color in enumerate(row):
rect = pygame.Rect(x*(size+1), y*(size+1), size, size)
# If the color is white ...
if color == 0:
pygame.draw.rect(screen, WHITE, rect)
# If the color is green ...
elif color == 1:
pygame.draw.rect(screen, GREEN, rect)
def main():
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
height = 30
width = 50
size = 20 # Cell size.
matrix = [[0 for i in range(width)] for j in range(height)]
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if pygame.mouse.get_pressed()[0]:
# To change the color, calculate the indexes
# of the clicked cell like so:
mouse_x, mouse_y = pygame.mouse.get_pos()
x = mouse_x // (size+1)
y = mouse_y // (size+1)
matrix[y][x] = 1
screen.fill((30, 30, 30))
# Now draw the grid. Pass all needed values to the function.
draw_grid(screen, matrix, size)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
pygame.init()
main()
pygame.quit()
sys.exit()
I'm currently working on a school project where I'm making a "hexcells" similar game in pygame and now I'm trying to blit an a new image if the user has clicked a current image. It will blit an image in the top left area, if clicked in the top left area, but not if I click any of the existing images. I told the program to print the coordinates from the images with help of the .get_rect() function, but it remains the same whereever I click and the coordinates aren't even where a image is. Can someone help me understand how this works and help me blit the new images on top of the existing images? Code below is not the entire document, however there is so much garbage/trash/unused code so I'd thought I spare you the time of looking at irrelevant code. Also sorry if the formatting is wrong or the information isn't enough, I tried my best.
import pygame, sys
from pygame.locals import *
#Magic numbers
fps = 30
winW = 640
winH = 480
boxSize = 40
gapSize = 75
boardW = 3
boardH = 3
xMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
yMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
#Lil bit o' color R G B
NAVYBLUE = ( 60, 60, 100)
correctCords = [[175,275,375],[375,275,175]]
bgColor = NAVYBLUE
unC = pygame.image.load("unC.png")
cor = pygame.image.load("correct.png")
inc = pygame.image.load("wrong.png")
correct = "Correct"
inCorrect = "Incorrect"
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((winW, winH))
mousex = 0 #stores x-coordinate of mouse event
mousey = 0 #stores y-coordinate of mouse event
pygame.display.set_caption("Branches")
DISPLAYSURF.fill(bgColor)
gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize)
while True:
mouseClicked = False
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex,mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
pos = pygame.mouse.get_pos()
mouseClicked = True
unCa = unC.get_rect()
corA = cor.get_rect()
print unCa
print corA
print pos
if unCa.collidepoint(pos):
DISPLAYSURF.blit(cor,(mousey,mousex))
"""lada = unC.get_rect()
lada =
if mousex and mousey == lada:
for x in correctCords:
for y in x:
for z in x:
if mousey and mousex == z and y:
DISPLAYSURF.blit(cor,(mousey,mousex))
print lada"""
pygame.display.update()
FPSCLOCK.tick(fps)
def gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize):
grid = []
cordX = []
cordY = []
correctRecs = []
#cordinates = []
#cordinates.append([])
#cordinates.append([])
#cordinates.append([])
#this is basically getBoard() all over again
#This part will arrange the actual backend grid
for row in range(3):
grid.append([])
#cordinates[0].append(gapSize+(row+1)*100)
#cordinates[1].append(gapSize+(row+1)*100)
#cordinates[2].append(gapSize+(row+1)*100)
for column in range(3):
grid[row].append(inCorrect)
for row in range(3):
cordX.append([])
for column in range(3):
cordX[row].append(gapSize+(row+1)*100)
for row in range(3):
cordY.append([])
for column in range(3):
cordY[row].append(gapSize+(column+1)*100)
#print cordX[0][0], cordY[0][0]
grid[0][2] = correct
grid[1][1] = correct
grid[2][0] = correct
#Y-AXEL SKRIVS FoRST ([Y][X])
#print cordinates[2][1]
DISPLAYSURF.blit(cor,(100,100))
#Let's draw it as well
for row in range(3):
for column in range(3):
DISPLAYSURF.blit(unC,(gapSize+(row+1)*100,gapSize+(column+1)*100))
main()
Also real sorry about the horrible variable naming and occasional swedish comments.
unCa = unC.get_rect() gives you only image size - so use it only once at start (before while True) - and later use the same unCa all the time to keep image position and change it.
btw: better use more readable names - like unC_rect
ie.
# move 10 pixel to the right
unC_rect.x += 10
# set new position
unC_rect.x = 10
unC_rect.right = 100
unC_rect.topleft = (10, 200)
unC_rect.center = (10, 200)
# center on screen
unC_rect.center = DISPLAYSURF.get_rect().center
etc.
And then use this rect to blit image
blit(unC, unC_rect)
and check collision with other rect
if unC_rect.colliderect(other_rect):
or with point - like mouse position
elif event.type == MOUSEMOTION:
if unC_rect.collidepoint(pygame.mouse.get_pos()):
hover = True
# shorter
elif event.type == MOUSEMOTION:
hover = unC_rect.collidepoint(pygame.mouse.get_pos()):