Showing posts with label introductory programming. Show all posts
Showing posts with label introductory programming. Show all posts

Wednesday, February 12, 2014

Adventures in junior programming, episode 4

As I've mentioned in previous posts (1, 2, 3), I've been teaching my son Ben a little Python here and there over the last few years. We're not very consistent, and in fact we haven't really done it much at all in a year or so. But that's not too terrible; it sort of reflects my own experience at Ben's age. I tinkered a little bit with BASIC once in a great while, copied some programs out of books and magazines, "hacked" some programs, forgot many things, and didn't really get deeply into program structure at all until I reached high school. So this is not an urgent task for me.

Ben and I did some work over the weekend. I have taught him a few things over the last couple of years, but we do it so sporadically that it's hard to keep the information fresh in his mind. So we started with this exercise: opened several of the programs that he has worked on in the past, then read through each one and predicted what it was going to do, and why. Doing this helped him get back into his headspace from earlier sessions, and also drilled the syntax back into his mind pretty quickly. Speaking for myself, I also find that reading my own code can help to refamiliarize myself with a language much more quickly than reading somebody else's examples.

Up until now it was clear that we'd done a lot of programs that were really brief -- single problem, single solution. Print all the powers of two up to a million. Print out a times table. Create a simple password verification program (which insults you if you fail; that's a ten year old mindset for you). These problems are interesting in their own right, but the real fun of programming is making a project with no immediate end goal, something you can tinker with over a long period.

Ben is very into gaming, just like his dad. We've been playing World of Warcraft together since he was seven. This seemed like a promising starting point, so I had him create a simple system of rules which could represent a fight between a hero and a monster. So we started out with a few basic hard coded numbers: Hero hit points, monster hit points, hero damage value, monster damage value. Then we wrote a loop so that the fight would keep going until one of the hit point values dropped below zero.

The program is pretty predictable at this point; the beauty of the concept is that we can build on the basic concept over time. So the first thing Ben wanted to do was tweak the numbers: The hero should always win, but just barely. So we did some math to figure out how to make that happen, and we saw the outcome change as the starting values got closer to numbers that "felt right."

This was a good time to introduce functions, which I don't think I've explained in detail before. We had a function for printing the current status ("The hero has X hit points! The monster has Y hit points!"); a function called "hithero" and another called "hitmonster". Initially the hit functions removed a fixed amount of damage; then we got a little more sophisticated, passed in the damage as a parameter, and also printed the action to the screen. After that we also added in weapon descriptions, so it then said "The hero hit the monster for 20 damage with his sword of epicness!"

It's a fun exercise and it has Ben's enthusiasm up, so he now thinks of it as "The first program I wrote mostly by myself!" (I did give him a whole lot of guidance, actually, but I've let him steer the creative direction of the program, so he does have plenty to be proud about.)

We now have a bug and feature wish list which is surely going to grow:
  • Make it so hit points can't go negative.
  • Make a "death" message.
  • Have multiple kinds of weapons; enable weapon switching.
  • Randomize damage within a range, like 16-24.
  • Allow the hero to pick a type of action, a la Pokemon, such as a direct damage attack or a debuff attack.
  • At some point we should probably start discussing object-oriented programming, before we get to the point where we bring in multiple monsters.
  • Item drops?
  • Visiting locations?
  • Ben really wants to make graphics, but that is a very advanced topic, and I'd rather he get solid with the fundamentals before touching that one.
  • I'm a web programmer, and putting stuff in web pages is a great way to showcase your work to friends. So maybe that's a better direction to go than graphics.
Obviously the best part of programming, as per the title of this blog, is building castles in the air -- constructing projects which seems to take on their own reality. So I'm looking forward to some more sessions where we make this thing interesting, while keeping it accessible to a kid who will be twelve soon.

Thursday, July 7, 2011

Adventures in junior programming, episode 3

Haven't been posting on this blog much lately. Since I last posted I got a new full time job at a high tech marketing firm, and also taught myself the fundamentals of both Android and iPhone programming. Interesting stuff, probably good fodder for a future post. But for now, I'd like to go over recent efforts to teach my son more programming.

We let it slip during the school year but we've picked it up again over the summer. We're doing about an hour of work several nights a week. It seems like teaching a nine year old to program irregularly is like pushing the stone of Sisyphus, since every time we take it up again, I have to re-teach concepts that seemed to stick the last time but didn't. Nevertheless, my feeling about programming has always been that you have to learn to "think like a programmer" first, and once you have burned this style into your memory, it becomes much easier to pick up any language or platform in existence.

So what is the core of thinking like a programmer? As far as I can sum up for a kid, it boils down to a few key elements which need to be practiced over and over under a variety of conditions:

  1. Output
  2. Tinkering with variables
  3. Input
  4. Loops
  5. Conditionals
  6. Logical operators
  7. Functions and classes, which fall broadly under the category of "splitting up the work into manageable smaller chunks."

I've fallen into sort of a systematic bootstrapping pattern of teaching, which goes something like this. I have milestones in mind for things Ben should know how to do well, and they should be second nature. The current milestone is: "Write a Python program that counts to ten." Once he can do this without hesitation and without complaining that he needs more hints, we'll bump it up and move on to another milestone.

Each session, I ask him to hit the milestone. If he can't do it well enough, I'll point out what he's missing and go over how it works again. After we get through this, if it's appropriate, I'll introduce a new concept, which we'll drill in the future until that becomes the new milestone.

I've also been making him follow the program logic step by step. It's not as intuitive as you might think. For instance, I ask him to explain HOW the computer goes through the stages of counting to ten, and this is the kind of response I'm looking for:

"First I set the counter to one. One is less than ten, so I enter the loop. I print the counter value. Then I add one to the counter, making it two. Now I return to the beginning of the loop. Two is less than ten, so I enter the loop..."

The kind of response I get takes frequent shortcuts, like "I keep doing that until it's ten." That may be technically correct, but it doesn't capture the essence of thinking through every step, which is critical to catching bugs. If you wind up writing a program that only counts to nine, or goes into an infinite loop, you can keep modifying lines until you get lucky, but if you can see what it's doing at every step, then you're less likely to make mistakes in the first place.

I don't even see the code. All I see is blonde, brunette, red-head...


Programming can seem tedious and repetitive, but at its best you get those "light bulb" moments when it's suddenly crystal clear what you want your program to be doing and how. And sometimes it's even more fun to write the code that solves a puzzle than to grind out the solution on your own.

Wednesday, March 10, 2010

Adventures in junior programming, episode 2

Thank you, everyone, for all the great suggestions that you submitted to my previous post. As a result of all the recommendations, I decided to go ahead and teach myself Python. I'm sure Python enthusiasts will not be surprised to learn that I've found it... almost embarrassingly easy to work with. For instance, the Java program I listed:

class Hello {
public static void main(String[] args) {
System.out.println("Hello world");
}
}

And the Python equivalent:

print "Hello world"

Not even so much as a semicolon is required in this one, because Python actually enforces proper indentation and uses it to recognize code blocks. Since last week, I've checked out a book from the library and read much of the online tutorial, and implemented a simple object-oriented puzzle game that I used to assign to my C++ students. A special "Thank you" goes to Shawn, who volunteered to be my Python guru and code reviewer all week.

So the real question is, how would Ben take to it? I sought the answer to that question over some wings at Plucker's last night. (Before I get to the coding part, let it be known that Ben actually tried one of the hot ones, and pronounced it good. Then he stuck to the mild and drained two root beers.) We did some stuff before the food arrived, and after that we moved to a Starbucks inside a Barnes & Noble and got hot chocolate.

Python works pretty well as a first time language for a few reasons. It is an interpreted language, so you can run it line by line. To facilitate this, there is a command line interface. Type print "hello world" at the prompt and it gives immediate feedback. In fact, it's not even necessary to type "print", as the CLI will assume that if you type an expression without context, you want to see the value of that expression. Type 2+2 and the interpreter dutifully spits out 4. I got to work in some easy math lessons first by making him guess what the result was going to be as I typed various expressions.

After that I re-introduced him to variables. name = "Ben" is all you need to declare a string, and then you type name at the prompt and the interpreter returns 'Ben'. I pointed out the difference between typing name and "name", as one would print "Ben" and the other would print the string "name."

So next, input. By now we are getting to the point where the command line would just get in the way, so I start up a text file and type a two line program that says "Enter your name: "; you type something and then it says "Hello, [name]". Ben likes to try and confound the computer, so he banged out a long gibberish string, and then thought it was hilarious when the computer treated that as a name too. Lesson: computers aren't smart. They can only do what you tell them.

I demonstrated a simple "if" statement by writing a five line program where you are supposed to guess the secret number. (It was 17. No hints, just a magic number in the code. Maybe I'll work on the "higher"/"lower" binary search game next time.)

At this point, I explained, you know all the basic things that a computer program can do. Input, output, and logic. The rest is all variations on that from now on.

We did some more math, and then Ben said he wanted the computer to print the number googol. He was starting to type in all those zeroes, when I said "Wait! Don't count the zeroes!" Then I got to make a "for" loop, which starts with the number one and multiplies it by ten a hundred times.

That managed to impress him, but he was surprised that a hundred zeroes didn't take up more screen space. I said "Ah, but here's the great thing! Instead of 100 zeroes, can you change one thing in the program to make it a thousand?" After some thinking, he got it.

But then he insisted on upping the number to a million zeroes, which didn't work so well. The loop's too long, the computer got stuck calculating the number in the loop and didn't print anything. Lesson: computers are fast, but they don't have infinite speed. You have to write your programs in order to avoid making them get stuck.

I then showed how we would modify the loop to just print sequential numbers on each iteration. I was going to show how the computer can write progressive doubles, but at that point my laptop's battery ran out and we couldn't find a free plug in the entire bookstore, so we browsed some books and called it a night. Total time on programming was a bit less than two hours.

Ben's into it. We'll see how it goes next time I get a chance at him.

Wednesday, March 3, 2010

Adventures in junior programming, episode 1

In my last post I mentioned that I had been writing an instructional applet for my son to learn some math concepts. I received this half-joking reply:

If you truly loved your son, you would have made HIM program that applet! He's seven - that's old enough for Java, at the very least.

I actually think seven is a little young to get started, but as I thought about it, I decided, heck, why not? I picked up some extra money in college tutoring a thirteen year old in C++, and later taught classes for half a year in Fort Worth. It's been over ten years since I taught any actual classes, but is it all that unreasonable to try and give the essential concepts of Java across to a seven year old?

I was already six when my dad bought our first computer, and it wasn't for a few more years that I started reading and understanding the BASIC programs that were in vogue back then. But Ben, like many kids of his generation, was introduced to computers at an early age, and has been comfortable using them for most of his life. He's already seen what the inside of a computer looks like when I swapped out components, and I've even gone over some explanations of binary numbers with him, including the "counting on your fingers" trick.

I have done two lessons so far, first on paper and last night on a laptop. Since I've done only sporadic posts on this blog recently, I think it's not a bad idea to chronicle some of this effort. One thing I discovered while teaching classes is that there is no better way for you to solidify fundamental concepts in your own mind than to try to explain it to somebody else. There is nothing like having to break down assumptions that are second nature to you but completely foreign to another person.

So the first thing I've discovered is: Java is kind of hard.

Programmers traditionally write "Hello world" as their first program, so let's take a look at some ways that this is handled in various languages.

BASIC:

10 print "Hello world"

Nobody learns BASIC anymore, but it was a standard on those old PC 8086's I had as a kid. In fact, if you booted up the computer without inserting a floppy disk, the computer (which lacked a hard drive, and hence lacked a useful operating system in memory) would just load up a BASIC compiler environment directly from the BIOS. It was designed to be a beginner language.

Next let's look at Perl, which is known as a scripting language that is powerful at handling string manipulation:

print "Hello world";

Even simpler, superficially, because Perl is a procedural language which does not use line numbers. Once you start getting into program flow, BASIC starts looking simpler through heavy use of the "goto" statement to control program flow. But as everyone should know, "goto" sucks.

Next we'll look at C, which is what I initially taught in the semester before teaching my classes C++.

#include <stdio.h>

main() {
printf("Hello world");
}

Slightly trickier. In C, nothing runs unless it is directly or indirectly invoked by a "main" function. Thus, unlike the other two languages, in order to become proficient enough to run the most trivial of programs, you have to have some trivial understanding of what a function is about.

There's also the rather cryptic line "#include <stdio.h>", which contains additional wacky symbols that have to be either explained or hand-waved away. When I introduced students to this language, I initially just gave them a complete "hello world" program and said "Focus on what's inside the braces, you'll understand what they mean later." Students love to complain about this sort of thing, as they tend to view unexplained stuff as unnecessary and annoying.

Now here's the java program.

class Hello {
public static void main(String[] args) {
System.out.println("Hello world");
}
}

Seriously now, those are a LOT of details to expect a pure novice to absorb, even if he were older. Let me count the unfamiliar concepts:

  1. "class Hello": Right from the get-go, all Java programs enforce object-oriented structure. Objects and classes are a beast to understand -- I first heard the concept as a senior in high school, failed to self-teach it, and then didn't really get it until my first college course in C++. Now let's explain the difference between a class and an instantiating object to kid who's going on eight.
  2. "main": Just like in the C example, you're not going to get anywhere until you understand methods (aka functions inside a class). I had to make an analogy to nouns and verbs in sentences, since Ben has played Mad Libs before. Even so, it's all pretty abstract, and the word "main" does not suggest an action word at all.
  3. "(...)": Now that we know that "main" is a verb, it's time to learn that all verbs in Java must be followed up with parentheses, which may or may not contain some arguments.
  4. "void": Some methods return an object type and others don't... you know what? I'll tell you later.
  5. "public": So here we encounter the notion of public and private methods, which is intended to separate interface from implementation. Simple, right?
  6. "static": So yeah, this function can be called generically through the class itself, and does not need to be applied to a particular instance of the class. And by the way, all methods called directly from "main" must also be called "static," and the only way to simplify your calls is if you declare a second class and make an instance object.
  7. "String ... args": It's an object declaration. A string is a sequence of characters. Your program won't recognize the "main" method unless that String argument is in there, even though we have no intention of reading the command line arguments yet...
  8. "[]": ...but this string is not just any old single string, it's actually an array of strings, which means there can be any number of them sequentially, see?
  9. "System.out.println": These are not even a proper part of the language definition. They are objects that are accessed by loading in the standard Java libraries, and they actually have a bunch of additional code written to accomplish their task somehow, but you will never see that code. You just have to accept that it will work as a "black box" that does what you expect. And then there's the idea that "System" contains an object called "out" which has a method called "println", where even the last word is not as easy to understand as plain old "print".
  10. All the syntax: This is probably second nature to every programmer by now, but just try to think about how you would explain and reinforce the idea of all the funny characters and when to use them. Quotation marks must signify string literals. Parentheses are required for both declaring and calling methods. Semicolons must end all statements, but NOT the method declaration (I don't know for sure if he ever saw a semicolon before). And, again, what the dots mean in between "System", "out", and "println".

That's quite a lot to bite off just to write two words. And by the way, when I try to get into inputting text, the proper format will be something like this:

String name = "";
InputStreamReader input = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(input);
try {
name = reader.readLine();
} catch (Exception e){};

Compare that to

INPUT "Input name: ", name$

in BASIC, and

$name = <>;

in Perl.

Nevertheless, we heroically slogged through that stuff, discussing some parts in detail and skipping over other parts. Then we finally got to String variables.

No input yet, and no kind of string manipulation or concatenate. Just
String name = "Ben";

followed by

System.out.print("Hello ");
System.out.print(name);

Had a tough time getting him to see that the second print statement would print "Ben" rather than "name," and why.

As far as I can tell, I still have his attention and he wants to keep at it. He would like to write a graphical game, but I told him he has a lot to learn about text-only programs first before we can start to cover that. I know a lot of graphics, but much of it requires knowledge of not only Cartesian coordinates but also trigonometry. Believe me, I'm not touching trig.

A couple of open questions for readers:

  1. Was it a mistake to start in Java?
  2. If not, why not?
  3. If you were being introduced to programming for the very first time, which language would you want to be taught first?
  4. Crazy thought: Ben has a bunch of favorite sites stuffed with Flash games. He even said that he wished he could make one someday, which prompted me to say that it's too advanced for now. I have never learned Flash myself. Is it easy? Is it free? Would it be better or worse than Java as a "first time" language?