Saturday, May 07, 2016

LearnJavaByTurnBasedGame - chapter 3

Learn Java By a Turn-Based Game

By Andrea Valente – andrea270872@gmail.com – andval.net


[CHAPTER 3] Oxidized Pot must be playable – moving the hero


The next thing I must have: the game has to be playable, interactive, not just a sequence of strings printed on the screen. The code below is taken from the OxidizedPot_v1 project, and shows a possible way to let the player decide in which direction the H should move (left or right).


A comment about comments

It is sometimes a good idea to take down few notes while (re)designing something. For example when I was building my LEGO super-robots I had a hard time keeping a record of what the robots looked like. Sometimes I would have to cannibalize the LEGO bricks from one version of a robot to the next, and that made it difficult to remember how each version actually looked like. I tried sketching simple diagrams and writing comments on them, to help me remember how I solved certain problems when building a particular version of a robot. It was annoying and time consuming (I wanted to build robots and play with them, not write notes), but it helped a bit in keeping track of my robots' development.

In programming I can do the same thing, but the good news is that I don't need to write on something else: Java allows me to write my comments directly in between the lines of my code.

The question then is: if I write stuff that is not Java code in the middle of a program, how will Java react to it when I try to run the code? Usually Java (the Java compiler in fact) is VERY picky about syntax, so I might expect trouble… But in fact there is a simple solution, which is also very standard in most programming languages. Just sandwich my comments between some special symbols that tell Java not to look at the comments as code. Smart. It's a bit like air quotes.










In Java a comment starts with /* and ends with */ . The comment can continue on multiple lines. When I only have a short comment that takes no more than 1 line I can use this instead // . The code of project OxidizedPot_v1 shows a couple of single-line comments.

Read player input


The first thing I need is a way to tell my program: 
“ask the player what he/she wants to do, and depending on what the player says, do it”.

In code, that becomes something like the following:
         someVariable = input 
which means: Java please pause the program, wait for the player to input some text, then place the inputted text into a variable (above called someVariable). This is the logical way I might expect things would work… but in Java I need to prepare the ground to read user input, with the following line of code:
        Scanner in = new Scanner(System.in);
I have to write it precisely as it is, just once in the beginning of my code, and after that I can read input from the player as many times as I want. The following code for example:
        String a;
        a = in.nextLine(); 
System.out.println( a );

written in the main block of the program, reads anything that the player types (followed by ENTER), sets that into the variable a (which has type String) and after that it outputs the text, so that the player can see what he/she wrote.

A final note on the Scanner. Java requires that I add the following line before my class block, so at the beginning of the program:
      import java.util.Scanner;
what it means is that Java needs to find the Scanner file (because I did not write the Scanner myself, but I'm borrowing it from other programmers that added it in the standard set of programs that are shipped with Java) and enables me to use Scanner to read player input.

Change a string 

Now that I have a way to read player input, I need to find a way to change the string representing the state of the game from "WEEHEEPEX" to "WEHEEEPEX" if the player moves to the left, and from "WEEHEEPEX" to "WEEEHEPEX" if the player moves to the right. But these 2 rules (call them moveLeft and moveRight) should not just work with the specific string "WEEHEEPEX", instead they should work wherever the H is. 
Better to consider 1 rule at the time. I start with moveLeft. To represent the H moving left I could:
find where the H character is in the string: "WEEHEEPEX" the H is the 4th character
cut the string in 3 pieces: "WE"  "EH"  "EEPEX"
change the central part so that the H moves left: "WE"  "HE"  "EEPEX"
and finally, put the 3 pieces back together: "WEHEEEPEX"
and it is done.
In Java there is an operation that works on strings and that makes a copy of a part of a string (called substring). There is also another operation that can glue together 2 strings one after the other to form a longer one (called concatenation). By using these operations I can explain to Java how to do the steps needed for my moveLeft rule.

        String map = "WEEHEEPEX";
        int heroPos = 3;
        map = map.substring(0,heroPos-1) + 
              "HE" +
              map.substring(heroPos+1);
        heroPos = heroPos-1;
        System.out.println( map );

An interesting fact about Java strings is that the 4th character has in fact index 3. In the string “abc” for example the character a is at position 1 but has index 0, and c is at position 3 but has index 2. And because indexes start from 0, the H character in the map string has index 3. Concatenation of strings is just + , so “ab”+”cd” gives “abcd” as result. The substring operation is a bit more complex to use. For example: 

    System.out.println( "abcd".substring(3) );

will output d , because substring(3) means "create a new string, copy all characters from the original string starting from the character with index 3, and add all other characters until the end of the original string". Substring can also cut a portion of a string out and create a copy, as in this example:

      System.out.println( "abcd".substring(2,4) );

will output cd , because "abcd".substring(2,4) tells Java to create a copy of "abcd", starting from the character at index 2 and ending at index 4, so that gives c and d.

A little note about this perhaps weird assignment:

        heroPos = heroPos-1;

What is the meaning of that? I have to remember that an assignment is just a way to give a value to a variable, the one that appears to the left of the = sign (in this case heroPos). So here what I'm telling Java is to:
take the value that is currently in the variable heroPos (which is 3 in my particular program)
subtract 1 to it (which gives a value of 2)
and place the newly calculated value into the variable to the left of the equals sign (that in this case happens to be the same variable!)
the result is that the value inside the variable heroPos is changed from 3 to 2. This makes sense in my program because I want to represent that my character moves left, from 4th position in the string to 3rd (so from index 3 to index 2).
The rule to moveRight is implemented in a similar way, but mirrored, as shown in project OxidizedPot_v1.

What if… ? Aka doing something only when needed

I have now a trick to read player input, and I worked out how to implement my 2 movement rules. Now the problem is that Java should know when to apply the moveLeft or the moveRight, depending on the player input.

What I need is a way to tell Java that if the player types something, say a, the H should move left, and if the player types something else, like d, the H should move right. What I need to express is the idea that:


   if playerInput is equal to a then moveLeft

   if playerInput is equal to d then moveRight


The Java command for if is in fact just if. 


   String s = in.nextLine();

   if ( s.equals("a") ){

// ... do the moveLeft stuff ... 

   } 


An if command has 2 parts: a head and a body. The head is a test that can be true or false, and the body is just a block containing other commands.
The cool thing is that the program will automatically decide whether to execute the commands that in body of the if, on the condition that the test is true (in fact the if command is called conditional statement in programming terms). 

When I write an if in Java I have to remember that the test must be sandwiched in between 2 round brackets: it is because of Java's syntax.
OK, but what if the test is false? If the player types d, then the string s will have value "d", and s.equals("a") will be false, because it is not true that "d".equals("a") . Then the body of the if will not be executed and the program will simply continue with the next command after the if.
IFs can be used in many other situations. For example I could have a variable that remembers the player's score as a whole number (aka integer). Then the following code:

   int score = 100;
   System.out.println( "let me see your score..." );
   if ( score<=10 ){
System.out.println( "you suck" );
   }
   if ( score>80 ){
System.out.println( "well done" );
   }
   if ( score>=100 ){
System.out.println( "terrific!" );
   }
   System.out.println( "... and that's all I have to say" );

will output:

let me see your score...
well done
terrific!
... and that's all I have to say

which means that both the second and third IF executed their bodies, since both their tests were true. But depending on the value of the score variable it might output something completely different. 
I can sandwich this code in a main block, inside a class block, and change the first line to:

    int score = 5;

to see what happens… It should output:

let me see your score...
you suck
... and that's all I have to say

which is correct because if score is less or equals than 10, the code should output "you suck". The other tests are:
score > 80 , which means "is score greater than 80?"
and: score>= 100 , meaning  "is score greater or equal than 100?"

Note: a and d are typically used in games to move left-right because of the position of the keys in a QWERTY keyboard that reminds of the way the arrow keys are placed on the right of the keyboard.


Reflections

The code in project OxidizedPot_v1 has a typical structure that is found in many programs:
1. initialization of program state 
2. input
3. calculations and/or decisions
4. output
Step 1 means variables are declared and values assigned to them, so that the state of the program represents some situation I want to work with. 
Step 2 is about letting the user/player input some data: this step makes the program interactive. Without user input I can only perform calculations or execute commands in a fixed way. 
In step 3 some calculations are performed, and typically that involves changing the values of the variables (aka the state of the program) according to some formulas. Step 3 can also involve conditional commands, things that I might do or not depending on the input and the values of my variables. Typically this step is implemented using IFs.
Finally, step 4 allows the program to show the results (or possibly its current state) to the user.

[Alternative ways]
Instead of cutting and putting back together my string map in the same line of code, I can use temporary variables (aka variables that exist only to help me doing something in a specific portion of my code and then I will not use them again). Project OxidizedPot_v1_1 shows this approach.

[Exercises]
1. Create a copy of project OxidizedPot_v1 (call it perhaps OxidizedPot_v1_2) so that the game prints the level in this way:
             "WE ]-[ EEPEX"
both before and after player's input is processed. The "H" representing the hero has been replaced by the string " ]-[ ". A possible execution of the program could be that the situation is printed on screen, then the player moves left and the new situation (aka game state) is printed again, like this:
             WE ]-[ EEPEX
-> player input: "a"
             W ]-[ EEEPEX
Suggestion: you might want to use a couple of variables to hold portions of the original map string, to help you print the new version of the game situation (check out project OxidizedPot_v1_1).

1.b. Practice working with string by printing the first 3 characters of the map string, followed in a new line by the last 3 characters. Add the code to achieve that at the end of the code in your OxidizedPot_v1_2 project.  The result should be something like (assuming the player moved left):
WEH
PEX

2. Make a copy of project OxidizedPot_v1, call it OxidizedPot_v1_3. In the very beginning of the main block, declare a int variable called score and set its value to 0. Now add an IF command in such a way that if the player types "+", the score changes to 100. The value of the variable score should be printed on screen each time the map is printed, to help the player keeping track of his/her score. It should be possible to run the game, type  +  and get a score of 100 without moving the "H".







No comments:

Post a Comment