Showing posts with label Eclipse. Show all posts
Showing posts with label Eclipse. Show all posts

Saturday, May 24, 2014

Android BlackJack: Getting Individual Cards

Android BlackJack: Getting Individual Cards

Android BlackJack: Getting Individual Cards

Introduction

Previously code was added in to the MainActivity class to diplay the full Bitmap for the card pictures. Now we want to get at one of the individual cards in that Bitmap and display it. This will ultimately become the code needed to display an entire hand as the game progresses. The Bitmap class has some methods that are similar to what was used in regular Java. Let's adapt the classes used in the regular Java program to take advantage of the new Android classes and methods

CardImageFactory

CardImageFactory was responsible for getting individual card images out of the larger bitmap picture of an entire deck of cards. Under Android the Bitmap class is used to manipulate these pictures. Looking at the code for Bitmaps from the Android documentation site, the Bitmap class has methods similar to the ImageBuffer class in standard Java. If we rewrite CardImageFactory class to use the appropriate Android classes then the PlayingCard class can have a Bitmap based method to return the bitmap of the particular card we want displayed. The code is fairly straight forward and changes were made to the initCardImageFactory method and the makeCardIcon method.

CardImageFactory

public class CardImageFactory {
           private static final int SUIT_COUNT = 4;
           private static final int RANK_COUNT = 13;
           private  static Bitmap fullDeckImg = null;
           public static   int width = 0;
           public static   int height = 0;

            /**
            * Initialized the .png image in memory and sets up width and height 
            * readying size parameters to cut the image up into icons. This also
            * isolates IO exceptions to this method so the individual calls 
            * do not have to have exception handling.
            * 
            * @param pathToDeck the http address of the full card image file
            * @throws MalformedURLException
            * @throws IOException 
            */
           public static void initCardImageFactory(Resources res, int resId) {
              if (fullDeckImg == null) {
                  final BitmapFactory.Options options = new BitmapFactory.Options();
                  // options.inJustDecodeBounds = true;
                  fullDeckImg = BitmapFactory.decodeResource(res, resId, options);
                  height = options.outHeight;
                  width = options.outWidth;

                  // width = fullDeckImg.getWidth();
                  // height = fullDeckImg.getHeight();
              }
           }

           /**
            * For the structure of the current Black Jack program this returns 
            * individual card images instead of a full list. This allows you to 
            * develop a class hierarchy where the image is stored at the individual
            * PlayingCard object level.
            * 
            * @param rank card face value number 0 - 12
            * @param suit suits 0 - 4
            * @return 
            */
           public static Bitmap makeCardIcon(int rank, int suit) {
                    int x = (rank * width) / PlayingCard.RANK;
                    int y = (suit * height) / PlayingCard.SUIT;
                    int w = width / PlayingCard.RANK;
                    int h = height / PlayingCard.SUIT;
                    //return fullDeckImg.getSubimage(x, y, w, h);
//                  BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h)
                    return Bitmap.createBitmap(fullDeckImg, x, y, w, h);
           } 

}

Similar to our previous use of the Android Bitmap routines (used to display a full deck of cards) there needs to be a 'Resources' instance passed in. There also needs to be the resource ID of the main bitmap that contains the pictures of each of the cards. Since there isn't any resizing of the Bitmap going on (just a piece of the bitmap is needed) we don't set the 'inJustDecodeBounds' option. BitmapFactory.decodeResource(res, resId) pulls in the full Bitmap. This gets stored under the static field fullDeckImg. The options field get populated with the width and the height of the full bitmap. These are stored in the CardImageFactory class for later use.

Now most of the code for the makeCardIcon method can be used the same way as in standard Java. Just calculate the starting pixel address and the length and width of the individual card and use the Bitmap.createBitmap method to generate a Bitmap of the individual card.

PlayingCard

The PlayingCard class is where the actual display method is located. It is at the level of this class that we have access to the data need to calculate the card suit and face value. The getCardBitmap method is all that was added. The display card back methods have been commented out as they still have the standard Java way of doing things. This will need to be fixed when we are ready to display a real game.

public class PlayingCard {
    public static final int RANK=13;
    public static final int SUIT=4;
    private int cardno;
    private int score = 0;
    private boolean diplayBack = false;

    private String faceVal = "A23456789TJQK";
    private String suit = "CSHD";

    public PlayingCard(int cardno, int score)
    {
        this.cardno = cardno;
        this.score = score;
        this.diplayBack = false;
       // this.setIcon(CardImageFactory.makeCardIcon(cardno%RANK, cardno%SUIT));
    }

    /**
     * Get the card scoring value for blackjack face cards = 10 ace = 11 
     * all other cards equal their face value. Aces can equal 1 at times and 
     * is handled elsewhere
     * @return 
     */
    public int card_value()
    {
        return this.score;
    }

    /**
     * convert cardno into text string of face value and suit
     * @return 
     */
    public String getCardText() {
        int card_val = this.cardno % 13;
        int card_suit = this.cardno % 4;
        return this.faceVal.substring(card_val, card_val + 1)
                + this.suit.substring(card_suit, card_suit + 1);
    }

    public boolean getDisplayBack() {
        return this.diplayBack;
    }

    public void setDisplayBack(boolean disp) {
        this.diplayBack = disp;
/*        if (this.diplayBack) {
            this.setIcon(new ImageIcon(System.getProperty("user.home")+"/Downloads/classic-cards/b1fv.png"));
        }
        else {
            this.setIcon(CardImageFactory.makeCardIcon(cardno%RANK, cardno%SUIT));
        }
        */
    }

    public Bitmap getCardBitmap() {
        return CardImageFactory.makeCardIcon(cardno%RANK, cardno%SUIT);
    }
}

Lifecycle issues

There is more to the Activity life cycle than just the onCreate method (more details here1,2). The onCreate happens before all the resources are created for the main resource object R. Luckily there is an onStart() method. Overriding this method in MainActivity allows the new graphic elements (the card pictures) to be displayed properly on the very first screen the user will see.

I moved the setup of the dealer and player hands into the onStart routine and added code to initialize getting the full card bitmap. I also added the display of the full deck into this method. Now the deck will be displayed when the program starts instead of having to see the little green robot.

onStart method and onCreate changes

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
                getFragmentManager().beginTransaction()
                                .add(R.id.container, new PlaceholderFragment()).commit();
        }
}

@Override
protected void onStart() {
        super.onStart();
this.strategy = new BlackJackStrategy();
this.card = new CardDeck(this.strategy);
// Before adding graphic elements shuffle the deck of cards
this.card.shuffle();

ImageView mImageView1 = (ImageView)findViewById(R.id.imageView1);

mImageView1.setImageBitmap(
            decodeSampledBitmapFromResource(getResources(), R.raw.classic_playing_cards, 100, 100));
CardImageFactory.initCardImageFactory(getResources(), R.raw.classic_playing_cards);

}

Display a Card in the onGo Method

ImageView is the easiest way to get a picture placed on the tablet screen. As with previous additions to the display just use the graphical placement tool under Eclipse under the Fragment.xml file. The ImageView instances placed under the dealer and player hands display their text. These ImageView object were set initially to display the little green robot.

Screen additions

onGo Method changes

Now the onGo method needs to add in code to access the 2 new ImageView objects placed on the screen. Then once the objects have been initialized they can be made to receive the individual card Bitmap. The following are the changes made to the onGo method to display a card from each hand. In this case the second card of the hand.

    public void onGo(View view) {
        TextView mPlayer = (TextView)findViewById(R.id.textView6);
        TextView mDealer = (TextView)findViewById(R.id.textView5);
        EditText mBet = (EditText)findViewById(R.id.editText1);
        EditText mBkroll = (EditText)findViewById(R.id.editText2);
//      ImageView mImageView = new ImageView(this.getBaseContext());
//        ImageView mImageView1 = (ImageView)findViewById(R.id.imageView1);
        ImageView mImageView2 = (ImageView)findViewById(R.id.imageView2);
        ImageView mImageView3 = (ImageView)findViewById(R.id.imageView3);

//        mImageView1.setImageBitmap(
//                  decodeSampledBitmapFromResource(getResources(), R.raw.classic_playing_cards, 100, 100));
//        CardImageFactory.initCardImageFactory(getResources(), R.raw.classic_playing_cards);

        // Get bet and bankroll from the EditText widgets
        this.bet = Integer.parseInt(mBet.getText().toString());
        this.bankroll = Integer.parseInt(mBkroll.getText().toString());

        player = new Hand("Player");
        dealer = new Hand("Dealer");

        // Deal cards
        player.deal(this.card);
        dealer.dealHoleCard(this.card);
        player.deal(this.card);
        dealer.deal(this.card);

        // Need a clear display because display appends
        player.display(mPlayer);
        dealer.display(mDealer);
        mImageView2.setImageBitmap(dealer.cards.get(1).getCardBitmap());
        mImageView3.setImageBitmap(player.cards.get(1).getCardBitmap());
    }

Screen Before onGo Executed

Screen After onGo Executed

Clicking the 'New' button causes the onGo method to be executed. If the changes were made correctly this is what you should see (the individual cards may differ secondary to the differences in the underlying random number generator).

Conclusion

There it is individual cards can now be displayed. In the next incantation of this program the following enhancements will be made:

  • Change the display so that the dealer and player hands can take up the whole width of the screen if necessary
  • Get rid of the display of the whole deck. It was just there as an experiment to learn how to setup a Bitmap for display
  • Add in display of the back of the card for the hole card of the dealer
  • Figure out how to erase the cards from the screen in preparation for a new game.
  • Package up for deployment on an actual android device

Author: Nasty Old Dog

Validate XHTML 1.0

Thursday, May 15, 2014

Android Development

Android Development

Android Development

Introduction

It's been a while since anything productive has been done on this blog. Previously published articles went over AP computer science and then developed a Blackjack game to show how beginning computer science skills can be used to create a useful program. The new realm of programming has become the hand-held devices. There are 2 flavors Apple IOS and Google Android. If you have been following along in this Blog you know that Java has been studied in depth. The next logical step would be to investigate how to program in the new realm. Logically it would be nice to start with a platform that uses Java as the basis for application development. This forces the investigation down the Android path. Andriod is Java based while Apple IOS uses Objective-C.

Eclipse over Netbeans

For this project I have chosen Eclipse as the IDE. There are plugins for Netbeans but I don't want to favor one IDE over another. That's ultimately for the user to decide. I use both they both get the job done. They are both free so what's the big deal? Have both on your machine use whichever one you like best. For this project I installed the latest Eclipse Kepler. I then downloaded and installed the latest Android plugin for Eclipse. All of this development is being done on a Mac Book Pro with Java 7.

Android development is complex

Android runs on a small tablet computer but the complexity is anything but small. As a user you tend to think of an andriod app as a single unit, after all it all starts by tapping a tiny icon on the screen. But then android's complex Framework takes over. Android supports different handheld devices from phones to full size tablets. Android is also multicultural it tries to separate out human language strings into a separate area so that a program can be easily modified for use in another country. To facilitate these features Google has added a level of complexity to development. It's a bit daunting at first but as you become familiar with where things go you begin to see the logic behind it.

Android already has some tutorials

Android provides a large amount of tutorials. "Building your first App" should be glanced over (https://developer.android.com/training/index.html). The important point here is that you will need to download the Android SDK. Then install the Android plug-in for Eclipse. Once you have accomplished this, you're ready for that famous starting point of all software development.

Hello World

There was a time when you logged into your computer open a file and after typing in a few lines of code you saw Hello World typed back at you. Under andriod you need multiple files and a large directory structure to accomplish the same feat. Under Android there isn't a lot of typing but you get a huge project directory and multiple files just to accomplish the same thing.

  • TO Create the Hello World program under android:
    • File>New>Other>Android Application Project
  • This brings up the following dialog:

  • Type in your application name (change the package if you want).
  • Change the minimum SDK to be the latest SDK
  • Hit Next>Next>Next>Next>Finish

At this point you may or may not have some small issues. Try one or all of the following

  • Right click on the project and choose Android Tools>Fix Project Properties
  • Right click and refresh the project
  • In the project menu do a "clean" on the project

After one or more of these your project should be able to run in the emulator. I named my project BlackJack which is probably not the best name since the name is already taken in Google's Play Store. But for our purposes who cares we can rename it if it ever becomes of commercial value. The following screen shot is what you should get if you set up your project correctly:

Run your android app in the simulator

Just right click (Ctrl-click on Mac) on the top level of your project and select "Run As">"Android Application" You may need to run this twice. Once to start up the simulator and once to load and run your program.

Intel Hardware Accelerator

If you get a message that HAX is not working you need to go get the fix from intel for their hardware accelerator (see reference 1). The link is at: intel HAX After you install this the execution on a Mac should be smooth. Working like the tablet itself.

For the project created so far this is what you should see in the emulator:

Conclusion

There is a lot of configuration with this project that I assumed the average user should be able to work out for themselves. This Hello World version of BlackJack will be the scaffold for which we will start to piecemeal add the functions of BlackJack from the previous projects.

Author: Nasty Old Dog

Validate XHTML 1.0