Zelle graphics in Python: How to move two objects separately - python

In this program I am able to get the green object to move but not the other one. I commented 'PROBLEM' above an 'if' statement written under function pygame() where I believe the problem exists. Am I supposed to make an elif statement to get the other object to move? Break after if valid(r, c)? etc. Here is the code:
from graphics import *
from time import sleep
''''''
def main():
global win,msg
win = GraphWin("PYGAME", winW, winH)
msg = Text(Point(100, winH - off_field//2), "PYGAME")
msg.draw(win)
make_field()
button_Exit, button_Restart = create_buttons()
pygame()
win.getMouse()
win.close()
''''''
column, row = 12, 10
adjacent = ( ( -1, -1), (0, -1), (1, -1),
( -1, 0), (1, 0),
( -1, 1), (0, 1), (1, 1) )
square_size = 30 # Size of each square on the field
off_field = 100 # Display off the field
# field : main game variable; 'I' = ice, 'B': broken
field = [ [ 'I' for c in range (column)] for r in range (row) ]
# user: identifies whose turn it is to play (click)
user = 0 # How do I switch users?
# Initial users' positions: [r, c]; None later replaced by Circle
users = [ [ row//2, 0, None],
[ row//2, column-1, None] ]
winW, winH = column * square_size, row * square_size + off_field # 360, 400
win = None # main app window
msg = None # main information Text
button_Exit = None # exit button
button_Restart = None # restart button
# squares: grid of squares, initially white, later changed to blue:
squares = None
''''''
# pygame_reset(): resets positions and squares turn white
def pygame_reset():
global win, squares
for r in range(row):
for c in range(column):
squares[r][c].setFill('white')
users[0][:2] = [row//2, 0]
users[1][:2] = [row//2, 0]
# User 1 and 2 are repositioned
# make_field(): makes visual grid of squares
def make_field():
global win, squares
# Allocate memory space for Rectangle objects:
squares = [ [ None for c in range (column)] for r in range (row) ]
for r in range(row):
for c in range(column):
x, y = c * square_size, r * square_size
squares[r][c] = Rectangle(Point(x,y), Point(x + square_size, y + square_size) )
squares[r][c].draw(win)
users[0][2] = Circle(Point(square_size//2, square_size//2 + row //2 *square_size),
square_size//2-5)
users[0][2].setFill('green')
users[0][2].draw(win)
users[1][2] = Circle(Point(square_size*11.5, square_size//2 + row //2 *square_size),
square_size//2-5)
users[1][2].setFill('yellow')
users[1][2].draw(win)
# Reset user's positions and all squares to white:
pygame_reset()
# returns True if position (r, c) is adjacent to
# current user's position
# Recall: users = [ [ r, c, Circle],[ r, c, Circle] ]
def valid(r, c):
pr, pc = users[user][0:2]
for dc, dr in adjacent:
if pr + dr == r and pc + dc == c:
return True
return False
def button_template(win, x, y, w, h, txt):
r = Rectangle(Point(x, y), Point(x+w, y+h))
r.setFill("white")
r.draw(win)
t = Text(r.getCenter(), txt) # same as Point(x+w//2, y+h//2)
t.draw(win)
return [ r, t ]
def create_buttons():
global win, field, squares, msg
button_Exit = button_template(win, 260, winH - off_field//1.25, 60, 25, "Exit")
button_Restart = button_template(win, 260, winH - off_field//2.25, 60, 25, "Restart")
return (button_Exit, button_Restart)
def temporary_color(r, c):
global squares
color = squares[r][c].config['fill']
squares[r][c].setFill('red')
sleep(0.5)
squares[r][c].setFill(color)
def move_user(r, c):
global msg, user, users
pr, pc = users[user][0:2]
dx, dy = square_size * (c - pc), square_size * (r - pr)
users[user][2].move(dx, dy)
users[user][0:2] = [ r, c]
msg.setText("User moves in: " + str((r, c)))
def pygame():
global win, field, squares, msg
while True:
pt = win.getMouse()
if pt.x > 260 and pt.y > winH - off_field//1.25:
msg.setText("Exit")
break
if pt.x > 260 and pt.y > winH - off_field//2.25:
msg.setText("Restart")
break
if pt.y < row * square_size:
r, c = pt.y // square_size, pt.x // square_size
msg.setText(str((r, c)))
# PROBLEM - DO I USE 'break' SOMEWHERE HERE?
if valid(r, c):
move_user(r, c)
# Do I use elif? Break? What to do next?
else:
temporary_color(r, c)
msg.setText("Invalid move")
continue
if valid(r, c):
squares[r][c].setFill('orange')
field[r][c] = 'B'
else:
msg.setText("Not in field")
main()

You need a more sophisticated loop for taking turns. The loop has to keep accepting mouse input until a valid move is made, then switch users. Here's a slightly streamlined version of your program with such a loop:
from time import sleep
from graphics import *
COLUMNS, ROWS = 12, 10
ADJACENT = (
(-1, -1), (0, -1), (1, -1),
(-1, 0), (1, 0),
(-1, 1), (0, 1), (1, 1)
)
SQUARE_SIZE = 30 # Size of each square on the field
OFF_FIELD = 20 # Display off the field
WIN_W, WIN_H = COLUMNS * SQUARE_SIZE, ROWS * SQUARE_SIZE + OFF_FIELD
# pygame_reset(): resets positions and squares turn white
def pygame_reset():
for r in range(ROWS):
for c in range(COLUMNS):
squares[r][c].setFill('white')
# User 1 and 2 are repositioned
users[0][:2] = [ROWS // 2, 0]
users[1][:2] = [ROWS // 2, COLUMNS - 1]
# make_field(): makes visual grid of squares
def make_field():
for r in range(ROWS):
y = r * SQUARE_SIZE
for c in range(COLUMNS):
x = c * SQUARE_SIZE
squares[r][c] = Rectangle(Point(x, y), Point(x + SQUARE_SIZE, y + SQUARE_SIZE))
squares[r][c].draw(win)
users[0][2] = Circle(Point(SQUARE_SIZE//2, SQUARE_SIZE//2 + ROWS//2 * SQUARE_SIZE), SQUARE_SIZE//2 - 5)
users[0][2].setFill('green')
users[1][2] = Circle(Point(SQUARE_SIZE * 11.5, SQUARE_SIZE//2 + ROWS//2 * SQUARE_SIZE), SQUARE_SIZE//2 - 5)
users[1][2].setFill('yellow')
# Reset user's positions and all squares to white:
pygame_reset()
users[0][2].draw(win)
users[1][2].draw(win)
# returns True if position (r, c) is adjacent to
# current user's position
# Recall: users = [[r, c, Circle], [r, c, Circle]]
def valid(r, c):
pr, pc = users[user][:2]
for dc, dr in ADJACENT:
if pr + dr == r and pc + dc == c:
return True
return False
def temporary_color(r, c):
color = squares[r][c].config['fill']
squares[r][c].setFill('red')
sleep(0.5)
squares[r][c].setFill(color)
def move_user(r, c):
pr, pc = users[user][:2]
dx, dy = SQUARE_SIZE * (c - pc), SQUARE_SIZE * (r - pr)
users[user][2].move(dx, dy)
users[user][:2] = r, c
msg.setText("User {} moves to: {}".format(user, (r, c)))
squares[r][c].setFill('orange')
field[r][c] = 'B'
def pygame():
global user
while True:
finished_move = False
while not finished_move:
pt = win.getMouse()
if pt.y < ROWS * SQUARE_SIZE:
r, c = int(pt.y // SQUARE_SIZE), int(pt.x // SQUARE_SIZE)
if valid(r, c):
move_user(r, c)
finished_move = True
else:
temporary_color(r, c)
msg.setText("Invalid move for user {}".format(user))
else:
msg.setText("Not in field")
user = 1 - user # switch user
# field : main game variable; 'I' = ice, 'B': broken
field = [['I' for c in range(COLUMNS)] for r in range(ROWS)]
# squares: grid of squares, initially white, later changed to blue:
squares = [[None for c in range(COLUMNS)] for r in range(ROWS)]
# user: identifies whose turn it is to play (click)
user = 0 # How do I switch users?
# Initial users' positions: [r, c]; None later replaced by Circle
users = [
[ROWS // 2, 0, None],
[ROWS // 2, COLUMNS - 1, None]
]
win = GraphWin("PYGAME", WIN_W, WIN_H) # main app window
msg = Text(Point(WIN_W//2, WIN_H - OFF_FIELD//2), "PYGAME") # main information Text
msg.draw(win)
make_field()
pygame()
win.getMouse()
win.close()
Code-wise, you need to (re)read about the global statement and when it's used.

Related

My parabola is working fine alone, but it's wrong in Pygame

So I created this parabola class which can be instantiated with 3 parameters (a, b and c) or with 3 points belonging to the parabola. The punti() function returns all the points belonging to the parabola in a range defined by n and m. Here's the code (Most of this is in Italian, sorry):
class Parabola:
def __init__(self, tipo=0, *params):
'''
Il tipo è 0 per costruire la parabola con a, b, c; 1 per costruire la parabola con
tre punti per la quale passa
'''
if tipo == 0:
self.__a = params[0]
self.__b = params[1]
self.__c = params[2]
self.__delta = self.__b ** 2 - (4 * self.__a * self.__c)
elif tipo == 1:
matrix_a = np.array([
[params[0][0]**2, params[0][0], 1],
[params[1][0]**2, params[1][0], 1],
[params[2][0]**2, params[2][0], 1]
])
matrix_b = np.array([params[0][1], params[1][1], params[2][1]])
matrix_c = np.linalg.solve(matrix_a, matrix_b)
self.__a = round(matrix_c[0], 2)
self.__b = round(matrix_c[1], 2)
self.__c = round(matrix_c[2], 2)
self.__delta = self.__b ** 2 - (4 * self.__a * self.__c)
def trovaY(self, x):
y = self.__a * x ** 2 + self.__b * x + self.__c
return y
def punti(self, n, m, step=1):
output = []
for x in range(int(min(n, m)), int(max(n, m)) + 1, step):
output.append((x, self.trovaY(x)))
return output
Now my little game is about shooting targets with a bow and i have to use the parabola for the trajectory and it passes by 3 points:
The player center
A point with the cursor's x and player's y
A point in the middle with the cursors's y
The trajectory is represented by a black line but it clearly doesn't work and I can't understand why. Here's the code of the game (Don't mind about the bow's rotation, I still have to make it function properly):
import os
import sys
import pygame
from random import randint
sys.path.insert(
1, __file__.replace("pygame-prototype\\" + os.path.basename(__file__), "coniche\\")
)
import parabola
# Initialization
pygame.init()
WIDTH, HEIGHT = 1024, 576
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# Function to rotate without losing quality
def rot_from_zero(surface, angle):
rotated_surface = pygame.transform.rotozoom(surface, angle, 1)
rotated_rect = rotated_surface.get_rect()
return rotated_surface, rotated_rect
# Function to map a range of values to another
def map_range(value, leftMin, leftMax, rightMin, rightMax):
# Figure out how 'wide' each range is
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
# Convert the left range into a 0-1 range (float)
valueScaled = float(value - leftMin) / float(leftSpan)
# Convert the 0-1 range into a value in the right range.
return rightMin + (valueScaled * rightSpan)
# Player class
class Player:
def __init__(self, x, y, width=64, height=64):
self.rect = pygame.Rect(x, y, width, height)
self.dirx = 0
self.diry = 0
def draw(self):
rectangle = pygame.draw.rect(screen, (255, 0, 0), self.rect)
# Target class
class Target:
def __init__(self, x, y, acceleration=0.25):
self.x, self.y = x, y
self.image = pygame.image.load(
__file__.replace(os.path.basename(__file__), "target.png")
)
self.speed = 0
self.acceleration = acceleration
def draw(self):
screen.blit(self.image, (self.x, self.y))
def update(self):
self.speed -= self.acceleration
self.x += int(self.speed)
if self.speed < -1:
self.speed = 0
player = Player(64, HEIGHT - 128)
# Targets init
targets = []
targets_spawn_time = 3000
previous_ticks = pygame.time.get_ticks()
# Ground animation init
ground_frames = []
for i in os.listdir(__file__.replace(os.path.basename(__file__), "ground_frames")):
ground_frames.append(
pygame.image.load(
__file__.replace(os.path.basename(__file__), "ground_frames\\" + i)
)
) # Load all ground frames
ground_frame_counter = 0 # Keep track of the current ground frame
frame_counter = 0
# Bow
bow = pygame.image.load(__file__.replace(os.path.basename(__file__), "bow.png"))
angle = 0
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Spawning the targets
current_ticks = pygame.time.get_ticks()
if current_ticks - previous_ticks >= targets_spawn_time:
targets.append(Target(WIDTH, randint(0, HEIGHT - 110)))
previous_ticks = current_ticks
screen.fill((101, 203, 214))
player.draw()
for i, e in list(enumerate(targets))[::-1]:
e.draw()
e.update()
if e.x <= -e.image.get_rect().width:
del targets[i]
# Calculating the angle of the bow
mouse_pos = pygame.Vector2(pygame.mouse.get_pos())
angle = map_range(mouse_pos.x, 0, WIDTH, 90, 0)
# Rotate the bow
rotated_bow, rotated_bow_rect = rot_from_zero(bow, angle)
rotated_bow_rect.center = player.rect.center
screen.blit(rotated_bow, rotated_bow_rect)
# Animate the ground
if frame_counter % 24 == 0:
ground_frame_counter += 1
if ground_frame_counter >= len(ground_frames):
ground_frame_counter = 0
for i in range(round(WIDTH / ground_frames[ground_frame_counter].get_rect().width)):
screen.blit(
ground_frames[ground_frame_counter],
(
ground_frames[ground_frame_counter].get_rect().width * i,
HEIGHT - ground_frames[ground_frame_counter].get_rect().height,
),
)
# Calculating the trajectory
mouse_pos.x = (
mouse_pos.x if mouse_pos.x != rotated_bow_rect.centerx else mouse_pos.x + 1
)
# print(mouse_pos, rotated_bow_rect.center)
v_x = rotated_bow_rect.centerx + ((mouse_pos.x - rotated_bow_rect.centerx) / 2)
trajectory_parabola = parabola.Parabola(
1,
rotated_bow_rect.center,
(mouse_pos.x, rotated_bow_rect.centery),
(v_x, mouse_pos.y),
)
trajectory = [(i[0], int(i[1])) for i in trajectory_parabola.punti(0, WIDTH)]
pygame.draw.lines(screen, (0, 0, 0), False, trajectory)
pygame.draw.ellipse(
screen, (128, 128, 128), pygame.Rect(v_x - 15, mouse_pos.y - 15, 30, 30)
)
pygame.draw.ellipse(
screen,
(128, 128, 128),
pygame.Rect(mouse_pos.x - 15, rotated_bow_rect.centery - 15, 30, 30),
)
pygame.display.update()
if frame_counter == 120:
for i in trajectory:
print(i)
frame_counter += 1
You can run all of this and understand what's wrong with it, help?
You round the values of a, b and c to 2 decimal places. This is too inaccurate for this application:
self.__a = round(matrix_c[0], 2)
self.__b = round(matrix_c[1], 2)
self.__c = round(matrix_c[2], 2)
self.__a = matrix_c[0]
self.__b = matrix_c[1]
self.__c = matrix_c[2]
Similar to answer above... rounding is the issue here. This is magnified when the scale of the coordinates gets bigger.
However, disagree with other solution: It does not matter what order you pass the coordinates into your parabola construction. Any order works fine. points are points.
Here is a pic of your original parabola function "drooping" because of rounding error:
p1 = (0, 10) # left
p2 = (100, 10) # right
p3 = (50, 100) # apex
p = Parabola(1, p3, p2, p1)
traj = p.punti(0, 100)
xs, ys = zip(*traj)
plt.scatter(xs, ys)
plt.plot([0, 100], [10, 10], color='r')
plt.show()

Making a game in python called Othello its a real game. Cannot change specific values in a array

This is a 8 by 8 array the problem is when I set the variable player_2_move to the row and column which is input we get from the user the value of that variable stays at 0 when its meant to go to the two inputs we get. And from there I don't know how to change the value which Is Player 2 move this only happens when a function which checks for a winning move is checked. The two inputs work when I call the drop piece function which is most confusing. And also I'm still drafting with arrays which is why the numbers are 1 and 2.
The game I'm making is called Othello.
import pygame, sys
import math
pygame.init()
ROW_COUNT = 8
COLUMN_COUNT = 8
PLAYER_COUNT = 2
RED = (255, 0, 0)
BEIGE = (255, 200, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SQUARESIZE = 100
width = COLUMN_COUNT * SQUARESIZE
height = ROW_COUNT * SQUARESIZE
size = (width, height)
screen = pygame.display.set_mode(size)
screen.fill(RED)
# Vertical
one_x_1 = 100
one_y_1 = 0
one_end_x = 100
one_end_y = 800
# Horizontal
two_x_1 = 0
two_y_1 = 100
two_end_x = 800
two_end_y = 100
RADIUS = int(SQUARESIZE/2 - 5)
def draw_board(board):
global one_x_1, one_y_1, one_end_x, one_end_y, two_x_1, two_y_1, two_end_x, two_end_y
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
pygame.draw.line(screen, BLACK, (one_x_1, one_y_1), (one_end_x, one_end_y), 3)
one_x_1 += 100
one_end_x += 100
pygame.draw.line(screen, BLACK, (two_x_1, two_y_1), (two_end_x, two_end_y), 3)
two_y_1 += 100
two_end_y += 100
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
if board[r][c] == 1:
pygame.draw.circle(screen, WHITE, (int(c*SQUARESIZE+SQUARESIZE/2), height - int(r*SQUARESIZE + SQUARESIZE/2)), RADIUS)
elif board[r][c] == 2:
pygame.draw.circle(screen, BLACK, (int(c*SQUARESIZE+SQUARESIZE/2), height - int(r*SQUARESIZE + SQUARESIZE/2)), RADIUS)
pygame.display.update()
class Player(object):
def __init__(self, number):
self.remaining_pieces = 32
self.number = number
board = np.zeros((ROW_COUNT, COLUMN_COUNT), dtype=np.uint8)
board[3][3] = 1
board[4][4] = 1
board[3][4] = 2
board[4][3] = 2
print(board)
draw_board(board)
pygame.display.update()
players = [Player(i) for i in range(1, PLAYER_COUNT + 1)]
print(len(players))
game_over = False
while not game_over:
# Event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for p in players:
if event.type == pygame.MOUSEBUTTONDOWN:
posx = event.pos[0]
posy = event.pos[1]
column = int(math.floor(posx/SQUARESIZE))
row = int(math.floor(posy/SQUARESIZE))
if board[row][column] == 0:
board[row][column] = p.number
p.remaining_pieces = p.remaining_pieces - 1
# The eight directions in which we will go
directions = [(-1, -1), (-1, 0), (-1, 1), (1, 1), (1, 0), (1, -1), (0, 1), (0, -1)]
for d in directions:
x = row
y = column
while True:
x = x + d[0] # Assign x to the first value in the tuple
y = y + d[1] # Assign y to the second value in the tuple
# check if we are still on the board
if (x in range(8)) and (y in range(8)):
print(f'checking y = {x + 1}, x = {y + 1}')
# if the file is empty there are no pieces to capture
if board[x][y] == 0:
break
"""
If we find a number around our move we run the same procedure for it and change it
if we have to
"""
if p.number == board[x][y]: # Here p.number is the players move we find it on the board
print(f'found {p.number}: y = {x + 1}, x = {y + 1}')
i = row
j = column
while i != x or j != y:
i = i + d[0]
j = j + d[1]
print(f'changed : y = {i + 1}, x = {j + 1} to {p.number}')
board[i][j] = p.number
else:
# We are outside the board
break
draw_board(board)
print(board)```
I will go step by step through your program and improve it.
First of all creating arrays like this:
player1 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
player2 = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
Is always a bad practice. Since you already use numpy in your project it's easy to create them like this:
player1 = np.ones(32, dtype=np.uint8)
player2 = np.full(32, 2, dtype=np.uint8)
However you don't really need those arrays anyway. You can just have an integer which keeps track of the remaining pieces. reamining_pieces = 32
To make the whole think easier I created a Player class which contains a Player number and the remaining Pieces.
class Player(object):
def __init__(self, number):
self.remaining_pieces = 32
self.number = number
Now after this you have a lot of functions which aren't really necessary. They are so simple that there is no advantage of writing a function for them.
So for example instead of writing
def create_board():
board = np.zeros((ROW_COUNT, COLUMN_COUNT))
return board
board = create_board()
It's a lot simpler and easier to read if you just write
board = np.zeros((ROW_COUNT, COLUMN_COUNT))
Same goes for def drop_piece(board, row, col, piece) and def is_valid_location(board, row, col) which both just add unnecessary complexity to it.
Step by step explanation
First, we start with a tuple of all directions:
directions = [(-1, -1), (-1, 0), (-1, 1), (1, 1), (1, 0), (1, -1), (0, 1), (0, -1)]
And we now want to go in all directions and every time we start at row, column which is where the newly placed piece is located.
for d in directions:
x = row
y = column
And since we don't know how far we have to go we use a while loop and take the first step in the direction. Because We don't want to go outside of the board we immediately check if we are still on the board. If we are, we can continue.
while True:
x = x + d[0]
y = y + d[1]
# check if we are still on the board
if (x in range(8)) and (y in range(8)):
For the following steps let's use this as an example:
[[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 1 2 0 0 0]
[0 0 * 2 1 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]]
The star is where has just been placed a one. If we go one step to the left, we will encounter a 0 and know that we don't have to go any further. That's what
if board[x][y] == 0:
break
Does.
If we now go to the right. We will first encounter a two and it just get's ignored and we go one step further to the right.
Here we finally find a one. So we know that between row, column and x, y every number can be converted to a one. To do that we start at row, column and move once again until we reach x, y. On the way we convert every number to a one:
if p.number == board[x][y]:
print(f'found {p.number}: x = {x + 1}, y = {y + 1}')
i = row
j = column
while i != x or j != y:
i = i + d[0]
j = j + d[1]
print(f'changed : x = {i + 1}, y = {j + 1} to {p.number}')
board[i][j] = p.number
Whole Code
import pygame, sys
import math
import numpy as np
pygame.init()
ROW_COUNT = 8
COLUMN_COUNT = 8
PLAYER_COUNT = 2
RED = (255, 0, 0)
BEIGE = (255, 200, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SQUARESIZE = 100
width = COLUMN_COUNT * SQUARESIZE
height = ROW_COUNT * SQUARESIZE
size = (width, height)
screen = pygame.display.set_mode(size)
screen.fill(RED)
# Vertical
one_x_1 = 100
one_y_1 = 0
one_end_x = 100
one_end_y = 800
# Horizontal
two_x_1 = 0
two_y_1 = 100
two_end_x = 800
two_end_y = 100
RADIUS = int(SQUARESIZE / 2 - 5)
def draw_board(board):
global one_x_1, one_y_1, one_end_x, one_end_y, two_x_1, two_y_1, two_end_x, two_end_y
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
pygame.draw.line(screen, BLACK, (one_x_1, one_y_1), (one_end_x, one_end_y), 3)
one_x_1 += 100
one_end_x += 100
pygame.draw.line(screen, BLACK, (two_x_1, two_y_1), (two_end_x, two_end_y), 3)
two_y_1 += 100
two_end_y += 100
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
if board[r][c] == 1:
pygame.draw.circle(screen, WHITE, (
int(c * SQUARESIZE + SQUARESIZE / 2), height - int(r * SQUARESIZE + SQUARESIZE / 2)), RADIUS)
elif board[r][c] == 2:
pygame.draw.circle(screen, BLACK, (
int(c * SQUARESIZE + SQUARESIZE / 2), height - int(r * SQUARESIZE + SQUARESIZE / 2)), RADIUS)
pygame.display.update()
class Player(object):
def __init__(self, number):
self.remaining_pieces = 32
self.number = number
board = np.zeros((ROW_COUNT, COLUMN_COUNT), dtype=np.uint8)
board[3][3] = 1
board[4][4] = 1
board[3][4] = 2
board[4][3] = 2
print(board)
draw_board(board)
pygame.display.update()
players = [Player(i) for i in range(1, PLAYER_COUNT + 1)]
print(len(players))
def next_player():
while True:
for player in players:
yield player
player_generator = next_player()
game_over = False
while not game_over:
# Event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
posx = event.pos[0]
posy = event.pos[1]
column = int(math.floor(posx / SQUARESIZE))
row = int(math.floor(posy / SQUARESIZE))
p = player_generator.__next__()
if board[row][column] == 0:
board[row][column] = p.number
p.remaining_pieces = p.remaining_pieces - 1
# The eight directions in which we will go
directions = [(-1, -1), (-1, 0), (-1, 1), (1, 1), (1, 0), (1, -1), (0, 1), (0, -1)]
for d in directions:
x = row
y = column
while True:
x = x + d[0] # Assign x to the first value in the tuple
y = y + d[1] # Assign y to the second value in the tuple
# check if we are still on the board
if (x in range(8)) and (y in range(8)):
print(f'checking y = {x + 1}, x = {y + 1}')
# if the file is empty there are no pieces to capture
if board[x][y] == 0:
break
"""
If we find a number around our move we run the same procedure for it and change it
if we have to
"""
if p.number == board[x][y]: # Here p.number is the players move we find it on the board
print(f'found {p.number}: y = {x + 1}, x = {y + 1}')
i = row
j = column
while i != x or j != y:
i = i + d[0]
j = j + d[1]
print(f'changed : y = {i + 1}, x = {j + 1} to {p.number}')
board[i][j] = p.number
else:
# We are outside the board
break
draw_board(board)
print(board)

Finding every point of intersection of multiple lines using pygame in python for creation of game board

I need to find every point of intersection of lines in my code. At these points, I want to put my game pieces. The logic of the game is like that of tic tac toe in which if a player places 3 same color marbles in a row he/she can grab a piece of the other player which are not arranged in a sequence.
My code so far:
import pygame
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# This sets the WIDTH and HEIGHT of each grid location
WIDTH = 20
HEIGHT = 20
# This sets the margin between each cell
MARGIN = 5
# Create a 2 dimensional array. A two dimensional
# array is simply a list of lists.
grid = []
for row in range(19):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(19):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
pygame.init()
WINDOW_SIZE = [800, 600]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("Array Backed Grid")
done = False
clock = pygame.time.Clock()
while not done:
# Set the screen background
screen.fill(BLACK)
# Draw the grid
for row in range(19):
for column in range(19):
color = WHITE
if grid[row][column] == 1:
color = GREEN
board_lines = [
( 13,15,462,15 ), ( 13,469,462,469 ), #lin1 and line2,outer rect
( 62,86,409,86 ), ( 62,389,409,389 ), #line3 and l4,mid reect
( 114,186,360,186 ), ( 114,318,360,318 ), #line5,l6,internl rect
( 13,15,13,469 ), ( 462,12,462,469 ), #line9,l10,left and right sides
( 62,86,62,389 ), ( 409,85,409,389 ), #l7,l8left and right sides
( 114,186,114,316), ( 360,187,360,318 ), #l11,lin12left and right sides
( 237,15,237,186 ), ( 237,469,237,320 ), #upper V.line,lowerV
( 13,242,113,242 ), ( 360,242,462,242 ) #rIGHT LEFT hoRIZONTAL LINE
]
for line in board_lines:
line_from = ( line[0], line[1] )
line_to = ( line[2], line[3] )
pygame.draw.line( screen, RED, line_from, line_to, 3)
# Limit to 60 frames per second
clock.tick(60)
pygame.display.flip()
pygame.quit()
The following function computes the intersection of 2 lines which are given by the points (P0, P1) and (Q0, Q1):
def lineLineIntersect(P0, P1, Q0, Q1):
d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0])
if d == 0:
return None
t = ((Q0[0]-P0[0]) * (Q1[1]-Q0[1]) + (Q0[1]-P0[1]) * (Q0[0]-Q1[0])) / d
u = ((Q0[0]-P0[0]) * (P1[1]-P0[1]) + (Q0[1]-P0[1]) * (P0[0]-P1[0])) / d
if 0 <= t <= 1 and 0 <= u <= 1:
return round(P1[0] * t + P0[0] * (1-t)), round(P1[1] * t + P0[1] * (1-t))
return None
The algorithm is explained in detail, in the answer to Problem with calculating line intersections:
P ... point on the 1. line
R ... normalized direction of the 1. line
Q ... point on the 2. line
S ... normalized direction of the 2. line
alpha ... angle between Q-P and R
beta ... angle between R and S
gamma = 180° - alpha - beta
h = | Q - P | * sin(alpha)
u = h / sin(beta)
t = | Q - P | * sin(gamma) / sin(beta)
t = dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, S)) / determinant(mat2(R, S))
u = dot(Q-P, (R.y, -R.x)) / dot(R, (S.y, -S.x)) = determinant(mat2(Q-P, R)) / determinant(mat2(R, S))
X = P + R * t = Q + S * u
You've to evaluate if a line segment intersects any other line segments. Iterate through the lines in nested loops and find the intersection of a line with any other line except itself, by using the function lineLineIntersect:
intersectionPoints = []
for i, line1 in enumerate(board_lines):
for line2 in board_lines[i:]:
isectP = lineLineIntersect(line1[:2], line1[2:], line2[:2], line2[2:])
if isectP:
intersectionPoints.append(isectP)
Draw circles at the intersection points:
for isectP in intersectionPoints:
pygame.draw.circle(screen, GREEN, isectP, 5)
See the example:
import pygame
import math
def lineLineIntersect(P0, P1, Q0, Q1):
d = (P1[0]-P0[0]) * (Q1[1]-Q0[1]) + (P1[1]-P0[1]) * (Q0[0]-Q1[0])
if d == 0:
return None
t = ((Q0[0]-P0[0]) * (Q1[1]-Q0[1]) + (Q0[1]-P0[1]) * (Q0[0]-Q1[0])) / d
u = ((Q0[0]-P0[0]) * (P1[1]-P0[1]) + (Q0[1]-P0[1]) * (P0[0]-P1[0])) / d
if 0 <= t <= 1 and 0 <= u <= 1:
return round(P1[0] * t + P0[0] * (1-t)), round(P1[1] * t + P0[1] * (1-t))
return None
board_lines = [
( 13,15,462,15 ), ( 13,469,462,469 ), #lin1 and line2,outer rect
( 62,86,409,86 ), ( 62,389,409,389 ), #line3 and l4,mid reect
( 114,186,360,186 ), ( 114,318,360,318 ), #line5,l6,internl rect
( 13,15,13,469 ), ( 462,12,462,469 ), #line9,l10,left and right sides
( 62,86,62,389 ), ( 409,85,409,389 ), #l7,l8left and right sides
( 114,186,114,316), ( 360,187,360,318 ), #l11,lin12left and right sides
( 237,15,237,186 ), ( 237,469,237,320 ), #upper V.line,lowerV
( 13,242,113,242 ), ( 360,242,462,242 ) #rIGHT LEFT hoRIZONTAL LINE
]
pygame.init()
intersectionPoints = []
for i, line1 in enumerate(board_lines):
for line2 in board_lines[i:]:
isectP = lineLineIntersect(line1[:2], line1[2:], line2[:2], line2[2:])
if isectP:
intersectionPoints.append(isectP)
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# This sets the WIDTH and HEIGHT of each grid location
WIDTH = 20
HEIGHT = 20
# This sets the margin between each cell
MARGIN = 5
# Create a 2 dimensional array. A two dimensional
# array is simply a list of lists.
grid = []
for row in range(19):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(19):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
WINDOW_SIZE = [800, 600]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("Array Backed Grid")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLACK)
# Draw the grid
for row in range(19):
for column in range(19):
color = WHITE
if grid[row][column] == 1:
color = GREEN
for line in board_lines:
pygame.draw.line(screen, RED, line[:2], line[2:], 3)
for isectP in intersectionPoints:
pygame.draw.circle(screen, GREEN, isectP, 5)
# Limit to 60 frames per second
clock.tick(60)
pygame.display.flip()
pygame.quit()

Icebreaker Game python

I'm going to create a python game by using a modules called graphics.
I have created a board with ice and I'm confusing how to create the position for the player in the beginning.
link to the graphics modules:
http://mcsp.wartburg.edu/zelle/python/graphics.py
Here is my code:
from graphics import *
from random import *
column, row = 7, 10
WIN_W, WIN_H = 450, 315
WIN_SZ, GAP = 40, 5
COLORS = [ 'blue', 'white']
player = 'X'
win = None
ices = []
def draw_ice(x, y):
global ices
left = GAP + x* (WIN_SZ+GAP)
top = GAP + y* (WIN_SZ+GAP)
r = Rectangle(Point(left, top), Point(left+WIN_SZ, top+WIN_SZ))
ices[x][y].append(r)
bit = randint(1,1)
ices[x][y].append(bool(bit))
ices[x][y][0].setFill(COLORS[bit])
ices[x][y][0].draw(win)
def draw_ices():
for i in range(row):
ices.append([])
for j in range(column):
ices[i].append([])
draw_ice(i, j)
def MS1():
global win
win = GraphWin("Icebreaker", WIN_W, WIN_H)
draw_ices()
while True:
pt = win.getMouse()
x = int((pt.x - GAP)/(WIN_SZ + GAP))
y = int((pt.y - GAP)/(WIN_SZ + GAP))
print(str((pt.x, pt.y)) + ' --> ' + str((x, y)))
ices[x][y][1] = not ices[x][y][0]
ices[x][y][0].setFill(COLORS[ices[x][y][1]])
position in the beginningMS1()
let's say 'X' is the red circle and 'O' is the blue circle.
I don't know anything about the Icebreaker game but I'm hoping the additional logic I provided you below gives you enough to move forward:
from graphics import *
COLUMN, ROW = 7, 10
WIN_W, WIN_H = 455, 320
WIN_SZ, GAP = 40, 5
COLORS = ['blue', 'white']
CIRCLE, RECTANGLE, COLOR = range(3)
player = 'X'
ices = []
def draw_ice(x, y):
left = GAP + x * (WIN_SZ + GAP)
top = GAP + y * (WIN_SZ + GAP)
r = Rectangle(Point(left, top), Point(left + WIN_SZ, top + WIN_SZ))
c = Circle(r.getCenter(), WIN_SZ / 4)
bit = 1
c.setFill(COLORS[bit])
c.setOutline('white')
r.draw(win)
c.draw(win)
ices[x][y] = [c, r, bool(bit)]
def draw_ices():
for i in range(ROW):
ices.append([])
for j in range(COLUMN):
ices[i].append(None)
draw_ice(i, j)
def MS1():
draw_ices()
x_player = ices[0][3][CIRCLE] # X / Red Player
x_player.setFill('red')
o_player = ices[9][3][CIRCLE] # O / Red Player
o_player.setFill('blue')
while True:
pt = win.getMouse()
x = int((pt.x - GAP) / (WIN_SZ + GAP))
y = int((pt.y - GAP) / (WIN_SZ + GAP))
print((pt.x, pt.y), '-->', (x, y))
ices[x][y][COLOR] = not ices[x][y][COLOR]
ices[x][y][CIRCLE].setFill(COLORS[ices[x][y][COLOR]])
win = GraphWin("Icebreaker", WIN_W, WIN_H)
MS1()

Python pygame not responding. Sierpinski triangle and problems with randint

The first problem that im getting is with my random numbers. every other time i try and run the program i get an error with a random number. The program worked and would make a sierpinski triangle every other time until i tried to add color into the equation now the display box pops up then everything freezes
import sys, pygame, random, math, array
####initializes pygame
pygame.init()
#####deffining all my functions
def verticiePos(verticies):
for i in range(2):
screen.set_at(verticies[i], (0,0,255))
def randV(verticies):
v = random.choice(verticies)
return v
def Show(delay):
pygame.display.flip()
pygame.time.delay(delay)
def randPoint(h,w):
yRand = random.randint(0,h-1)
#maxX = ((w - yRand) * 2)
xRand = random.randint(0, w-1)
return (xRand, yRand)
def mainFunc():
verticiePos(verticies)
randPoint(h,w)
def colors(point, maxRed, maxBlue, maxGreen, bv, gv):
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 255
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 255
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 255
howBlue = int(howBlue)
return (howRed, howGreen, howBlue)
#####global variables
xRand = 0
yRand = 0
howRed = 0
howBlue = 0
howGreen = 0
#####Let the user choose the size of the display and setting screne
w = input("What do you want the width of the dcreen to be: ")
w = int(w)
h = input("What do you want the height of the dcreen to be: ")
h = int(h)
size = [w,h]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Project 1, Spierpinski triangle")
######setting up my verticies and all the functions i made
verticies = [(1,h - 1), (int(w/2), 1), (w-1,h-1)]
gv = verticies[1]
bv = verticies[2]
lengthOne = w
lengthTwo = math.sqrt(((w/2)**2) + (h**2))
if lengthOne >= lengthTwo:
maxRed = lengthOne
maxBlue = lengthOne
else:
maxRed = lengthTwo
maxBlue = lengthTwo
maxGreen = lengthTwo
############################################
mainFunc()
point = [yRand,xRand]
iteration = 0
delay = 2
#######the main loop thats plots points
for i in range(10000):
v = randV(verticies)
#colors(point, maxRed, maxBlue, maxGreen, bv, gv)
point = (int((point[0] + v[0])/2), int((point[1] + v[1])/2))
howRed = (math.sqrt(point[0]**2 + point[1]**2) / maxRed) * 200
howRed = int(howRed)
howGreen = ((math.sqrt((point[0] - gv[0])**2 + (point[1] - gv[1])**2)) / maxGreen) * 200
howGreen = int(howGreen)
howBlue = ((math.sqrt((point[0] - bv[0])**2 + (point[1] - bv[1])**2)) / maxBlue) * 200
howBlue = int(howBlue)
screen.set_at(point,(howRed,howGreen,howBlue))
Show(delay)
iteration = iteration + 1
#####the loop went really fast and was hard to see it coming into shape so i added this
if iteration > 2000:
delay = 0
#howRed,howGreen,howBlue
This is an updated version of the code that works i just need to clean it up now
Problem with random:
You use random.randint(yRand, maxX) in randPoint() and sometimes yRand > maxX
but random.randint(a, b) require a <= b
http://docs.python.org/2/library/random.html#random.randint
Problem with freeze ???
I have not problem with freeze but you have loop for i in range(50000): and it takes 1 minute to finish. At first run I thought that program freeze.
You have no event loop to get keyboard event and stop program with ESC.
Function color() always return (0,0,0) - it is black - so I don't see Sierpinski triangle.
#EDIT:
Sierpinski Triangle with recursion
import pygame
import math
class Sierpinski():
def __init__(self):
h = w = int(input("Triangle size: "))
level = int(input("Recursion level: "))
margin = 50 # add to size to make margin around triangle
# initializes pygame and setting screne
pygame.init()
self.screen = pygame.display.set_mode( (w + margin*2, h + margin*2) ) # self. - to make accessible in all function
pygame.display.set_caption("Sierpinski Triangle - Recursion")
# offset to move triangle to middle of window
const_height = math.sqrt(3)/2 # h = a * sqrt(3)/2 = a * const_height
invert_const_height = 1 - const_height
offset = int(h * invert_const_height / 2) # to move triange up - to middle
# main vertices A, B, C
a = (margin, h + margin - offset)
b = (w + margin, h + margin - offset)
c = (w/2 + margin, int(h * invert_const_height) + margin - offset)
self.screen.set_at(a, (255,255,255))
self.screen.set_at(b, (255,255,255))
self.screen.set_at(c, (255,255,255))
# recursion
self.drawTriangle(a, b, c, level)
# main loop (in game)
clock = pygame.time.Clock()
running = True
while running:
# keyboard & mouse event
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# move objects - nothing to do here
# draw object & redraw on screen
pygame.display.set_caption("Sierpinski Triangle - Recursion [FPS: %f]" % (clock.get_fps()))
pygame.display.update()
# frametime
clock.tick(25) # max 25 Frames Per Second
# end program
pygame.quit()
#-------------------------------------------------------
def drawTriangle(self, a, b, c, level):
if level == 0:
return
ab = self.middlePoint(a, b)
ac = self.middlePoint(a, c)
bc = self.middlePoint(b, c)
self.screen.set_at(ab, (255,255,255))
self.screen.set_at(bc, (255,255,255))
self.screen.set_at(ac, (255,255,255))
self.drawTriangle(a, ab, ac, level-1)
self.drawTriangle(b, ab, bc, level-1)
self.drawTriangle(c, bc, ac, level-1)
#-------------------------------------------------------
def middlePoint(self, a, b):
x = (a[0] + b[0])/2
y = (a[1] + b[1])/2
return (x,y)
#----------------------------------------------------------------------
if __name__ == '__main__':
Sierpinski()

Categories