It is currently Wed Nov 27, 2024 1:21 pm



Reply to topic  [ 3 posts ] 
 Python Programming 
Author Message
Site Administrator
Site Administrator
User avatar

Joined: Wed Jul 05, 2006 10:32 am
Posts: 1917
Location: Brooklyn, NY
YAY, so last night, I finished a course on basic python programming.
it was a go-at-your-own-pace kind of course. Finished a month early (2nd in the class) - had I not slacked off because of senioritis, I might have finished before April even started.

So, what's the point? I have a problem with exactly *HOW* I passed that programming exam.
I got the exact question that had been at the end of the lesson - standard for the course. Like always, however, I ignored all of the questions at the end of the chapter, and just tried to finish it.

I got my program to work. but I don't like how they solved it.
I have the question, the original code, my answer, and their answer. My questions include:
1.) Did I screw up
2.) Is mine more correct
3.) What is the fundamental difference between what I did and what they did.


So, anyone with Python experience, it would be nice if you can help. If there is anyone who wants me to, I can upload all of my files, including lessons and exams.


Question: Code is provided for the original Blocker game program developed in Unit 11. Modify the program so that the goal moves horizontally, one pixel per animation step, bouncing when it hits either side of the playing field.
Beginning Code:
Code:
from tkinter import *
from random import choice
from time import clock

# sx and sy are the horizontal and vertical speed of the ball
# in pixels per animation step
block, ball, sx, sy = None, None, 5, 5

# returns position of the *center* of the ball
def ballPosition():
    x1, y1, x2, y2 = list(field.coords(ball))
    return [(x1+x2)/2, (y1+y2)/2]

def startGame():
    global startTime, ball, block
    # remember to delete block and ball from previous game
    if block:
        field.delete(block)
    block = None
    if ball:
        field.delete(ball)
    # place ball at random
    upperLeftX = choice(list(range(290)))
    upperLeftY = choice(list(range(290)))
    ball = field.create_oval(upperLeftX, upperLeftY,
                             upperLeftX+10, upperLeftY+10,
                             fill='blue')
    startTime = clock()
    animate()

def animate():
    global sx, sy
    pattern = 'Elapsed time: {0:.1f} seconds'
    timeDisplay['text'] = pattern.format(clock()-startTime)
    x, y = ballPosition()
    hitVertical = hitBlock() and blockType == 'vertical'
    if x+sx>300 or x+sx<0 or hitVertical:
        sx *= -1
    hitHorizontal = hitBlock() and blockType == 'horizontal'
    if y+sy>300 or y+sy<0 or hitHorizontal:
        sy *= -1
    field.move(ball, sx, sy)
    if not inGoal():
        root.after(20, animate)
       
# Only one block at a time; delete one before creating the next

def leftClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x-20, event.y,
                                   event.x+20, event.y+6,
                                   fill='light green')
    blockType = 'horizontal'

def rightClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x, event.y-20,
                                   event.x+6, event.y+20,
                                   fill='light green')
    blockType = 'vertical'

# return True if the center of the ball is inside the
# block’s boundary
def hitBlock():
    if not block:
        return False
    ballX, ballY = ballPosition()
    blockX1, blockY1, blockX2, blockY2 = field.coords(block)
    return (blockX1 <= ballX <= blockX2 and
            blockY1 <= ballY <= blockY2)

# return True if the center of the ball is inside the
# goal area
def inGoal():
    ballX, ballY = ballPosition()
    return 0 <= ballX <= 25 and 275 <= ballY <= 300
   
root = Tk()

timeDisplay = Label(root)
timeDisplay.pack()

field = Canvas(root, width=300, height=300, bg='light blue')
field.pack()

startButton = Button(root, command=startGame, text='Go')
startButton.pack()

# the goal
field.create_rectangle(0, 275, 25, 300, fill='red')

field.bind('<ButtonPress-1>', leftClick)
field.bind('<ButtonPress-3>', rightClick)

mainloop()


My answer:
Code:
from tkinter import *
from random import choice
from time import clock

# sx and sy are the horizontal and vertical speed of the ball
# in pixels per animation step
block, ball, goal, sx, sy, gX, gY = None, None, None, 5, 5, 1, 0

# returns position of the *center* of the ball
def ballPosition():
    x1, y1, x2, y2 = list(field.coords(ball))
    return [(x1+x2)/2, (y1+y2)/2]

def goalPosition():
    x1, y1, x2, y2 = list(field.coords(goal))
    return [(x1+x2)/2, (y1+y2)/2]
   
def startGame():
    global startTime, ball, block, goal
    # remember to delete block and ball from previous game
    if block:
        field.delete(block)
    block = None
    if ball:
        field.delete(ball)
    if goal:
        field.delete(goal)
    # place goal at coordinates
    goalX = choice (list(range(275)))
    goalY = 288
    goal = field.create_rectangle(goalX-12, goalY-12,
                                  goalX+12, goalY+12,
                                  fill='red')
    # place ball at random
    upperLeftX = choice(list(range(290)))
    upperLeftY = choice(list(range(290)))
    ball = field.create_oval(upperLeftX, upperLeftY,
                             upperLeftX+10, upperLeftY+10,
                             fill='blue')
    startTime = clock()
    animate()

def animate():
    global sx, sy, gX, gY
    pattern = 'Elapsed time: {0:.1f} seconds'
    timeDisplay['text'] = pattern.format(clock()-startTime)
# Defining Goal movement
    goalX, goalY = goalPosition()
    if goalX+gX>287 or goalX+gX<13:
        gX *= -1
    goalY = 275
    if goalY+gY>288 or goalY+gY<288:
        goalY == 288
    field.move(goal, gX, gY)
# Defining Ball movement
    x, y = ballPosition()
    hitVertical = hitBlock() and blockType == 'vertical'
    if x+sx>300 or x+sx<0 or hitVertical:
        sx *= -1
    hitHorizontal = hitBlock() and blockType == 'horizontal'
    if y+sy>300 or y+sy<0 or hitHorizontal:
        sy *= -1
    field.move(ball, sx, sy)
    if not inGoal():
        root.after(20, animate)

       
# Only one block at a time; delete one before creating the next

def leftClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x-20, event.y,
                                   event.x+20, event.y+6,
                                   fill='light green')
    blockType = 'horizontal'

def rightClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x, event.y-20,
                                   event.x+6, event.y+20,
                                   fill='light green')
    blockType = 'vertical'

# return True if the center of the ball is inside the
# block’s boundary
def hitBlock():
    if not block:
        return False
    ballX, ballY = ballPosition()
    blockX1, blockY1, blockX2, blockY2 = field.coords(block)
    return (blockX1 <= ballX <= blockX2 and
            blockY1 <= ballY <= blockY2)

# return True if the center of the ball is inside the
# goal area
   
def inGoal():
    ballX, ballY = ballPosition()
    goalX, goalY = goalPosition()
    return goalX-12 <= ballX <= goalX+12 and goalY-12 <= ballY <= goalY+12
   
root = Tk()

timeDisplay = Label(root)
timeDisplay.pack()

field = Canvas(root, width=300, height=300, bg='light blue')
field.pack()

startButton = Button(root, command=startGame, text='Go')
startButton.pack()


field.bind('<ButtonPress-1>', leftClick)
field.bind('<ButtonPress-3>', rightClick)

mainloop()


Thier answer:
Code:
from tkinter import *
from random import choice
from time import clock

# sx and sy are the horizontal and vertical speed of the ball
# in pixels per animation step
block, ball, sx, sy, goalSpeed = None, None, 5, 5, 1

fieldSize, goalSize, ballSize = 300, 25, 10

# returns position of the *center* of the ball
def ballPosition():
    x1, y1, x2, y2 = list(field.coords(ball))
    return [(x1+x2)/2, (y1+y2)/2]

def startGame():
    global startTime, ball, block
    # remember to delete block and ball from previous game
    if block:
        field.delete(block)
    block = None
    if ball:
        field.delete(ball)
    # place ball at random
    upperLeftX = choice(list(range(290)))
    upperLeftY = choice(list(range(290)))
    ball = field.create_oval(upperLeftX, upperLeftY,
                             upperLeftX+10, upperLeftY+10,
                             fill='blue')
    startTime = clock()
    animate()

def goalLeftX():
    return list(field.coords(goal))[0]

def animate():
    global sx, sy, goalSpeed
    pattern = 'Elapsed time: {0:.1f} seconds'
    timeDisplay['text'] = pattern.format(clock()-startTime)
    x, y = ballPosition()
    hitVertical = hitBlock() and blockType == 'vertical'
    if x+sx>300 or x+sx<0 or hitVertical:
        sx *= -1
    hitHorizontal = hitBlock() and blockType == 'horizontal'
    if y+sy>300 or y+sy<0 or hitHorizontal:
        sy *= -1
    if goalLeftX()+goalSpeed<0 or goalLeftX()+goalSize+goalSpeed>fieldSize:
        goalSpeed *= -1
    field.move(ball, sx, sy)
    field.move(goal, goalSpeed, 0)
    if not inGoal():
        root.after(20, animate)
       
# Only one block at a time; delete one before creating the next

def leftClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x-20, event.y,
                                   event.x+20, event.y+6,
                                   fill='light green')
    blockType = 'horizontal'

def rightClick(event):
    global block, blockType
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x, event.y-20,
                                   event.x+6, event.y+20,
                                   fill='light green')
    blockType = 'vertical'

# return True if the center of the ball is inside the
# block’s boundary
def hitBlock():
    if not block:
        return False
    ballX, ballY = ballPosition()
    blockX1, blockY1, blockX2, blockY2 = field.coords(block)
    return (blockX1 <= ballX <= blockX2 and
            blockY1 <= ballY <= blockY2)

# return True if the center of the ball is inside the
# goal area
def inGoal():
    ballX, ballY = ballPosition()
    return goalLeftX() <= ballX <= goalLeftX()+goalSize and fieldSize-goalSize <= ballY <= fieldSize
   
root = Tk()

timeDisplay = Label(root)
timeDisplay.pack()

field = Canvas(root, width=fieldSize, height=fieldSize, bg='light blue')
field.pack()

startButton = Button(root, command=startGame, text='Go')
startButton.pack()

# the goal
goal = field.create_rectangle(0, fieldSize-goalSize, goalSize, fieldSize, fill='red')

field.bind('<ButtonPress-1>', leftClick)
field.bind('<ButtonPress-3>', rightClick)

mainloop()


Help?


Fri Apr 20, 2012 2:19 pm
Profile
Pokemon Ranger
Pokemon Ranger
User avatar

Joined: Thu Oct 01, 2009 6:05 am
Posts: 614
Location: Coming soon to a store near you!
Okay, first of all, i'm not going to admit expertise in Visual Python, but i know a little. I'm much better at other windows programming (C# and VB.NET).

After looking at all your code and running it, now i'll answer your questions before my own comments:

1.) Did I screw up ~ No, it does as it's supposed to and how it asks in the question. And exactly the same as their answer.
2.) Is mine more correct ~ With programming, there's no set way to do things. I'm sure you know this. The main functions behind programs are that it does as it is meant to, by any means possible, and then efficiency of the program. Look below for the proper answer to this.
3.) What is the fundamental difference between what I did and what they did. ~ As far as i can gather, the main difference isn't huge. But they used a different way of 'grabbing' the coordinates of the goal. And also, you took the y coordinates as well, which if i understand correctly, arent needed?

So technically yours is a tiny bit less efficient. But still does what it's supposed to just in a slightly different way. As i said, Python really isn't m strong point but it was fun to look at. Hope this helped. If you want to compare better, cut out duplicated bits of code between yorus and their answer.That's what i did and the differences are easily compared.

Regards

_________________
[img]http://i.imgur.com/VFUEj21.png[/img]


Wed Apr 25, 2012 3:56 am
Profile
Site Administrator
Site Administrator
User avatar

Joined: Wed Jul 05, 2006 10:32 am
Posts: 1917
Location: Brooklyn, NY
Heh, I found out yesterday.

The guy that wrote the program, was using (in his "solution") the modified form of the program, from a previous question in their solved problems (making number modifications easier).

No there were other problems, which I'm bringing up when I see the guy who wrote this. We never learned the job function, so if you restart without winning, the speed is cumulative, as is the number of animation steps that the goal needs to be in the goal.

Here is a heavily modified form of the program for those who look in and want to play the game. Python 3.2 is online, and this has no modules other than those native to Python (no need for extra code beyond this).
Code:
from tkinter import *
from random import choice
from time import clock

# allow the user to make the game as fast as they like, and as big as they like (minimum size 100).
ballSpeed = int(input('How fast for the ball? '))
goalSpeed = int(input('How fast for the goal? '))
fieldSize = int(input('How large do you want the field to be (minimum 100)? '))
job = None
while fieldSize < 100:
        fieldSize = int(input('How large do you want the field to be (minimum 100)? '))


# sx and sy are the horizontal and vertical speed of the ball
# in pixels per animation step. gX will stand for the goal
block, ball, goal, sx, sy, gX, blockSize = None, None, None, ballSpeed, ballSpeed, goalSpeed, fieldSize/20

# returns position of the *center* of the ball and goal
def ballPosition():
    x1, y1, x2, y2 = list(field.coords(ball))
    return [(x1+x2)/2, (y1+y2)/2]

def goalPosition():
    x1, y1, x2, y2 = list(field.coords(goal))
    return [(x1+x2)/2, (y1+y2)/2]
   
def startGame():
    global startTime, ball, block, goal, job
    print('NEW GAME')
    # remember to delete block and ball from previous game   
    if block:
        field.delete(block)
    block = None
    if ball:
        if job is not None:
           root.after_cancel(job)
        field.delete(ball)
    if goal:
        field.delete(goal)
    # place goal at random X. This must be done BEFORE coding the ball's position, or the goal will cover the ball.
    goalX = choice(list(range(fieldSize-25)))
    print('Initial goalX = ', goalX)
    if goalX<13:
        goalX = 13
    if goalX>fieldSize-12:
        goalX = fieldSize-12
    goalY = fieldSize-12
    goal = field.create_rectangle(goalX-12, goalY-12,
                                  goalX+12, goalY+12,
                                  fill='red')
    print('coordinates(goal)', (field.coords(goal)))
    # place ball at random
    ballX = choice(list(range(fieldSize-10)))
    ballY = choice(list(range(fieldSize-10)))
    ball = field.create_oval(ballX-5, ballY-5,
                             ballX+5, ballY+5,
                             fill='blue')
    print('coordinates(ball)', ballX, ballY)
    # to prevent the ball from starting and the game already been won
    if inGoal():
        print('FLUKE')
        startGame()
    startTime = clock()
    animate()

def animate():
    global sx, sy, gX, job
    pattern = 'Elapsed time: {0:.1f} seconds'
    timeDisplay['text'] = pattern.format(clock()-startTime)
    # Defining Goal movement. This must be done BEFORE coding the ball's movement, or the goal will cover the ball.
    goalX, goalY = goalPosition()
    # If the goal's next move puts it to the right of 288, or left of 13
    if goalX+gX>fieldSize-12 or goalX+gX<13:
        gX *= -1
    field.move(goal, gX, 0)
    # Defining Ball movement
    x, y = ballPosition()
    hitVertical = hitBlock() and blockType == 'vertical'
    if x+sx>fieldSize-5 or x+sx<5 or hitVertical:
        sx *= -1
    hitHorizontal = hitBlock() and blockType == 'horizontal'
    if y+sy>fieldSize-5 or y+sy<5 or hitHorizontal:
        sy *= -1
    field.move(ball, sx, sy)
    if inGoal():
        print('game over', ballPosition(), field.coords(goal))
        job = None
    else:
        job = root.after(20, animate)

       
# Only one block at a time; delete one before creating the next

def leftClick(event):
    global block, blockType, blockSize
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x-blockSize, event.y-3,
                                   event.x+blockSize, event.y+3,
                                   fill='light green')
    blockType = 'horizontal'

def rightClick(event):
    global block, blockType, blockSize
    if block:
        field.delete(block)
    block = field.create_rectangle(event.x-3, event.y-blockSize,
                                   event.x+3, event.y+blockSize,
                                   fill='light green')
    blockType = 'vertical'

# return True if the center of the ball is inside the
# block’s boundary
def hitBlock():
    if not block:
        return False
    ballX, ballY = ballPosition()
    blockX1, blockY1, blockX2, blockY2 = field.coords(block)
    return (blockX1 <= ballX <= blockX2 and
            blockY1 <= ballY <= blockY2)

# return True if the center of the ball is inside the
# goal area
   
def inGoal():
    ballX, ballY = ballPosition()
    goalX, goalY = goalPosition()
    return goalX-12 <= ballX <= goalX+12 and fieldSize-25 <= ballY <= fieldSize
   
root = Tk()

timeDisplay = Label(root)
timeDisplay.pack()

field = Canvas(root, width=fieldSize, height=fieldSize, bg='light blue')
field.pack()

startButton = Button(root, command=startGame, text='Go')
startButton.pack()


field.bind('<ButtonPress-1>', leftClick)
field.bind('<ButtonPress-3>', rightClick)

mainloop()


More modifications to come


Wed Apr 25, 2012 6:10 am
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 3 posts ] 

Who is online

Users browsing this forum: No registered users and 18 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by STSoftware for PTF.