Snake Game score not adding - turtle-graphics

This snake game code. I want to add the system score in this game. So that each time the snake eating his score would be increased. But if the snake does not get food score will not increase.
How do I go about displaying the current score?
this is :
""" A simple snake game using Turtle Graphics. """
import turtle
import math
import random
WIDTH = 500
HEIGHT = 500
FOOD_SIZE = 10
DELAY = 100 # milliseconds
offsets = {
"up": (0, 20),
"down": (0, -20),
"left": (-20, 0),
"right": (20, 0)
}
scores are not updating
def addscore():
global score
score += 1
def reset():
global snake, snake_direction, food_pos, pen
snake = [[0, 0], [0, 20], [0, 40], [0, 60], [0, 80]]
snake_direction = "up"
food_pos = get_random_food_pos()
food.goto(food_pos)
#screen.update() Only needed if we are fussed about drawing food before next call to `draw_snake()`.
move_snake()
def move_snake():
global snake_direction
# Next position for head of snake.
new_head = snake[-1].copy()
new_head[0] = snake[-1][0] + offsets[snake_direction][0]
new_head[1] = snake[-1][1] + offsets[snake_direction][1]
# Check self-collision
if new_head in snake[:-1]: # Or collision with walls?
reset()
else:
# No self-collision so we can continue moving the snake.
snake.append(new_head)
# Check food collision
if not food_collision():
snake.pop(0) # Keep the snake the same length unless fed.
wrapping up
# Allow screen wrapping
if snake[-1][0] > WIDTH / 2:
snake[-1][0] -= WIDTH
elif snake[-1][0] < - WIDTH / 2:
snake[-1][0] += WIDTH
elif snake[-1][1] > HEIGHT / 2:
snake[-1][1] -= HEIGHT
elif snake[-1][1] < -HEIGHT / 2:
snake[-1][1] += HEIGHT
# Clear previous snake stamps
pen.clearstamps()
# Draw snake
for segment in snake:
pen.goto(segment[0], segment[1])
pen.stamp()
# Refresh screen
screen.update()
# Rinse and repeat
turtle.ontimer(move_snake, DELAY)
def food_collision():
global food_pos
if get_distance(snake[-1], food_pos) < 20:
food_pos = get_random_food_pos()
food.goto(food_pos)
return True
return False
def get_random_food_pos():
x = random.randint(- WIDTH / 2 + FOOD_SIZE, WIDTH / 2 - FOOD_SIZE)
y = random.randint(- HEIGHT / 2 + FOOD_SIZE, HEIGHT / 2 - FOOD_SIZE)
return (x, y)
def get_distance(pos1, pos2):
x1, y1 = pos1
x2, y2 = pos2
distance = ((y2 - y1) * 2 + (x2 - x1) * 2) ** 0.5
return distance
def go_up():
global snake_direction
if snake_direction != "down":
snake_direction = "up"
def go_right():
global snake_direction
if snake_direction != "left":
snake_direction = "right"
def go_down():
global snake_direction
if snake_direction != "up":
snake_direction = "down"
def go_left():
global snake_direction
if snake_direction != "right":
snake_direction = "left"
# Screen
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Snake")
screen.bgcolor("green")
screen.setup(500, 500)
screen.tracer(0)
# Pen
pen = turtle.Turtle("square")
pen.penup()
pen.hideturtle()
pen.goto(0, 250)
pen.write("Score : 0 High Score : 0", align="center", font=("candara", 24, "bold"))
# Food
food = turtle.Turtle()
food.shape("circle")
food.color("red")
food.shapesize(FOOD_SIZE / 20) # Default size of turtle "square" shape is 20.
food.penup()
# Event handlers
screen.listen()
screen.onkey(go_up, "Up")
screen.onkey(go_right, "Right")
screen.onkey(go_down, "Down")
screen.onkey(go_left, "Left")
# Let's go
reset()
turtle.done()

It's defined, but you have to call your addscore() function. Replace
if not food_collision():
snake.pop(0)
with
if food_collision():
addscore()
else:
snake.pop(0)

You can just add this code to your game. It will write a score:
score = 0
#Creating Score Writer
turtle.hideturtle()
turtle.penup()
turtle.color("white")
turtle.goto(-300,300)
turtle.write(f"Score = {score}", font=("Arial",16,"normal"))
You also don't need a screen.setup() for this.
You can change the score variable. Every time you want the text to update you write
turtle.clear()
turtle.write(f"Score = {score}", font=("Arial",16,"normal"))

Related

How to set parameters for Conv

I am modifying YOLOV5 into a rotating object detection network and replacing its head part with a decoupled head. I successfully replaced the head of the origin YOLOV5 with a decoupled head, but when I tried to replace it for my modified YOLOV5, it reported an error :RuntimeError: Given groups=1, weight of size [256, 128, 1, 1], expected input[1, 63, 32, 32] to have 128 channels,
but got 63 channels instead. The only part I changed in the head of YOLOV5 is that I turned self.no = nc + 5 into self.no = nc + 5 + 180, to adapt to rotating target detection scenarios.
This is the modification I made for the decoupled head
class DecoupledHead(nn.Module):
def __init__(self, ch=256, nc=80, width=1.0, anchors=()):
super().__init__()
self.nc = nc # number of classes
self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors
self.merge = Conv(ch, 256 * width, 1, 1)
self.cls_convs1 = Conv(256 * width, 256 * width, 3, 1, 1)
self.cls_convs2 = Conv(256 * width, 256 * width, 3, 1, 1)
self.reg_convs1 = Conv(256 * width, 256 * width, 3, 1, 1)
self.reg_convs2 = Conv(256 * width, 256 * width, 3, 1, 1)
self.cls_preds = nn.Conv2d(256 * width, self.nc * self.na, 1)
self.reg_preds = nn.Conv2d(256 * width, 4 * self.na, 1)
self.obj_preds = nn.Conv2d(256 * width, 1 * self.na, 1)
def forward(self, x):
x = self.merge(x)
x1 = self.cls_convs1(x)
x1 = self.cls_convs2(x1)
x1 = self.cls_preds(x1)
x2 = self.reg_convs1(x)
x2 = self.reg_convs2(x2)
x21 = self.reg_preds(x2)
x22 = self.obj_preds(x2)
out = torch.cat([x21, x22, x1], 1)
return out
and I changed __init__ in class Detect with
def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
super().__init__()
self.n_anchors = 1
self.nc = nc # number of classes
self.no = nc + 5 + 180 # number of outputs per anchor
self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors
self.grid = [torch.zeros(1)] * self.nl # init grid
self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
# self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv
self.m = nn.ModuleList(DecoupledHead(x, nc, 1, anchors) for x in ch)
self.inplace = inplace # use in-place ops (e.g. slice assignment)
The origin __init__ was like
def __init__(self, nc=80, anchors=(), ch=(), inplace=True): # detection layer
super().__init__()
self.n_anchors = 1
self.nc = nc # number of classes
self.no = nc + 5 # number of outputs per anchor
self.nl = len(anchors) # number of detection layers
self.na = len(anchors[0]) // 2 # number of anchors
self.grid = [torch.zeros(1)] * self.nl # init grid
self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid
self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2)
self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv
self.inplace = inplace # use in-place ops (e.g. slice assignment)
How to modify the class DecoupledHead to make it work?

How to calculate anchor boxes given scale and ratio?

I am referring to code from this Git repository: https://github.com/kbardool/Keras-frcnn/ I don't understand the below code.
# anchor box scales
self.anchor_box_scales or anchor_size = [128, 256, 512]
# anchor box ratios
self.anchor_box_ratios = [[1, 1], [1./math.sqrt(2), 2./math.sqrt(2)], [2./math.sqrt(2), 1./math.sqrt(2)]]
how x1_anc,x2_anc and y1_anc,y2_anc calculated
for anchor_size_idx in range(len(anchor_sizes)):
for anchor_ratio_idx in range(n_anchratios):
anchor_x = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][0]
anchor_y = anchor_sizes[anchor_size_idx] * anchor_ratios[anchor_ratio_idx][1]
for ix in range(output_width):
# x-coordinates of the current anchor box
x1_anc = int(downscale * (ix + 0.5) - anchor_x / 2)
x2_anc = int(downscale * (ix + 0.5) + anchor_x / 2)
# ignore boxes that go across image boundaries
if x1_anc < 0 or x2_anc > resized_width:
continue
for jy in range(output_height):
# y-coordinates of the current anchor box
y1_anc = int(downscale * (jy + 0.5) - anchor_y / 2)
y2_anc = int(downscale * (jy + 0.5) + anchor_y / 2)
# ignore boxes that go across image boundaries
if y1_anc < 0 or y2_anc > resized_height:
continue

Speed function doesn't change the turtles position regardless of any parameters I put in

The program I made has two turtles one being the user(player) and the other being player 2 which are run through a function called checkcollision which determines if the turtles intersect thus moving the second turtle to a random position of -250,250 for its x and y coordinates. The problem however is I want the second turtle(non user) to move in a straight line across the screen and I set it to 2 and I also tried setting it to normal and such all not making the turtle move.
import turtle
import random
wn = turtle.Screen()
wn.setup(width = 450, height = 450)
player = turtle.Turtle()
player2 = turtle.Turtle()
def up():
y = player.ycor()
y = y + 5
player.sety(y)
if y>=310:
player.sety(y-15)
checkcollision(player,player2)
def down():
y = player.ycor()
y = y - 5
player.sety(y)
if y<-310:
player.sety(y+15)
checkcollision(player,player2)
def left():
x = player.xcor()
x = x - 5
player.setx(x)
if x<=-625:
player.setx(x+15)
checkcollision(player,player2)
def right():
x = player.xcor()
x = x + 5
player.setx(x)
if x>=625:
player.setx(x-15)
checkcollision(player,player2)
player.penup()
player.setpos(0,0)
player.showturtle()
player.shape("square")
wn.bgcolor("green")
player2.shape("turtle")
player2.penup()
player2.setpos(300,300)
player2.showturtle()
player2.setheading(-100)
player2.speed(2)
turtle.listen()
turtle.onkeypress(up,"Up")
turtle.onkeypress(left,"Left")
turtle.onkeypress(right,"Right")
turtle.onkeypress(down, "Down")
def checkcollision(t1,t2):
if abs(t1.xcor() - t2.xcor()) < 10 and abs(t1.ycor() - t2.ycor()) < 10:
player2.setpos(random.randint(-250,250), random.randint(-250,250))
checkcollision(player,player2)
Your code has multiple problems and I'm surprised it runs at all as presented above. (It should just fall through the bottom of the code, close the turtle window and return to the console.) For example, it doesn't seem to understand it's own coordinate system -- the x coordinates go from -425 to +425 but we're testing if the turtle's x coordinate is <= -625. Below is my rework to address your question and these other issues:
from turtle import Screen, Turtle
from random import randint
def up():
y = player.ycor() + 5
if y < 200:
player.sety(y)
checkcollision()
def down():
y = player.ycor() - 5
if y > -200:
player.sety(y)
checkcollision()
def left():
x = player.xcor() - 5
if x > -200:
player.setx(x)
checkcollision()
def right():
x = player.xcor() + 5
if x < 200:
player.setx(x)
checkcollision()
def checkcollision():
if player.distance(player2) < 20:
player2.setpos(randint(-200, 200), randint(-200, 200))
screen = Screen()
screen.setup(width=450, height=450)
screen.bgcolor('green')
player = Turtle()
player.shape('square')
player.speed('fastest')
player.penup()
player2 = Turtle()
player2.shape('square')
player2.speed('slowest')
player2.color('yellow')
player2.penup()
checkcollision()
screen.onkeypress(up, 'Up')
screen.onkeypress(left, 'Left')
screen.onkeypress(right, 'Right')
screen.onkeypress(down, 'Down')
screen.listen()
screen.mainloop()

Keras ImageDataGenerator how to see parameters by which image was modified

I understand how and why to use an ImageDataGenerator, but I am interested in casting an eyeball on how the ImageDataGenerator affects my images so I can decide whether I have chosen a good amount of latitude in augmenting my data. I see that I can iterate over the images coming from the generator. I am looking for a way to see whether it's an original image or a modified image, and if the latter what parameters were modified in that particular instance I'm looking at. How/can I see this?
Most of the transformations (except flipping) will always modify the input image. For example, if you've specified rotation_range, from the source code:
theta = np.pi / 180 * np.random.uniform(-self.rotation_range, self.rotation_range)
it's unlikely that the random number will be exactly 0.
There's no convenient way to print out the amount of transformations applied to each image. You have to modify the source code and add some printing functions inside ImageDataGenerator.random_transform().
If you don't want to touch the source code (for example, on a shared machine), you can extend ImageDataGenerator and override random_transform().
import numpy as np
from keras.preprocessing.image import *
class MyImageDataGenerator(ImageDataGenerator):
def random_transform(self, x, seed=None):
# these lines are just copied-and-pasted from the original random_transform()
img_row_axis = self.row_axis - 1
img_col_axis = self.col_axis - 1
img_channel_axis = self.channel_axis - 1
if seed is not None:
np.random.seed(seed)
if self.rotation_range:
theta = np.pi / 180 * np.random.uniform(-self.rotation_range, self.rotation_range)
else:
theta = 0
if self.height_shift_range:
tx = np.random.uniform(-self.height_shift_range, self.height_shift_range) * x.shape[img_row_axis]
else:
tx = 0
if self.width_shift_range:
ty = np.random.uniform(-self.width_shift_range, self.width_shift_range) * x.shape[img_col_axis]
else:
ty = 0
if self.shear_range:
shear = np.random.uniform(-self.shear_range, self.shear_range)
else:
shear = 0
if self.zoom_range[0] == 1 and self.zoom_range[1] == 1:
zx, zy = 1, 1
else:
zx, zy = np.random.uniform(self.zoom_range[0], self.zoom_range[1], 2)
transform_matrix = None
if theta != 0:
rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0],
[0, 0, 1]])
transform_matrix = rotation_matrix
if tx != 0 or ty != 0:
shift_matrix = np.array([[1, 0, tx],
[0, 1, ty],
[0, 0, 1]])
transform_matrix = shift_matrix if transform_matrix is None else np.dot(transform_matrix, shift_matrix)
if shear != 0:
shear_matrix = np.array([[1, -np.sin(shear), 0],
[0, np.cos(shear), 0],
[0, 0, 1]])
transform_matrix = shear_matrix if transform_matrix is None else np.dot(transform_matrix, shear_matrix)
if zx != 1 or zy != 1:
zoom_matrix = np.array([[zx, 0, 0],
[0, zy, 0],
[0, 0, 1]])
transform_matrix = zoom_matrix if transform_matrix is None else np.dot(transform_matrix, zoom_matrix)
if transform_matrix is not None:
h, w = x.shape[img_row_axis], x.shape[img_col_axis]
transform_matrix = transform_matrix_offset_center(transform_matrix, h, w)
x = apply_transform(x, transform_matrix, img_channel_axis,
fill_mode=self.fill_mode, cval=self.cval)
if self.channel_shift_range != 0:
x = random_channel_shift(x,
self.channel_shift_range,
img_channel_axis)
if self.horizontal_flip:
if np.random.random() < 0.5:
x = flip_axis(x, img_col_axis)
if self.vertical_flip:
if np.random.random() < 0.5:
x = flip_axis(x, img_row_axis)
# print out the trasformations applied to the image
print('Rotation:', theta / np.pi * 180)
print('Height shift:', tx / x.shape[img_row_axis])
print('Width shift:', ty / x.shape[img_col_axis])
print('Shear:', shear)
print('Zooming:', zx, zy)
return x
I just add 5 prints at the end of the function. Other lines are copied and pasted from the original source code.
Now you can use it with, e.g.,
gen = MyImageDataGenerator(rotation_range=15,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=0.5)
flow = gen.flow_from_directory('data', batch_size=1)
img = next(flow)
and see information like this printed on your terminal:
Rotation: -9.185074669096467
Height shift: 0.03791625365979884
Width shift: -0.08398553078553198
Shear: 0
Zooming: 1.40950509832 1.12895574928

How to use bounding box in Love2d?

I've been using some extremely bulky code to detect collision between simple objects, and I've heard about bounding boxes. I can't find any tutorials on how to use it, so I'm asking about how to use it. Here is how I detect collision:
function platform.collision()
if player.x + player.width / 2 <= platform.x + platform.width and
player.x + player.width / 2 >= platform.x and
player.y + player.height <= platform.y + platform.height and
player.y + player.height >= platform.y then
The MDN has a rather concise article on 2D collision detection. Being the MDN, the examples are in javascript, but are easily translated to, and applicable in, any language - including Lua.
Let's take a look:
Axis-Aligned Bounding Box
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
Their example, translated to Lua:
local rect1 = { x = 5, y = 5, width = 50, height = 50 }
local rect2 = { x = 20, y = 10, width = 10, height = 10 }
if
rect1.x < rect2.x + rect2.width and
rect1.x + rect1.width > rect2.x and
rect1.y < rect2.y + rect2.height and
rect1.height + rect1.y > rect2.y
then
-- collision detected!
end
-- filling in the values =>
if
5 < 30 and
55 > 20 and
5 < 20 and
55 > 10
then
-- collision detected!
end
A live example, again in JavaScript, demonstrates this well.
Here's a quick (and imperfect) Love2D example you can throw into a main.lua and play around with.
local function rect (x, y, w, h, color)
return { x = x, y = y, width = w, height = h, color = color }
end
local function draw_rect (rect)
love.graphics.setColor(unpack(rect.color))
love.graphics.rectangle('fill', rect.x, rect.y,
rect.width, rect.height)
end
local function collides (one, two)
return (
one.x < two.x + two.width and
one.x + one.width > two.x and
one.y < two.y + two.height and
one.y + one.height > two.y
)
end
local kp = love.keyboard.isDown
local red = { 255, 0, 0, 255 }
local green = { 0, 255, 0, 255 }
local blue = { 0, 0, 255, 255 }
local dim1 = rect(5, 5, 50, 50, red)
local dim2 = rect(20, 10, 60, 40, green)
function love.update ()
if kp('up') then
dim2.y = dim2.y - 1
end
if kp('down') then
dim2.y = dim2.y + 1
end
if kp('left') then
dim2.x = dim2.x - 1
end
if kp('right') then
dim2.x = dim2.x + 1
end
dim2.color = collides(dim1, dim2) and green or blue
end
function love.draw ()
draw_rect(dim1)
draw_rect(dim2)
end
Oka explained it very well. This works for everything rectangular, not rotated and axis aligned. And you even already did it that way. This is great for buttons and the like!
But what I like doing is using (invisible) circles around objects and see if these collide. This works for everything where height is about the same as the width (which is the case for many sidescrolling platformers or top-down RPGs).
It's quite handy if you want to have the object centered at the current position. And it's especially helpful to simulate a finger on a touchscreen device, because a finger is quite a bit bigger than a mouse cursor. ;)
Here's an example on how to use this method. You can copy it as an actual game, it'll work.
--[[ Some initial default settings. ]]
function love.load()
settings = {
mouseHitbox = 5, -- A diameter around the mouse cursor.
-- For a finger (thouchscreen) this could be bigger!
}
objects = {
[1] = {
x = 250, -- Initial X position of object.
y = 200, -- Initial Y position of object.
hitbox = 100, -- A diameter around the CENTER of the object.
isHit = false -- A flag for when the object has been hit.
},
[2] = {
x = 400,
y = 250,
hitbox = 250,
isHit = false
}
}
end
--[[ This is the actual function to detect collision between two objects. ]]
function collisionDetected(x1,y1,x2,y2,d1,d2)
-- Uses the x and y coordinates of two different points along with a diameter around them.
-- As long as these two diameters collide/overlap, this function returns true!
-- If d1 and/or d2 is missing, use the a default diameter of 1 instead.
local d1 = d1 or 1
local d2 = d2 or 1
local delta_x = x2 - x1
local delta_y = y2 - y1
local delta_d = (d1 / 2) + (d2 / 2)
if ( delta_x^2 + delta_y^2 < delta_d^2 ) then
return true
end
end
--[[ Now, some LÖVE functions to give the collisionDetection() some context. ]]
function love.draw()
for i=1,#objects do -- Loop through all objects and draw them.
if ( objects[i].isHit ) then
love.graphics.setColor(255, 0, 0) -- If an object is hit, it will flash red for a frame.
objects[i].isHit = false
else
love.graphics.setColor(255, 255, 255)
end
love.graphics.circle("line", objects[i].x, objects[i].y, objects[i].hitbox/2)
end
end
-- You can use the following to check, if any object has been clicked on (or tapped on a touch screen device).
function love.mousepressed(x,y,button)
if ( button == 1 ) then
local i = objectIsHit(x,y) -- Check, if an object has been hit.
if ( i ) then
-- The object number 'i' has been hit. Do something with this information!
objects[i].isHit = true
end
end
end
function objectIsHit(x,y)
for i=1,#objects do -- Loop through all objects and see, if one of them has been hit.
if ( collisionDetected(x, y, objects[i].x, objects[i].y, settings.mouseHitbox, objects[i].hitbox) ) then
return i -- This object has been hit!
end
end
end
-- For the sake of completeness: You can use something like the following to check, if the objects themselves collide.
-- This would come in handy, if the objects would move around the screen and then bounce from each other, for example.
function love.update(dt)
if ( collisionDetected(objects[1].x, objects[1].y, objects[2].x, objects[2].y, objects[1].hitbox, objects[2].hitbox) ) then
-- The objects collided. Do something with this information!
end
end
As you can see, the collisionDetection() function is quite easy and intuitive to use.
Hopefully I could give you some more insight. And have fun with LÖVE 2D! :)

Resources