Sunday, October 14, 2012


 I want to follow up on my previous post by looking at the code for the onClick method.  However, a quick look tells me that it is too complex for a tyro to make any sense out of.  So, I'm going to start with an earlier proof of concept:

 [1]  public void onClick(View v){
 [2]       int   dispNumber;
 [3]       TextView text = (TextView)findViewById(R.id.LineOne);
 [4]       EditText formText = (EditText)this.findViewById(R.id.entry);
 [5]       TextView lastText = (TextView)findViewById(R.id.EndOfGame);
 [6]       String DoDahTxt = formText.getText().toString();
 [7]       dispNumber      = Integer.parseInt(DoDahTxt);
 [8]       dispNumber      = dispNumber + 1;
 [9]       DoDahTxt        = Integer.toString(dispNumber);
 [10]      text.setText(DoDahTxt);
 [11]      lastText.setText("You Loose!");  }
 

This went (replaced) the existing onClick method.  It did everything that was needed in the real onClick method: it displayed something, took input from the text box, did something with that input, and displayed some kind of a result.  So let's go over this line by line:

[1]   First line of the block.  Note that this is a Public method, and that it does not return anything.

[2]   The final result will need to keep track of the current working numbers: the number behind what the Rat is displaying (either RAT, CAT, RATCAT, or the number itself if it is not divisible by 3 or 5).  So, we define a local integer variable.

[3]  The first line of our layout (in horizontal mode) consists two views: id/TopLine, which we plan to use as a static text field 'The RAT Says', and the view id/LineOne, which we will use as a dynamic field, and which starts out with the value '1'.  Our code needs to get a handle on this dynamic field.  And we can't just change it's value with simple assignment statements.  Line [3] gives us a variable (which I like to think  of as a handle) named 'text'

 [3]       TextView text = (TextView)findViewById(R.id.LineOne);

Which gives the variable 'text' the id of the text part of the LineOne view.  We will need this later on.  For now, I was getting all the handles at one time.

 [4]       EditText formText = (EditText)this.findViewById(R.id.entry);

[4]  Remember that the data entry text box is part of an EditText view named 'entry'.  And line [4] get us a handle on this data entry box.  Note that the views are named @+id/viewname in the XML, but R.id.viewname in the code.  Then you won't spend as much time as I did worrying about this.

[5]  At this time I was planning on using a view to contain any system comments, such as end of game.  This line gave me a handle on that field. 

[6]  Something different:

[6]       String DoDahTxt = formText.getText().toString();

So, we take whatever was input in the input box, and whose handle is formText (and remember, we only execute this block of code if the button was pushed, so there should be something in the box.  And we get it with the getText method, and then use to String to turn whatever it is into a string.

[7]  What this silly block does is take whatever number the user enters (without checking that it really was a number), add one to it, display the result, and then display 'You Loose'.  Since we plan to add one to whatever, we must make it an integer

[8]  As planned, we add one to it.

[9]  And turn it into a string, so we can stick it back onto our form.


[10]      text.setText(DoDahTxt);
This is (duh!) the setText method, available to all strings.  Since 'text' is a string, it has the setText method (note to the one or two really experienced Java programmers reading this post:  inexperienced Java programmers really need to think like this once in a while).  And this is how whatever is inside the parenthesis gets stuck into 'text'.  No assignment operator needed.

[11]  Then we put something out on the last line, just to prove that we can.

O.K., but what this thingee is really supposed to do is the following:

Variables: 
currNumber:  The number under consideration, from the point of view of whoever is making a move.  At the start of the game, the currNumber is 1.  When the player is ready to make his first move, the currNumber becomes 2.  Then the RAT gets to play, and the currNumber is 3.

maxNumber:  The currNumber at which the game is over.

dispString: What is supposed to be entered or displayed on that turn.  dispString is related to currNumber as follows:

If currNumber is divisible by 15, dispString = 'RATCAT'
Otherwise, if currNumber is divisible by 5, dispString = 'CAT'
Otherwise, if currNumber is divisible by , dispString = 'RAT'
Otherwist, dispString = toString(currNumber).

PreCondition:  currNumber = 1.  Empty input box for the player.
The RAT has displayed '1'.

 Loop Invariant (condition at end of player's turn):  currNumber has been incremented by 2.  The RAT has displayed the dispString for the currNumber.  The player has entered the dispString for the currNumber - 1,  and that string was accepted.  After entering the correct number, the input box has been blanked out.

PostCondition:  either currNumber has exceeded maxNumber, or the player made a mistake.  Display an appropriate message, and restart the game.

Rather than display this message myself, I decided to use the Toast method to display the results of the game.

And, with all of this help, the reader should be able to make sense of the code:


    public void onClick(View v){
        String inputNumber = " ";
        String matchString = " ";
        RatCatApp app = (RatCatApp)getApplication();
        TextView text = (TextView)findViewById(R.id.LineOne);
        EditText formText = (EditText)this.findViewById(R.id.entry);
         if (app.currNumber < (app.maxNumber))
         {
                    app.currNumber++;
                 matchString = getMatchTxt(app.currNumber);
                inputNumber = formText.getText().toString();     
                if (!matchString.equals(inputNumber)){
                        Toast.makeText(this, "You Loose!", Toast.LENGTH_SHORT).show();
                         restartMeUp();
                         } else {
                           app.currNumber++;
                           formText.setText("");
                            text.setText(getMatchTxt(app.currNumber));
                       }
          }  /* All turns until the last one go thru here  */
    
         if (app.currNumber == app.maxNumber) {
             if (matchString.equals(inputNumber)) {
                     Toast.makeText(this, "You Beat Me!", Toast.LENGTH_SHORT).show();
                     restartMeUp();     /*  Correct last turn, let's end here  */
                                                     }
             else  {
                    Toast.makeText(this, "You Loose!", Toast.LENGTH_SHORT).show();
                    restartMeUp();
                     } /* Goofed on the last turn  */
          }
            
         if (app.currNumber >(app.maxNumber))
          {
            Toast.makeText(this, "You Beat Me!", Toast.LENGTH_SHORT).show();
            restartMeUp();
           }   /* should only get here if an odd number for maxNumber is set */
       }
        public static String getMatchTxt(int P1){
                 int  mod = P1%15;
                  if (mod == 0){ return "RATCAT";}
                  if (mod%5 == 0) {return "CAT";}
                  if (mod%3 == 0)  {return "RAT";}
                  return Integer.toString(P1);
              }
        public void restartMeUp() {
               Toast.makeText(this, "Starting Over...", Toast.LENGTH_SHORT).show();
            RatCatApp app = (RatCatApp)getApplication();
               app.currNumber  = 1;
               EditText formTxt = (EditText)this.findViewById(R.id.entry);
                  TextView txt = (TextView)findViewById(R.id.LineOne);
               txt.setText("1");
             formTxt.setText("");
        }

}

Thursday, September 27, 2012

Android Games: Some Code

Time to look at some code.  The way that I would prefer to do this is to start with my first attempt,  describe what went wrong, and expound on what I learned in fixing it.  Unfortunately, my notes are too incomplete to do this.  So, instead, I am going to list my code as it stands Right Now, and comment on each line (or group of lines).

So, here is the code (and note that my numbers make it invalid):

package rat.cat;                         [1]

import static java.lang.System.out;      [2]
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
                                        [3]
public class RatCatActivity extends Activity implements OnClickListener  {
    /** Called when the activity is first created. */
    @Override
        public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Button buttoff =                       [4]       (Button)findViewById(R.id.button1);    
        buttoff.setOnClickListener(this);       [4a]
    }
   
    public void onClick(View v){
        String inputNumber = " ";
        String matchString = " ";
        RatCatApp app = (RatCatApp)getApplication();
        TextView text = (TextView)findViewById(R.id.LineOne);
        EditText formText = (EditText)this.findViewById(R.id.entry);
         if (app.currNumber < (app.maxNumber))
         {
                    app.currNumber++;
                 matchString = getMatchTxt(app.currNumber);
                inputNumber = formText.getText().toString();     
                if (!matchString.equals(inputNumber)){
                        Toast.makeText(this, "You Loose!", Toast.LENGTH_SHORT).show();
                         restartMeUp();
                         } else {
                           app.currNumber++;
                           formText.setText("");
                            text.setText(getMatchTxt(app.currNumber));
                       }
          }  /* All turns until the last one go thru here  */
    
         if (app.currNumber == app.maxNumber) {
             if (matchString.equals(inputNumber)) {
                     Toast.makeText(this, "You Beat Me!", Toast.LENGTH_SHORT).show();
                     restartMeUp();     /*  Correct last turn, let's end here  */
                                                     }
             else  {
                    Toast.makeText(this, "You Loose!", Toast.LENGTH_SHORT).show();
                    restartMeUp();
                     } /* Goofed on the last turn  */
          }
            
         if (app.currNumber >(app.maxNumber))
          {
            Toast.makeText(this, "You Beat Me!", Toast.LENGTH_SHORT).show();
            restartMeUp();
           }   /* should only get here if an odd number for maxNumber is set */
       }
        public static String getMatchTxt(int P1){
                 int  mod = P1%15;
                  if (mod == 0){ return "RATCAT";}
                  if (mod%5 == 0) {return "CAT";}
                  if (mod%3 == 0)  {return "RAT";}
                  return Integer.toString(P1);
              }
        public void restartMeUp() {
               Toast.makeText(this, "Starting Over...", Toast.LENGTH_SHORT).show();
            RatCatApp app = (RatCatApp)getApplication();
               app.currNumber  = 1;
               EditText formTxt = (EditText)this.findViewById(R.id.entry);
                  TextView txt = (TextView)findViewById(R.id.LineOne);
               txt.setText("1");
             formTxt.setText("");
        }

}

[1] Note that this is package rat.cat.  When you create an application in Eclipse, you have to specify a name, and the name must contain a period.  This name is going to become important; the name of other objects will depend on it.

[2] Next, we must import a number of methods and classes.  Ctrl-Shift-0 will automagically import any missing items.  Of course, sometimes one has to keep adding new imports, because it isn't until item-A gets imported that we find we need item-B

[3]  This method gets created by Eclipse when the project gets created.  AFAIK, every Android App will have some variation of this method.

Now, the basic class (what Eclipse creates) looks like this:

public class RelativeLayoutsActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

And, a few notes here:

1)   The first thing Android does when it starts up an app is call the onCreate method.  Since every app does something unique from all other apps, they will need a more-or-less unique onCreate class.  So, the native onCreate method must be overridden, and Eclipse throws in the @Override directive to let the compiler know that you want to do this.

2)  The main thing which this stock onCreate does is to call setContentView to put our layout (defined in layout.main) on the screen.  This may be a good place to put an image of the app:


[4]  Note that the main thing we have done to the onCreate method  is to add a button, more specifically, a Push Button, to distinguish it from Radio Buttons and Checkboxes.  This is a subclass of TextView.  It gets placed in the onCreate method because the button must, in general, be ready to roll when the application launches.

Line [4] and [4a] are just about stock, that is, they look just about like every example I have seen.  With some exceptions.  The
"cannonical" example looks like this:

Button button = (Button)findViewById(R.id.button_id);    
        button.setOnClickListener(this);

 
The typical examples use the object types as the names of the instantiated objects.  I have found it instructive to use a different name, to make it obvious to me which is which.  So in the code I have created a button named 'buttoff', whose look-and-feel is defined in my layout XML as 'button1'.

findViewById is a method which returns the view created by the onCreate method which corresponds to the ID in it's argument list.  In other words, it put a handle to the Button view 'button1' into the view variable 'buttoff'.  And the next statement sets up a listener for this button.  Puzzle over this long enough and it almost makes sense.

O.K., that sentence reads like the kind of documentation IBM became famous for: Syntactically correct, semantically accurate, and totally void of any useful information. After talking with someone who understands this better than me, I will now offer the following account:

setOnClickListener is a method which takes an object as an argument.  The expected type of object is an activity.  'This' refers to the current activity.  So, it wants to 'wire' a listenter between the button and something which can handle clicks in the current activity.  And, the classic something for doing that is the onClick method.  And we give Android a clue by stating that our activity (RatCatActivity) is extending onClickListener.

Much easier in Javascript.  But then I've been doing this there a lot longer.   Rather than run on and on, I will pause here and continue tomorrow.

Sunday, August 26, 2012

Android Layout - Part II.

In Part I., I rambled through setting up a layout for the RatCat game.  And I ended with a note that the layout will not work well should the device be held in the landscape position.   Fortunately,   there is a good reference here on how to do this.

It appears that three things are necessary to handle rotation

  1. Create layouts that handle rotation.

  2. Set the rotation behavior in your AndroidManifest file.

  3. Handle rotation in your application code by saving state or caching data.

Let's start with the first one.  I am going to want two layouts: one for portrait and one for landscape.  It turns out that I have to put this landscape layout in a different folder: /res/layout-land

To rotate the screen in my emulator, I use ctrl-F11.  Some emulators use ctrl-F12.  Some use shift-F11.  Some don't work if one uses the right ctrl or shift key.  Ctrl-F11 works for me.

So, I end up with this:

    <TextView
        android:id="@+id/LineOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/TopLine"  [1]
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="15dp"
        android:text="1"                        [2]
        android:textColor="#FFFFFF"            
        android:textSize="36dp" />

    <TextView
        android:id="@+id/LineTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/TopLine" 
        android:layout_centerHorizontal="true"
        android:layout_alignLeft="@+id/TopLine" 
        android:layout_marginTop="10dp"
        android:text="@string/LineTwoTxt"
        android:textColor="#FFFFFF"
        android:textSize="30dp" />

    <EditText
        android:id="@+id/entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LineOne"     [3] 
        android:layout_toRightOf="@+id/LineTwo"  
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:ems="6" >
        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginRight="20dp"
        android:layout_below="@+id/entry"
        android:text="@string/Button" />


Notes:
[1]   The ToRightOf method puts the item to the right of TopLine on the same line.

[2]  Make a note of this:  when we shift orientation we reset the "Rat's" display value to '1'. Note that we do not change the internal value.  Which means, if the counter has gone up to 3 (so the Rat is showing 'RAT', and we rotate the device, the RAT is now showing '1', but the correct response is still '4'. 

[3]  We want this to be below Line One and to the right of Line Two.  One might expect that the ToRightOf method would do both.  It doesn't.

This post I actually proofread. And discovered that modern browsers + blogger have a terrible time trying to render the XML from an Android app. It seems that they don't know if it should be considered XHTML or XML, so they combine the worst features of each guess. I found the following problems:
The < and > symbols looked like some sort of a tag, so they and everything between them got stripped.
Trying to surround them with a <PRE> tag didn't work eitherl the browser thought that I had some kind of an XML document, and treated it accordingly.
So, what I finally did was to use the ampersand encoding for LT and GT to get my PRE and /PRE tags. I will be going back and fixing up part I of this.


The problem mentioned in note [2] will be discussed after  the Java code gets discussed, where it may actually make sense.

Friday, July 20, 2012

Android Layout - Pt. 1

So I've discovered that the first step in an Android project is to define the layout.  Which, compared to a web page, is about as difficult (or easy), it just has it different difficulties.

When one creates a project using Eclipse, Eclipse helpfully creates the beginning of a layout.  This layout  (I've starting talking like an Android developer; the term 'layout' is used whenever talking about the screen) looks like this:


    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

            android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

Time to try to translate this into something more familiar to a web developer who has minimal experience with Java.

Note that we start out with an xml declaration.  Much of what goes on in an Android application is done in xml. And this is know as 'the mail.xml' file, located in the /res folder.  Main.xml defines the ViewGroup used by the project. 

The ViewGroup contains View groups.  There are five different View groups, but the primary ones are 'Linear Layout' and 'Relative Layout'.  Linear Layout lays out the fields one to a line.  As one seldom wants to have all one's fields one to a line, left justified, there are techniques for doing positioning on a line.

However, if one wants to place multiple items on the same line, or line up items with other items, the way to go is with Relative Layout.  Which is exactly what I have done.

Rather than deconstruct what I came up with, here is my initial layout.  The numbers in square brackets refer to the following notes, and are NOT part of the xml:


    android:layout_width="fill_parent"
    android:layout_height="match_parent"            [1]
    android:background="#A0A000"                    [2]
    android:orientation="vertical" >                [3]

            android:id="@+id/TopLine"                   [4]
        android:layout_width="wrap_content"         [5]
        android:layout_height="wrap_content"
        android:text="@string/TopLineTxt"           [6]
        android:textColor="#FFFFFF"                 [7]
        android:layout_marginTop="20dp"             [8]
        android:layout_centerHorizontal="true"      [9]
        android:textSize="36dp" />

            android:id="@+id/LineOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"                            [10]
        android:textColor="#FFFFFF"
        android:layout_below="@id/TopLine"          [11]
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:textSize="36dp" />
   
                android:id="@+id/LineTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/LineTwoTxt"
        android:textColor="#FFFFFF"
        android:layout_below="@+id/LineOne"
        android:layout_marginTop="30dp"
        android:textSize="36dp"
        android:layout_centerHorizontal="true" />

            android:id="@+id/entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/LineTwo"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:ems="10" />                          [12]

   

Note that each item on the screen gets its own view definition.  Now to explain the meaning of those parameters, and try to justify the choices I made:

[1]  The Relative Layout item describes the properties of the screen as a whole.  From the XML point-of-view, it also functions as a container for the individual screen fields. In this case, the parent is the entire device, and I want to define via the layout_height and layout_width parameters that this Relative Layout is to fill up the screen.  Fill_parent and match_parent mean exactly the same thing (the original parameter was match_parent; it was renamed fill_parent in the API version 8), and it means, fill up all of the space of the parent (minus any specified padding).

[2]  We want to specifiy the background color, and this is done using the standard hex color codes.

[3]  This specifies that the device is in the vertical orientation.  More on this later.

[4]  As mentioned above, in Android-Talk, each field is called a view.  And each view (for that matter each object) can be given a name, or 'id'.  For a view, the syntax for specifying the name is  "@+id/idname".  Here, the idname is TopLine

[5] We are in the process of defining a Text View named TopLine.  The layout_width parameter specifies how wide the view will try to be.  Match_parent will make it try to be as wide as it's parent container.  Wrap_content will make it try to be just wide enough for whatever content is put inside of it.  Layout_height is similar.

[6]  An Android project can have another XML folder for the constants.  And if you try to use a literal for a string item, Eclipse will scream at you.  So, the text which this Text View is going to contain is defined in /res/strings.xml as the constant TopLineTxt.  Note that these are truely constants.  Should it become necessary to change the text contained in TopLine, one does NOT simply assign a diffferent string to TopLineTxt in the Java code.

[7]  And it is possible to define the color of this text.

[8]  I wanted to put some separation between the first line and this field.  Layout_marginTop specifies some extra space (here 20dp) on the top side of this view (field).  As to what a 'dp' may be:  According to http://developer.android.com/guide/topics/resources/more-resources.html#Dimension a 'dp' is a Density-Independent Pixel.  The idea is that on a 160 dpi screen 1dp = 1px (pixel).  On a screen with more pixels per inch, the number of physical pixels used to draw 1dp increases.  On screens with poorer resolution, the number decreases.  Google deprecates the use of px as a unit, prefering dp, which provides a painless way to make the image scale up or down depending on the device used.

[9]  Makes sure the text is centered in the field.

[10] Not every string on the screen must be defined in strings.xml.  As LineOne is going to constantly change, there is little to gain by defining its starting value in strings.xml, so it is simply entered as the constant "1".

[11]  This positions the top edge of the LineOne field (view) with the bottom edge of the TopLine field.  We are starting to exploit Relative Layout.

[12]  An EditText view is a box into which one can type some text.  Android:ems specifies how wide this box should be, in ems.  And one em is the width of the letter 'M' in the current font.

So, this a picture of what we have.  But there is a problem.  While this would work just fine on my Droid Pro, on a device with a soft keyboard, said keyboard will take up some of the space.  On my emulator, when the keyboard pops up, it hides the Submit button.  So, I need to alter the layout.  My plan is to reduce the line spacing, reduce the size of those lines, and move the button to the right of the text entry box.  The question is:  do I already know how to do all that?

The changes start out simple enough:



    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:background="#A0A000"
    android:orientation="vertical" >

            android:id="@+id/TopLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
/* Change from 20dp to 15dp  */
        android:text="@string/TopLineTxt"
        android:textColor="#FFFFFF"
        android:textSize="36dp" />

            android:id="@+id/LineOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/TopLine"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="1"
        android:textColor="#FFFFFF"
        android:textSize="30dp" />
/*  Change from 36 to 30dp */

            android:id="@+id/LineTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LineOne"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="@string/LineTwoTxt"
        android:textColor="#FFFFFF"
        android:textSize="30dp" />
/*  Change from 36 to 30dp */

With the EditText box, we have a problem.  We cannot leave it centered, as (a) there isn't enough room for the button to fit on the right of it,  and (b) that would be really ugly if it did work.  So, I'm going to allign it on the left margin.

Now Eclipse is supposed to have some drag-and-drop functionality for layout. And, if I was starting completely fresh, it just might work.  But, when I try to drag the text box to the margin, I can't get it where I want it.  My suspicion is that Eclipse is trying to retain my prior parameters and add what it hopes I want for new ones, and the combination does not make sense.  So, I have to finish the job by hand:

            android:id="@+id/entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LineTwo"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:ems="6" >
       
   

   

I did discover the tag in the process of trying to drag-and-drop.  It keeps the focus on the text box, which is something I want.

I have one last issue with my layout. I've been assuming the device has always been held in the portrait orientation.  And this game really needs a different layout if the device is held in the landscape orientation. So, next time we'll look at how to accomplish that.

Sunday, July 8, 2012

This isn't exactly (remotely?) Oracle. But it is related to FizzBuzz.
Here's the deal: Ever since I got my Droid Pro I've had this curiosity about what it would take to program something on it. And, the FizzBuzz puzzle inspired a simple (the kind word) game for it. Since I do not want to be known as a copycat, I decided to name my game 'RatCat'. Very simple game. I imagine the screen having a line reading:



The RAT Says:

Followed by a field which would start out at '1'
Beneath this, there should be a line reading:



But You Say:


Followed by a data entry box, and a button labeled "Submit".

Obviously (?), the player is supposed to respond '2', and the game responds 'RAT'. The successful player will then enter '4' and the game will respond 'CAT'. This back-and-forth continues until the number '50' ('CAT') is reached, which results in a 'You Win' being displayed. To my way of thinking, this is a much more interesting game than Angry Birds. And this game would actually be worth the price.

The first thing I discovered is that writing Android Apps requires a lot of software to be loaded.
In Order:

  1. Eclipse Classic for 64-bit Linux
  2. The Java SDK (I already had an JRE, but that isn't enough here
  3. The Android SDK
  4. The Android Development Toolset plugin for Eclipse
And that is just the beginning. The next steps are to use Eclipse to install an Android platform and create an Android Virtual Device. The steps are outlined in the "Hello World"tutorial , so I won't go into more detail here. Suffice it to say that the troubleshooting guides almost got me through it all.

The one exception was when I tried to compile using Eclipse. I had been doing testing with java from the command line, and I thought I had java installed just fine. But, when I tried to use Eclipse I found myself with some strange java errors. It turned out that I had GCJ installed as my "sort of" java. Getting a propper java installation fixed everything.

Friday, January 13, 2012

Desktop Games, Pt. III

I do hope to get back to discussing Oracle.  Unfortunately, I have been distracted by the end of the year.  More specifically, by a strong need to get my Federal Income Tax return filed as soon as possible.

Here's the problem:  The Fat Client version (there is a cloud version available) ofmy favorite tax preparation software (TaxAct) only comes in a Windows edition.  And, I no longer dual boot to Windows, and do not wish to start.  However, I have some old Windows licenses lying around which can potentially run in a VirtualBox environment.  So, installing VirtualBox rose to #1 on my priority list (and VirtualBox is now an Oracle Product, after all).

Here is where my recent experience sent me down the wrong path.  I didn't have VirtualBox installed on my new desktop.  And my first thought was to go to the Oracle site and download it, just as I had done with Java, Firefox, Eclipse, Android, etc.  And ... sitting there on the Oracle site, just ripe for the downloading was an OpenSUSE 11.4 rpm.  So, I downloaded it, installed it, and was rewarded by several screenfulls of error messages.  Based on my experience with Android, my instinct was to try to see what did get installed.  And, I discovered that I now had a startup menu item for VirtualBox, which started up just fine, and even allowed me to create a virtual machine.

What I didn't realize at the time was that there are two parts to a successful VirtualBox installation on Linux (and probably Windows as well).  One part is the installation of the VirtualBox manager.  What I had started was the GUI manager.  (There also is a command line UI, more about which later.)  The VirtualBox Manager allowed me to create a Virtual Machine quite easily, so easily, that nothing more need be said.  However, when I tried to start the machine and load an o/s, it failed miserably.

The other part to an installation is to add components to the Linux kernel which enable the actual emulation.  The prefered way is thru DKMS (Dynamic Kernel Modification System), which leaves the base kernel untouched.  But, OpenSUSE 11.4 does not support DKMS.  In which case, the installation script attempts to rebuild the kernel.  And my 11.4 installation did not contain the source files needed to rebuild the kernel.  Fortunately, the install log contained a helpful suggestion (set KERN_DIR=source directory).

So, I tried installing the source files, and wound up with a kernel which would not boot.  Fortunately, my original kernel was not removed, and I was able to investigate things in more detail.

What I found was that OpenSUSE did include all the needed VirtualBox packages.  Not for the most current version, but it include all the needed packages.  So, I started YAST, removed the package I had downloaded from Oracle, and installed what OpenSUSE distributed.  Then, I was able to create a VM and start loading Windows.  Which went smoothly, except for the following issues:

  1. To have proper access to the Optical Drive, I had to add my logon name to the cdrom group.  I was impressed with how easy YAST2 made this.
  2. The install kept looping.  It turns out there is a known bug in W2000 in the disk subsystem.  It is a race condition, which never shows up with physical components, but can happen with virtual ones.  The solution is to use the command line interface to add a delay to the disk system.  The command line interface looks interesting, and I may explore it some more at a later time.
  3. To get a decent sized screen I had to install what Oracle calls the 'Virtual Box Additions'.  And this time, my OpenSUSE distribution did not help me.  Fortunately, the GUI VirtualBox Manager offered to go out and attempt to download them for me.  Which worked fine.

So, now I am in the 21st Century with a Real VM on my desktop.