Home > Enterprise >  Python Bounce Ball Game in functional programming
Python Bounce Ball Game in functional programming

Time:03-15

This is a common arcade game, the goal is to hit all targets as many times as you can to earn the highest score. Every time the ball hits a "stone" you earn 1 point, and if it hits 2 you earn 2 points, respectively. If the player fails to catch the ball on the bar or "pole" then the game is over.

My assignment is to turn this game written in object-oriented programming into functional programming.

import time

class Ball:
    def __init__(self, cvs, pole, stones, scre):
        self.stones = stones
        self.cvs = cvs
        self.pole = pole
        self.scre = scre
        self.bottom_hit = False
        self.hit = 0
        self.id = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
        self.cvs.move(self.id, 230, 461)

        self.a = 3
        self.b = -3
        self.cvs.move(self.id, self.a, self.b)
        self.cvs_height = canvas.winfo_height()
        self.cvs_width = canvas.winfo_width()

    def stone_strike(self, push):
        for stone_line in self.stones:
            for stone in stone_line:
                stone_push = self.cvs.coords(stone.id)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            self.hit  = 1
                            self.scre.configure(text="Score: "   str(self.hit))
                            self.cvs.delete(stone.id)
                            return True
                except:
                    continue
        return False

    def pole_strike(self, push):
        pole_push = self.cvs.coords(self.pole.id)
        if push[2] >= pole_push[0] and push[0] <= pole_push[2]:
            if push[3] >= pole_push[1] and push[1] <= pole_push[3]:
                return True
            return False

    def draw(self):
        self.cvs.move(self.id, self.a, self.b)
        push = self.cvs.coords(self.id)
        if self.stone_strike(push):
            self.b = 3
        if push[1] <= 0:
            self.b = 3
        if push[3] >= self.cvs_height:
            self.bottom_hit = True
        if push[0] <= 0:
            self.a = 3
        if push[2] >= self.cvs_width:
            self.a = -3
        if self.pole_strike(push):
            self.b = -3


class Pole:
    def __init__(self, cvs):
        self.cvs = cvs
        self.id = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
        self.cvs.move(self.id, 200, 485)
        self.a = 0
        self.cvs_width = canvas.winfo_width()
        self.cvs.bind_all("<Left>", self.turn_left)
        self.cvs.bind_all("<Right>", self.turn_right)

    def draw(self):
        push = self.cvs.coords(self.id)
        if push[0]   self.a <= 0:
            self.a = 0
        if push[2]   self.a >= self.cvs_width:
            self.a = 0
        self.cvs.move(self.id, self.a, 0)

    def turn_left(self, event):
        self.a = -5

    def turn_right(self, event):
        self.a = 5


class Stone:
    def __init__(self):
        self.id = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")


def start_game(event):
    score.configure(text="Score: 00")
    canvas.delete("all")
    pole = Pole(canvas)
    stones = []
    for i in range(0, 5):
        b = []
        for j in range(0, 19):
            tmp = Stone()
            b.append(tmp)
        stones.append(b)

    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j].id, 25 * j, 25 * i)

    ball = Ball(canvas, pole, stones, score)
    root.update()

    time.sleep(1)
    while 1:
        if not ball.bottom_hit:
            ball.draw()
            pole.draw()
            root.update()
            time.sleep(0.01)
            if ball.hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break

root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", start_game)
root.mainloop()

Here is the code I have written.. There must be logical errors since it's not working. Any ideas??

import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        pa = -5

    def turn_right(event):
        pa = 5

    def stone_strike(push):
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit  = 1
                            score.configure(text="score:"   str(hit))
                            stonaki.delete()
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left)
    canvas.bind_all("<Right>", turn_right)
    push_p = canvas.coords(pole)
    if push_p[0]   pa <= 0:
        pa = 0
    if push_p[2]   pa >= canvas_width:
        pa = 0


    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    root.update()
    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    ba = 3
    bb = -3
    canvas.move(ball, ba, bb)
    push_b = canvas.coords(ball)

    if stone_strike(push_b):
        bb = 3
    if push_b[1] <= 0:
        bb = 3
    if push_b[3] >= canvas_height:
        bottom_hit = True
    if push_b[0] <= 0:
        ba = 3
    if push_b[2] >= canvas_width:
        ba = -3
    if pole_strike(push_b):
        bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

CodePudding user response:

In the process of turning this game written in object-oriented programming into functional programming, we need to take care of variables/widgets which are being used by every function. If we are making changes to some variable in a local function and want to retain the changes made after the function call ends, so I will be making those variables/widgets global.

Also, in the OOP code, changes are being made every time in the canvas using functions draw() for both "ball" and "pole". Hence making two functions for the same drawB() and drawP():

from tkinter import *
import time

def startgame(event):
    score.configure(text="score:00")
    canvas.delete("all")
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    global pole,pa, ba,bb,bottom_hit, hit,ball
    pole = canvas.create_rectangle(0, 0, 100, 10, fill="darkgoldenrod")
    canvas.move(pole, 200, 425)
    pa = 0
    
    def turn_left(event):
        global pa
        pa = -5

    def turn_right(event):
        global pa
        pa = 5

    def stone_strike(push):
        global stones, hit
        for stone_line in stones:
            for stone in stone_line:
                stone_push = canvas.coords(stone)

                try:
                    if push[2] >= stone_push[0] and push[0] <= stone_push[2]:
                        if push[3] >= stone_push[1] and push[1] <= stone_push[3]:
                            canvas.bell()
                            hit  = 1
                            score.configure(text="score:"   str(hit))
                            canvas.delete(stone)   #what to delete
                            return True
                except:
                    continue
        return False

    def pole_strike(push_b):
        global pole
        pole_push = canvas.coords(pole)
        if push_b[2] >= pole_push[0] and push_b[0] <= pole_push[2]:
            if push_b[3] >= pole_push[1] and push_b[1] <= pole_push[3]:
                return True
            return False



    canvas.bind_all("<Left>", turn_left) 
    canvas.bind_all("<Right>", turn_right)

    def drawP():
        global pa,pole
        push_p = canvas.coords(pole)
        if push_p[0]   pa <= 0:
            pa = 0
        if push_p[2]   pa >= canvas_width:
            pa = 0
        canvas.move(pole, pa, 0)

    global stones
    stones = []
    for i in range(0, 5):
        lista = []
        for j in range(0, 19):
            stonaki = canvas.create_rectangle(5, 5, 25, 25, fill="firebrick")
            lista.append(stonaki)
        stones.append(lista)
    for i in range(0, 5):
        for j in range(0, 19):
            canvas.move(stones[i][j], 25 * j, 25 * i)

    
    bottom_hit = False
    hit = 0
    ball = canvas.create_oval(10, 10, 25, 25, fill="cadetblue", width=1)
    canvas.move(ball, 230, 461)
    
    ba = 3
    bb = -3

    root.update()
    
    def drawB():
        global ba,bb,bottom_hit, hit,ball,pole
        canvas.move(ball, ba, bb)
        push_b = canvas.coords(ball)

        if stone_strike(push_b):
            bb = 3
        if push_b[1] <= 0:
            bb = 3
        if push_b[3] >= canvas_height:
            bottom_hit = True
        if push_b[0] <= 0:
            ba = 3
        if push_b[2] >= canvas_width:
            ba = -3
        if pole_strike(push_b):
            bb = -3
    
    time.sleep(1)
    while 1:
        if not bottom_hit:
            drawB()
            drawP()
            root.update()
            time.sleep(0.01)
            if hit == 95:
                canvas.create_text(250, 250, text="YOU WON!!", fill="darkolivegreen", font="Calibri 24")
                break
        else:
            canvas.create_text(250, 250, text="GAME OVER!!", fill="darkolivegreen", font="Calibri 24")
            break


root = Tk()
root.title("Bounce Ball Game")
root.geometry("500x570")
root.resizable(0, 0)

canvas = Canvas(root, width=500, height=500, bd=0, bg="black")
canvas.pack(padx=10, pady=10)
canvas.create_text(250, 250, text="Press Enter to start Game!!", fill="darkolivegreen", font="Calibri 18")

score = Label(height=50, width=80, text="Score: 00", font="Calibri 14 italic")
score.pack(side="left")

root.bind_all("<Return>", startgame)
root.mainloop()

You may further optimize this code.

  • Related