Computer Science Canada

Pong

Author:  Ice2099 [ Mon Feb 27, 2006 7:40 pm ]
Post subject:  Pong

Hello, all.
I'm relatively new to Turing and programming in general. (Only my third week in grade 10 Comp Science) but I have managed to make a game of Pong Smile

Anywho, any tips on how to improve this would be most appreciated. And I have heard from some of my friends that the ball goes through the top of the paddle in some cases, although this has not happened to me personally.

Author:  iker [ Tue Feb 28, 2006 7:38 pm ]
Post subject: 

Very impressive. I like the AI, haven't tried the two player, but I would assume its good. I like how you have the score in a different window. One thing maby, instead of just the horazontal speed increasing insanely fast, have both horazontal and verticle speed increase at different increments (so it doesn't always move at a 45) to add a little more challenge.

Author:  Delos [ Tue Feb 28, 2006 9:27 pm ]
Post subject: 

I like this. It's a fairly well put together programme, with only a few bugs. As your friends have reported, the ball does sometimes go through the board. This is simply your collision detection, which may not be entirely 'mutually exclusive and exhastive' in its possibilities.

There are a lot of things you can improve on here, which will cut down your code from 288 lines to...hmm...150 something I'd say. This all involves Procedures, Functions, Arrays, Types, and all those other wonderful pre-Object Oriented concepts we need.

The Turing Walkthrough will give you a good start on all of these topics. I suggest you read through the tuts on all mentioned topics before continuing with this post.

I'll wait...

...ok now that you've done that, a couple of comments.

code:

        if ovaly >= y1 + 30 and ovalx = 10 and ovaly <= y2 - 15 then
            hitNumber += 1
            nx := hitNumber * 1


I love that last line. I know you're doing that for the sake of continuity, which only makes sense when compared to:

code:

       if ovalx = 490 and ovaly >= y3 + 30 and ovaly <= y4 - 15 then
            hitNumber += 1
            nx := hitNumber * -1


I want you to notice a few things:

1.
code:

var y1, y3 := 0
var y2, y4 := 60

All variables look very similar, are treated similarly, and eventually serve a similar purpose.

2.
code:

var ovalx := 250
var ovaly := 200
%...
var nx, ny : int := 1

All variables refer to the same piece in your game - the ball.

3.
code:

        if ovaly >= y1 + 30 and ovalx = 10 and ovaly <= y2 - 15 then
            hitNumber += 1
            nx := hitNumber * 1
            if ny = -1 or ny = -2 then
                ny := -1
            else
                ny := -1
            end if

        elsif ovaly <= y2 - 30 and ovalx = 10 and ovaly >= y1 + 15 then
            hitNumber += 1
            nx := hitNumber * 1
            if ny = 1 or ny = 2 then
                ny := 1
            else
                ny := -1
            end if
        %...

Each clause is structured in exactly the same way and uses all the same variables, with only a few differences in numbers and signs.

Now to consider each point:
1. When we find a series of variables that are essentially components on one big idea, we can just turn them into an array instead. It centralizes our code and makes things so much easier.
code:

% Instead of:
var name1, name2, name3, name4 : string
% use:
var names : array 1..4 of string
% and initialize by:
names (1) := "Name1!"

Optimizing code is a good thing. If we can deal with fewer variable names, we're less likely to confuse them. Of coures, we have to make sure our variables are well named to begin with...

2. When we find a group of variables that all relate to the same object, we can compartmentalize in them in one of several ways. In Object Oriented programming, you'd make a class out of them. For now, we'll stick with a simpler approach, but which uses the same idea. We'll make a record-type.
code:

% Instead of:
var name : string
var age : int
var mass : real
% Use
type info :
   record
      name : string
      age : int
      mass : real
   end record
% and create a new variable of that type:
var person : info
person.name := "My Name!"

Thinking about programming in terms of 'Objects' is the first step you'll take towards higher levels of coding. Start now and you'll be in good standings in no time.

3. Repition need not hinder us. Repitition need not lengthen our code unnecassarily. Indeed, repitition is the soul of wit...repitition is the soul of wit...repitition...
In this case you have a number of clauses that all do the same thing with the same variables. More importantly than the conditions, for now, is the fact that the instructions of each clause involve the same variables.
code:

var name : string
var num : int

put "?"
get name

if name = "Bert" then
   num := 4
elsif name = "Tatiana" then
   num := 2
end if

% A simplistic example.  But we can use it to illustrate the point:
% Use a function:
function setNum (inNum : int) : int
   result inNum
end setNum

% Now, for each "num := ", we'd replace it with "num := setNum()" instead.
% Utterly pointless right now, but this leads up to *so* much.


If we had several lines of code as you do, you could use a procedure to set all the variables in one line instead of in several. For instance, if we had the three variables 'name', 'hat', and 'sponge', we could use a procedure to set them thusly:

code:

procedure setVars (inName, inHat, inSponge : string)
   name := inName
   hat := inHat
   sponge := inSponge
end setVars

%...
setVars ("Name", "Top", "Soft")


Even better yet, we've spotted that all 3 vars deal with the same object, so we create a type instead.

code:

% create type...call it 'data'
procedure setVars (inVar : data, inName, inHat, inSponge : string)
   %  We can now specify which variable will be set, using 'inVar'.
   inVar.name := inName
   inVar.hat := inHat
   inVar.sponge := inSponge
end setVars
setVars (person1, "Alan", "Bowler", "Square-pants")


Even better yet, we've noticed that our procedure does a lot of initialization. So, we instead use a function. As wtd (our resident guru) has said:
wtd wrote:

Mutable state is something that should be avoided when possible.

(Quoting wtd always makes things seem more authoritative).

code:

% Start with our type declaration, again called 'data'.

function init_data (inName, inHat, inSponge : string) : data
   var temp : data
   temp.name := inName
   temp.hat := inHat
   temp.sponge := inSponge
   result temp
end init_data

var newPerson : data
newPerson := init_data("Leia", "Pointy", "Rock")


Works like magic!
How does this all relate to your programme? You have a lot of repitition in it that could be cut out and replaced with procedures and functions. Trust me on this one, it will look a lot neater after, and debugging will be much simpler (like figuring out that phantom platform bug of yours!)

Now, to put things in perspective: do I really expect you to catch on to all I've said right away? It'd be great, but no. I would expect that most of this post went over your head, or at least a bit to the wayside. That's not a problem. I'm simply throwing all this at you since your code speaks quite a bit to your manner of thinking, and I would hazard that you have the right thought process to do well in programming. So, by introducing you, at least briefly, to the concepts that will serve you well I hope to implicitely prime you well enough to peak your interest...

Have fun, and +bits for the good work.

Disclaimer: All code in this post that I typed, I typed in this post. So, it may crash. Sorry, I didn't feel like cross-checking it in the IDE.

Author:  Ice2099 [ Tue Feb 28, 2006 9:52 pm ]
Post subject: 

Wow. Thanks a lot for your input. I honestly did not expect someone to give me that much feed-back on this, and I thank you wholeheartedly for it.

Indeed, I have much now to read over for the next few days. Hopefull, with this new knowledge, I will be able to make this program a lot better.


: