Showing posts with label array. Show all posts
Showing posts with label array. Show all posts

Tuesday, February 6, 2018

Simple Statistics and the R Language

Statistics and the R Language

Statistics and the R Language

Introduction

Statistics plays such an important role in so many different fields that a large portion of College students will find themselves having to take a Statistics course. That course will generally involve learning how to use a statistics package. At the tail end of the second decade of the 21st Century that package will likely be the R language. As a new student to Statistics you aren't privy to the steps leading up to the R language. You didn't have to live throught the use of hand written routines to calculate out the statistical functions on a computer. You didn't have to live through the days of using a hand calculator with statistical function keys. You don't need to wade through statistical function tables in the appendix of a book to calculate your statistical distribution functions. At the same time though you become detatched with the actual mathematics that is statistics. The pre-packaged functions of the R statistical library hides all that hard work from you.

My introduction to statistics happened rather late in my life in the first decade of the 21st century in the Harvard extension Biostatistics class. At that time there were various statistics packages that cost a considerable amount of money to purchase (luckily there were educational discounts). The book used for the course provided different examples of solutions in a couple of different statistical packages but centered around one called Stata. By seeing the same problem solved with different package side by side, the actual mathematics of statistics became the basis for understanding the idiosyncracies between the statistics packages. This maintained a link between the mathematical representation of the statistics formulas and their use in the statistics software.

With R being the popular statistics language there is less of a tendency to dive back into the mathematical formulas and you may lose some understanding of the mathematics in the process. This blog post is meant to be an elementary bridge between some of the simple formulas of statistical mathematics and their R built-in counter parts. To do this I am going to use (actually rely on heavily for example data and answers) a paper of Dr. Keith Smillie at the University of Alberta. He produced a wonderful Statistics package for the J language and summarizes it in the paper "J Companion for Statistical Calculations"[1]. I am going to transpose some of that into R covering a subset of his implementation. Hopefully you will be able to then use that format to extrapolate the mathematical connections for subjects I haven't covered here. Use this type of framework to help you gain more understanding of the theory and implementation of statistics.

R is an Array Language

R uses Vectors or Arrays as a built-in element of it's language. If you aren't used to array languages it can seem pretty strange at first, but once you get the hang of it it's pretty cool. You do have to think in terms of operating on the whole vector. That's because R has functions that streamline vector operations. You are welcome to breakdown those operations so they look like a regular programming language, but that may slow down processing time when dealing with large amounts of data.

R is an interpreted language

This just means that R grabs your R code and tries to execute it as soon as you type it in and hit the enter key. You can also save code in a file and load it into the R console environment. But you can do quite a bit at the command prompt in the R Console. Look at the following R Console Session. The session uses the comments operator '#' to add commentary in line. The comment operator '#' is usually called the 'hash' sign (you might know it as the number sign). When R sees the hash sign it will ignore the sign and everything else to the end of the line. Anything that preceeds the hash will be executed as R code.

> # The hash comments out the rest of the line in R
> 2.3 # entering a numeric constant R returns it as a vector of one value
[1] 2.3
> # Assignment using the back arrow operator <-
> w <- 2.3 # assigning 2.3 to the variable w
> w 
[1] 2.3
> # add 2 numeric constants
> 2.3 + 2
[1] 4.3
> # you can use the = sign for assignment as well
> w = 3
> w 
[1] 3
> # see we have changed w from 2.3 to 3

Creating vectors(array or list if you prefer) of more than 1 value

You create vectors or lists by Concatenating (or Combining) values together. R has a c() function for doing just that.

> w <- c(2.3,5,3.5,6)  # w will now have multiple values in it
> # display w by typing it in at the command prompt
> w
[1] 2.3 5.0 3.5 6.0
> 

Arithmetic Mean

This is what is commonly known as the average of a list of values. We calculate it by taking a list of numbers, suming them and dividing by how many numbers are in the list

\[w = {2.3,5,3.5,6} \] \[n = 4 \]

Doing this by hand you compute the mean using the following formula: \[mean = \frac{\displaystyle\sum_{i=1}^{n}w_{i}}{n}\]

so

2.3 + 5 is 7.3
7.3 + 3.5 is 10.8
10.8 + 6 is 16.8

divide 16.8 by the total number of values (4): 16.8/4 is 4.2

How do we accomplish this in R? There are 3 categories of solutions:

  • The first is the old fashioned way: Loop through the values of interest that we stored in w, accumulate the sum of those numbers then after the looping is finished divide by the number of values.
  • The second is the vector way: use R vector operations to operate on the whole group of values
  • The third is to use an R built-in function to calculate in one step

Traditional looping average calculation

Lets create a function myave that does it the first way.

myave <- function (values_vector) {
 sum = 0
 for (i in 1:length(values_vector)) {
  sum = sum + values_vector[i]
 }
 # i should be the value of the last index and therefore the number of values
 sum/i
}

In the R console you will need to open the source editor by clicking the blank page icon in the tool bar at the top of the console. Save the above text into the editor window. Then click the 'source .r' icon and type in the name of your script.

> source("/Users/Nasty/Downloads/LearnBayes/R/myave.R") # where my file ended up
> myave
function (values_vector) {
 sum = 0
 for (i in 1:length(values_vector)) {
  sum = sum + values_vector[i]
 }
 # i should be the value of the last index and therefore the number of values
 sum/i
}
> # myave has a value of the function code so you can see it as above
> # Now lets use it create the vector of values
> w = c(2.3,5,3.5,6)
> w
[1] 2.3 5.0 3.5 6.0
> # plug it into myave
> myave(w)
[1] 4.2

A more vector way to calculate

> sum(w)
[1] 16.8
> sum(w)/length(w)
[1] 4.2
> 

This is pretty simple and to reduce typing you could create an R function to do it. You don't need the editor since it's a one-liner.

>  myave1 <- function(values) {sum(values)/length(values)}
> myave1
function(values) {sum(values)/length(values)}
> myave1(w)
[1] 4.2
> 

R built-in method

Now R being a statistics package it must have a predefined function that will do this. It does have something called 'ave'. But it has a wierd idiosyncracy that the above functions don't share. Let's try it.

> ave(w)
[1] 4.2 4.2 4.2 4.2

It turns out that the 'ave' function runs the average on subsets of our values. So it produces a vector of averages. Not quite what we wanted right now. So guess at a function name at your own risk. In the computer world there is an old acronym RTFM. Which in nice language stands for Read the Stinking Manual. So try to look up what you want to do (Google is your friend here).

So the built-in function we really want to use is 'mean'

> mean(w)
[1] 4.2

Now mean has other parameters that you can use that have default values. So for our usage it works with the default values. Depending on how in depth your statistics course is you may discover them. If you're interested check https://www.rdocumentation.org/packages/base/versions/3.4.3/topics/mean

Frequencies

It's helpful to look at frequencies of occurances many times when analyzing data. So how would we use R vector operations to build a list of frequencies. The key is to know the complete range of values that the random process we are looking at can take on. This is because in a small sample some of the values may not show up and the number of occurances will be 0. To compare all the values of one vector with all the values of a second vector we use a function known as 'outer product'. Outer product will take an operator and execute it between values of the 2 vectors. R has an outer product built-in function called 'outer'. It takes 3 parameters, 2 vectors and an operator symbol. It then does all the heavy lifting of applying the operator between each element of vector1 to each element of vector2. This will produce a table of calculations. In our case using equality operator '==' we obtain a matrix of truth values.

> # frequencies from a list of die rolls stored in a vector
> D = c(4,5,1,4,3,6,5,4,6,4,6,1)
> D
 [1] 4 5 1 4 3 6 5 4 6 4 6 1
> # range of values of a single die
> r = c(1:6)
> r
[1] 1 2 3 4 5 6
> # use the outer product function 'outer' to create a table of what in D == values in r
> outer(r,D,"==")
      [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9] [,10] [,11] [,12]
[1,] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
[2,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[3,] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[4,]  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE
[5,] FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
[6,] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE
> # these are all logical values that we want to sum to create frequencies
> # if we multiply by 1 R will convert these to numeric values for us
> 1*outer(r,D,"==")
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,]    0    0    1    0    0    0    0    0    0     0     0     1
[2,]    0    0    0    0    0    0    0    0    0     0     0     0
[3,]    0    0    0    0    1    0    0    0    0     0     0     0
[4,]    1    0    0    1    0    0    0    1    0     1     0     0
[5,]    0    1    0    0    0    0    1    0    0     0     0     0
[6,]    0    0    0    0    0    1    0    0    1     0     1     0
> # sum the rows of the equality table to obtain the frequencies
> # there happens to be a function called 'rowSums' that will do just that
> rowSums(1*outer(r,D,"=="))
[1] 2 0 1 4 2 3
> 

Next we combine the range values with their respective frequencies into a table.

> # lets assign the frequencies to a variable f
> f = rowSums(1*outer(r,D,"=="))
> f
[1] 2 0 1 4 2 3
> # Now lets combine the range of values with their frequencies
> matrix(c(r,f),length(f),2)
     [,1] [,2]
[1,]    1    2
[2,]    2    0
[3,]    3    1
[4,]    4    4
[5,]    5    2
[6,]    6    3
> # to see them in horizontal representation use the matrix transpose function 't'
> t(matrix(c(r,f),length(f),2))
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    2    3    4    5    6
[2,]    2    0    1    4    2    3
> # R has a 'barplot' function to make a nice graph of the frequencies
> # however it's not quite smart enough to break up our matrix representation
> # so we will go back to using r and f vectors
> barplot(f)
>

> # Not very informative if you look up the function we can add some parameters
> # to name the bars and place labels and a title
> barplot(f,names.arg = r,main="Die Roll Frequencies",xlab="Die values",ylab="Occurances")
> 

Now R has a function built in to create a frequency table. It's called 'table'

> table(D)
D
1 3 4 5 6 
2 1 4 2 3 
> 

It doesn't quite provide the same thing we calculated. This is the distinct frequency list. Remember the 2 value of the die had no rolls in our list. So 'table' doesn't include it.

Median and Quartiles

Median is the "middle" observation when you look at a set of sorted data. So rather than being a complex formula this is more of a positional definition. Sometimes it actually is in the exact middle (which happens for an odd number of items) for example: 3 4 5 6 7 then 5 is the median and the actual middle number. But if you had: 4 5 6 7, there is no actual middle number. In this case 5.5 would be condidered the median. To find the median in R we would perform the following vector operations:

  • sort the data into a new sorted vector
  • find the index of the middle number (if there are a odd number of values) or find the middle 2 numbers (if an even number of values)
  • return the number found or calculated above.

Median for even length vector

> # Median by hand
> # sample data:
> M = c(22, 14, 32, 30, 19, 16, 28, 21, 25, 31)
> M
 [1] 22 14 32 30 19 16 28 21 25 31
> # need to sort the data. we will cheat and use the sort function in R rather than 
> # doing it by hand
> sM = sort(M)
> sM
 [1] 14 16 19 21 22 25 28 30 31 32
> length(sM)
[1] 10
> # length is even so we divide length by 2 and get the value at the calculated index
> # and we need the value at the calculated index + 1 as well
> midx = length(sM)/2
> midx
[1] 5
> midx+1
[1] 6
> # so jumping ahead a couple of steps and putting all together
> (sM[midx]+sM[midx+1])/2
[1] 23.5
> # Thats the median that lies between the 2 values
> sM[midx]
[1] 22
> # and
> sM[midx+1]
[1] 25
> 

Median for odd length vector

> # lets add a value to our even vector to make the length odd
> M1 = c(M,40)
> M1
 [1] 22 14 32 30 19 16 28 21 25 31 40
> # formula for the index of odd length
> m1idx = (length(M1)+1)/2
> m1idx
[1] 6
> # we still need to sort before we find the median
> sM1 = sort(M1)
> sM1
 [1] 14 16 19 21 22 25 28 30 31 32 40
> # just select the median value at m1idx now
> sM1[m1idx]
[1] 25
>

Package it into an R script/function

mymedian <- function(myvector) {
# we will need to sort the vector for both cases
# let's do that now
 sM = sort(myvector)
 if (0 == length(myvector)%%2) {
  # even length code
  midx = length(sM)/2
  z = (sM[midx]+sM[midx+1])/2
 } else {
  # odd length code
  midx = (length(sM)+1)/2
  z = sM[midx]
 }
 z
}

Now test the function on the 2 data sets and compare mymedian against R's median function

> # Test out mymedian and R's median function
> # first what were the data sets?
> M
 [1] 22 14 32 30 19 16 28 21 25 31
> M1
 [1] 22 14 32 30 19 16 28 21 25 31 40
> # source the mymedian function
> source("/Users/Nasty/Downloads/LearnBayes/R/mymedian.R")
> mymedian
function(myvector) {
# we will need to sort the vector for both cases
# let's do that now
 sM = sort(myvector)
 if (0 == length(myvector)%%2) {
  # even length code
  midx = length(sM)/2
  z = (sM[midx]+sM[midx+1])/2
 } else {
  # odd length code
  midx = (length(sM)+1)/2
  z = sM[midx]
 }
 z
}
> mymedian(M)
[1] 23.5
> mymedian(M1)
[1] 25
> # what about R's built in median function
> median(M)
[1] 23.5
> median(M1)
[1] 25
> 

For any statistical definition, you could code it your self using R. But R was built with statistics in mind. Someone has probably already beat you to it. This means that there is probably a built-in function or a library function that already has that functionality. However, by going from a statistics book that gives you a mathematical definition and using the R function you lose the transition from mathematics into implementation that would seal in the math stuff in your mind. Your professor is going to expect that you know the theoretical math to some extent so don't overlook it. If your having trouble understanding just what the math is driving at try to implement it (if you have the time). Your text should have some simple examples with data you can test with. You won't have to do it every time and you can always google an implementation and just read it to see what it would look like. It may give you some understanding of what the text book is trying to define mathematically.

Quartiles

> # Quartiles are the numbers that mark the boundries such that
> # one quarter of the data lies between any consequtive quartile number
> # the easiest quartile to find is quartile 2. It's just the median
> Q2 = median
> # Q1 is the median of all numbers less than the value found by Q2
> Q1 <- function (myvec){median(myvec[which(Q2(myvec)>myvec)])}
> # lets set up some test data
> u = c(22,14,32,30,19,16,28,21,25,31)
> Q2(u)
[1] 23.5
> Q1(u)
[1] 19
> # Q3 is the median of all numbers greater than Q2 (ie. the median)
> Q3 <- function (myvec){median(myvec[which(Q2(myvec)<myvec)])}
> Q3(u)
[1] 30
> 

five-statistic

This is a summary of the data producing the following values:

min,Q1,Q2,Q3,max

> # five-statistic definition
> five <- function(myvec){c(min(myvec),Q1(myvec),Q2(myvec),Q3(myvec),max(myvec))}
> five(u)
[1] 14.0 19.0 23.5 30.0 32.0
> 

Mode

One thing that R does not provide a built-in for is the statistical mode. This is defined as the most frequently occuring data value in your vector of data. So this one we have to define. If I follow Prof. Smillie's example for J but use R equivalents this is what the code will look like.

# return the indexes of the most frequent values
# the %in% tests membership and produces a vector of truth values
# which converts the TRUEs to their indexes
# imx - short for indexes of maximum value of a vector
imx <- function(myvec){which(myvec %in% max(myvec))}

# ufrq - returns a frequency list of all accounted for values.
# values in the domain that don't appear are not accounted for
# ufrq short for unique values frequencies
ufrq <- function(myvec){rowSums(selfclassify(myvec))}

# simpleMode - the simple most frequent value (statistical mode) in a vector list
# it relies on the fact that ufrq will produce frequencies in the order that 
# unique returns the uniques members of the data
simpleMode <- function(myvec){unique(myvec)[imx(ufrq(myvec))]}
> source("/Users/Nasty/Downloads/LearnBayes/R/simpleMode.R")
> imx
function(myvec){which(myvec %in% max(myvec))}
> ufrq
function(myvec){rowSums(selfclassify(myvec))}
> simpleMode
function(myvec){unique(myvec)[imx(ufrq(myvec))]}
> D
 [1] 4 5 1 4 3 6 5 4 6 4 6 1
> simpleMode(D)
[1] 4
> simpleMode(c(1,2,3,2,3,2,3,4))
[1] 2 3
> simpleMode(c(1,2,3,4))
[1] 1 2 3 4
> 

Variance

This is a measure of how close each element of a data set is to the mean of the data set. This involves summing the squares of the differences between the value and the mean. Some people have trouble with this because it introduces squaring. When logically if you wanted to find out how far a value is from the mean you would just subtract the smaller number from the larger number from each other and get your answer. So a naive set of steps might look like the following R-like pseudo code:

m = mean(values)
for (i=1:length(values)) {
 if (m > values[i]) {
  diff[i] = m - values[i]
 }
 else {
  diff[i] = values[i] - m 
 }
}
diff

Now you could fix that up and get the values for the distance from each mean but we don't have a very sussinct mathematical formula. So the mathematical way of doing this without all the if statements is the following:

  • for each i={1..N} valuesi - mean
  • now that will give some negative numbers so one mathematical way of getting rid of negatives is to square the numbers.
  • for each i={1..N} (valuesi - mean)2
  • This formula will give all positive numbers that will be related to the actual distance.
  • but having separate distance related numbers doesn't tell us much so one thing you could do is sum all the squared distances up and divide by the number of values. In essence take the mean of the squared distances.
  • Divide by N or N-1. What's up with that?
    • Population - this is the total universe of everybody or everthing you want to study. Now you may have data on every single subject of interest. In this case you would be dividing by N.
    • Sample - This is where you look at a few or some number less than the number of things in the population (ie. you 'sample' the population). Since you sample you could have been unlucky and chosen things that were very similar with very similar data. This means there is still larger variation in the population. To account for that in the variance you use N-1 to divide. This enlarges the variance but as your sample size approaches the population size the difference in dividing by N or N-1 is negligible. = for example: (N=2) 1/2 = 0.5 and 1/3=0.33 the difference is 0.17 = But: (N=100) 1/99 = 0.0101 1/100 = 0.01 the difference is 0.001 = Makes sense naively you would think the more samples you have the higher the accuracy. This is just a mathematical way to express it.
> # the built in variance calculation
> # remember the w data from before?
> w
[1] 2.3 5.0 3.5 6.0
> mean(w)
[1] 4.2
> w - mean(w)
[1] -1.9  0.8 -0.7  1.8
> (w - mean(w))^2
[1] 3.61 0.64 0.49 3.24
> sum((w - mean(w))^2)
[1] 7.98
> sum((w - mean(w))^2)/(length(w)-1)
[1] 2.66
> # or using the built-in var function in r
> var(w)
[1] 2.66
> 

Standard Deviation

variance is useful for a variety of things that you may go into in your course. But you are probably thinking if I just took the absolute value of my numbers I would have a more exact representation of the distance each value is from the mean. You would be correct but the accepted mathematical way to do this is to take the square root of the variance instead and call it Standard Deviation.

> var(w)^0.5   # you should remember that square root is the same as taking to the 1/2 power
[1] 1.630951
> sqrt(var(w)) # in case you didn't believe me
[1] 1.630951
> sd(w)
[1] 1.630951
>

Create a Statistics Summary

let's put this all together and create a statistics summary. Essentially this is a report or table of everything we have just covered.

ssummary <- function(myvec){
 cat("Sample size\t\t\t",length(D),"\n")
 cat("Minimun\t\t\t\t",min(D),"\n")
 cat("Maximum\t\t\t\t",max(D),"\n")
 cat("Arithmetic mean\t\t",mean(D),"\n")
 cat("Variance\t\t\t\t",var(D),"\n")
 cat("Standard deviation\t",sd(D),"\n")
 cat("First Quartile\t\t",Q1(D),"\n")
 cat("Median\t\t\t\t",median(D),"\n")
 cat("Third Quartile\t\t",Q3(D),"\n")
}

So lets use it in R

> # using summary on our dice data variable D
> D
 [1] 4 5 1 4 3 6 5 4 6 4 6 1
> ssummary(D)
Sample size          12 
Minimun    1 
Maximum    6 
Arithmetic mean   4.083333 
Variance   2.992424 
Standard deviation  1.729862 
First Quartile   1 
Median    4 
Third Quartile   6 
> 

Now if you want something more fancy, there are ways to export this stuff to latex or HTML, rather than just printing to the screen within the R console. That is for you to look up and figure out. By the way R has a built-in 'summary' function:

> summary(D)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   3.750   4.000   4.083   5.250   6.000 
>

Conclusion

There is much more in the main reference for statistics and it's implementation in J in Dr. Smillie's paper.

Bibliography

  1. Smillie, K. (1999, January). J Companion for Statistical Calculations. Retrieved February 05, 2018, from https://webdocs.cs.ualberta.ca/~smillie

Author: NASTY OLD DOG

Validate

Sunday, April 28, 2013

AP Computer Science Study Guide as Computer Program Take 2

AP Computer Science Study Guide Take 2 <![CDATA[/*>

AP Computer Science Study Guide Take 2

Introduction

This guide was started in a previous article with comments for language elements an AP Student should know and be able to give a code example. This incantation of the same topic fills in most of the blanks with coding examples. If you were a good student you should be able to compare yours to mine. If you are a lazy student (meaning you didn't try to add any of your own code to the study guide) you better look through the code examples carefully and make sure they look familiar to you.
How to use this guide:
  • Pull the code into your IDE in its own project and run the program.
  • Generate the javadoc for the project. There should be a menu command to do it. In netbeans in was found in the run menu. For eclipse users if you can't find a quick web search should give you an answer.
  • Read through the code. The comments tell the story of what is going on.
  • Print out
    • the JavaDoc
    • the code
    • the output
  • Place them side by side on a large table and look through line by line and find where things are happening and why.

Things to look for

Different Types of Java Comments

The AP overview indicates you should be aware of the various types of comments. The most complex is the Javadoc style block comment. It contains @param and @return metafunctions in them. These comments start with /** and have *'s beginning each line with a terminating */ (on the last line). If they occur just before a method or class declaration the text within the comment will appear in the generated Javadoc. There are 2 other forms of comments one the // is used extensively in the APSubset code. The regular block comment /* . . . */ is shown only once.
The reason to point this out to you is that large portions of the code have to be used to engage the Java comments in an insignificant way. Where most of the java code examples can be accomplished with a few lines of code and a few output statements.

Method overloading

This functionality is spread in 2 different sections of code. The reverse method is defined twice. Once for Strings and then for integers. It is then used in the main method showing how the call signatures are the same and only the parameters change.

Exceptions

This could almost be done within the main method alone except that you also need to know about throwing an Exception. For this I created a small method that looks at its 'int' input parameter and throws an Exception if the parameter is the 'int' 3. Otherwise it just prints some diagnostic text to let you know it was called. The AP document was not too specific about which 'Exception's you should know about. I picked 3 that I thought you may have come across already in your projects. The fourth 'Exception' used is the parent class for Exceptions. Using this class is a useful way to catch Exceptions when your not sure which ones are likely to be thrown.
The reason for try-catch-finally and 'Exceptions' are to allow a program to either die gracefully or recover from an error. They are used extensively in large programming projects and Java does a nice job of integrating them in a modular way.
The 'finally' clause is run after every exception 'catch' clause has completed. In the code set up in APSubset the try catch block is run in a loop. The loop is set up to simulate a different error during each iteration. In a more robust program the try-catch block may be around your entire code. Remember most of the time Exceptions are things to avoid in the design of your code. You put them in because you may not be aware of every error scenario that could occur. In a small example such as this I had to force things to happen in a very small space. The idea behind 'finally' is that it gives you a guarenteed exit point from any Exception. A place where you can reset things or decide that the error involved was too grave and you must terminate the program. It's a place where common error handling or recovery can be done.
In the exception code there is a line commented out. It does a divide by zero but it is outside the try-catch block. Uncomment it in the IDE and run the code. You should find that the program will terminate there and no other statements past that point will be executed. Now compare that with the way the zero divide works inside the try-catch block. That should give you an idea of the utility of the Exception handling facilities in Java.

APSubset.java

The code is 600+ lines of code so rather than place it in the text of the article I have made it into a downloadable file. Go ahead and download it and run it yourself in your own Java IDE.
APSubset.java

Output (Run from Netbeans IDE)

run:
APSubset: BASIC TYPES
APSubset: int a = 0
APSubset: double b = 0.0
APSubset: boolean c = false
APSubset: 

APSubset: BASIC OPERATORS
APSubset: int a = 1 + 2 = 3
APSubset: double b = 2.0 + 3.5 = 5.5
APSubset: int a = 2 - 3 = -1
APSubset: double b = 2.0 - 3.5 = -1.5
APSubset: int a = 2 * 3 = 6
APSubset: double b = 2.0 * 3.5 = 7.0
APSubset: int a = 3 / 2 = 1
APSubset: double b = 3.5 / 2.0 = 1.75
APSubset: int a = 17 % 5 = 2
APSubset: double b = 17.0 % 6.0 = 5.0
APSubset: 

APSubset: Pre/Post-increment and Pre/Post-decrement
APSubset: int a = 2
APSubset: a++ = 2
APSubset: int a = 3
APSubset: ++a = 4
APSubset: int a = 4
APSubset: a-- = 4
APSubset: int a = 3
APSubset: --a = 2
APSubset: int a = 2
APSubset: double b = 5.0
APSubset: b++ = 5.0
APSubset: double b = 6.0
APSubset: ++b = 7.0
APSubset: double b = 7.0
APSubset: b-- = 7.0
APSubset: double b = 6.0
APSubset: --b = 5.0
APSubset: double b = 5.0
APSubset: 

APSubset: Assignment operators +=, -=, *=, /=, %=
APSubset: int a = 13
APSubset: double b = 13.0
APSubset: int a += 7 = 20
APSubset: double b += 7.5 = 20.5
APSubset: int a -= 3 = 17
APSubset: double b -= 3.5 = 17.0
APSubset: int a *= 2 = 34
APSubset: double b *= 2.0 = 34.0
APSubset: int a /= 2 = 17
APSubset: double b /= 2.0 = 17.0
APSubset: int a %= 5 = 2
APSubset: double b %= 6.0 = 5.0
APSubset: boolean c = 1 == 1 = true
APSubset: boolean c = 2 != 3 = true
APSubset: boolean c = 2 < 1 = false
APSubset: boolean c = 2 < 3 = true
APSubset: boolean c = 2 <= 4 = true
APSubset: boolean c = 2 <= 2 = true
APSubset: boolean c = 4 > 1 = true
APSubset: boolean c = 4 >= 5 = false
APSubset: boolean c = 5 >= 5 = true
APSubset: 

APSubset: Logical Operators ||, &&, !
APSubset: boolean c = true || true = true
APSubset: boolean c = true || false = true
APSubset: boolean c = false || false = false
APSubset: boolean c = true && true = true
APSubset: boolean c = true && false = false
APSubset: boolean c = false && false = false
APSubset: int[] d = null: in else clause due to short circuit
APSubset: int[] d = 1  2  3  4  5  
APSubset: double b = 5.0/2 = 2.5
APSubset: double b = (int) b = 2.0
APSubset: int a = (int) 5.0/2 = 2
APSubset: double b = 5.0/(int) 2 = 2.5
APSubset: double b = (int) 5.0/(int) 2 = 2.0
APSubset: double b = ((int) 5.0)/(double) 2 = 2.5
APSubset: double b = ((int) 5.0)/ 2 = 2.0
APSubset: Take a string, concat a number13and another string
APSubset: to see a back slash must escape it with a backslash \\ = \
APSubset: to print a double quote use backslash double quote \" = "
APSubset: 
 to get
 extra 
 lines use backslash-n (\n) 

APSubset: Look at the code for this because there are some interesting \ (backslash) uses


APSubset: One Dimension Array: Size = 5  array = 0 1 2 3 4
APSubset: Notice in the code that the size is 5 and the indexes range from 0 - 4
APSubset: Output 2 x 2 array in matrix form
0  1   
1  0   
APSubset: twod[0].size = 2
APSubset: twod[1].size = 2
APSubset: twod.size = 2
APSubset: if statements: single statement follows
APSubset:   stmt1:
APSubset:   single statement if: 1 < 2
APSubset:   stmt2:
APSubset: if statements: compound statements
APSubset:   stmt1:
APSubset:   compound if:
APSubset:   1 < 2 is true
APSubset:   all statements are executed within braces
APSubset:   stmt2:
APSubset: only 1 of the if statement is executed in the compound ifs
APSubset: then clause: num + 5 < 20 is true
APSubset: else clause: num + 15 < 20 is false
APSubset: while loop: count numbers from 0 to 9
0 1 2 3 4 5 6 7 8 9 APSubset: end while loop
APSubset: for loop: version of above while loop
APSubset: for(i = 0; i < 10; i++): all loop controls are in first line (you don't have to search through the loop)
0 1 2 3 4 5 6 7 8 9 APSubset: end for loop
APSubset: for each: use on intarr defined above, check the difference
APSubset: this version uses the fact that if you are going to visit each element
APSubset: the computer knows the size and can automatically code the loop parameters
0 1 2 3 4 APSubset: end for each style loop
APSubset: new operator: using new to create an object instance of APSubset
APSubset: this will give us an object to use the 'reverse' methods defined above
APSubset: apsubset instantiated to an APSubset object
APSubset: method over loading: 2 reverses have been defined:
APSubset: one to reverse strings and one to give a string of reversed 'int'
APSubset: look at their definitions they have different call parameters
APSubset: the compiler figures out which one to use based on parameter type
APSubset: apsubset.reverse("abcdefg") = gfedcba
APSubset: apsubset.reverse(12345) = 54321
APSubset: The methods do similar things but to different types of parameters.
APSubset: Run your IDE JavaDoc on this class and you will see what different
APSubset: comment styles do for the JavaDoc Documentation.
APSubset: Single line comments starting with // are used copiously in this class
APSubset: these 'log' statements are defined as static they can be used anywhere
APSubset: inside this class definition. If one were to use it in another class
APSubset: would have to use: APSubset.log();
APSubset: APSubset.log() call check the code
APSubset: static field: APSubset.ANSWER = 42
APSubset: String nullstr = null;  can't print this because it's null it has no String value yet
APSubset: We can test if the variable is a null variable
APSubset: null: reserved variable name value is null
APSubset: if (e = true): Forgot the extra equal sign setting e to true rather than testing with ==
APSubset: e = true; f = false
APSubset: if (e = f): in else clause because of '=' assignment now e is false
APSubset: e = true; f = true
APSubset: if (e == f): Now this works as expected.
APSubset: Be careful with your use of = and == especially with booleans
APSubset: exceptionGeneratorMethod executed no exception thrown ctr = 0
APSubset: try-catch ArithmeticException: / by zero
APSubset: finally clause executed: j = 0
APSubset: exceptionGeneratorMethod executed no exception thrown ctr = 1
APSubset: try-catch NullPointerException: null
APSubset: finally clause executed: j = 1
APSubset: exceptionGeneratorMethod executed no exception thrown ctr = 2
APSubset: loop past intarr boundry
0 1 2 3 4 APSubset: try-catch IndexOutOfBoundsException: 5
APSubset: finally clause executed: j = 2
APSubset: try-catch Exception: exeptionGenerator Method: ctr = 3
APSubset: finally clause executed: j = 3
APSubset: java.lang.Object
APSubset:  
APSubset: java.lang.Integer
APSubset: Integer myint = new Integer(55) therefore myint.intValue() = 55
APSubset: Integer.MIN_VALUE = -2147483648
APSubset: Integer.MAX_VALUE - 2147483647
APSubset:  
APSubset: java.lang.Double
APSubset: Double mydub = new Double(35.75) therefore mydub.doubleValue() = 35.75
APSubset:  
APSubset: java.lang.String
APSubset: String test_str = "this has 22 characters"
APSubset: test_str.length = 22
APSubset: test_str.substring(4,10) =  has 2
APSubset: test_str.substring(4) -  has 22 characters
APSubset: test_str.indexOf("has") = 5
APSubset: test_str.compareTo("this has 22 characters") = 0
APSubset: test_str.compareTo("this has 22 characters") = 19
APSubset: test_str.compareTo("this has 22 characters") = -6
APSubset:  
APSubset: java.lang.Math
APSubset: Math.abs(-3) = 3
APSubset: Math.abs(-3.56) = 3.56
APSubset: Math.pow(2.0,5.0) = 32.0
APSubset: Math.sqrt(2.0) = 1.4142135623730951
APSubset: Math.random() = 0.025126650838768416
APSubset: Math.random() = 0.8468764801673784
APSubset: Math.random() = 0.5932715934489992
APSubset:  
APSubset: Added values to end of list in succession: 
1 2 3  
APSubset: intList.size() = 3
APSubset: Added 4 to end of list: inList.size() = 4
APSubset: intList.get(2) = 3
APSubset: intList.add(2,5): 
1 2 5 3 4  
APSubset: Added 5 to each value using intList set: 
6 7 10 8 9  
APSubset: intList.remove(1): 
6 10 8 9  
APSubset: intList.remove(2): 
6 10 9  
APSubset: Because remove shifts the elements the 2 method calls end up removing
APSubset: elements at index 1 and 3 of the original array
BUILD SUCCESSFUL (total time: 1 second)

APSubset JavaDoc

A pdf of the JavaDoc Generated from netbeans can be downloaded from:
APSubset JavaDoc

Conclusion

There are still some things from the AP document not coded. Some of them were outside the scope of this type of study guide. Some I couldn't think of a simple yet elegant example. I've marked those in the comments of the APSubset code. Most of them you should have been exposed to in projects you've done in your class.
This study guide is meant to remind you of the functional elements of Java available to you during your AP Test. I think it is more of a guide for the free response problems. Helping you to cast your answers in the subset so that you don't over think the problem or over utilize functionality available in advanced libraries.
I did not cover the Grid World case study in this and certainly that is something you need to look over and understand. The idea here was to cover the foundational elements of Java by way of a program so you may remember them if you need them.

References

  1. https://apstudent.collegeboard.org/apcourse/ap-computer-science-a/course-details "Course Details." AP Computer Science A. N.p., n.d. Web. 29 Mar. 2013.
Author: Nasty Old Dog
-->

Friday, April 5, 2013

Blackjack: No Fun if You Don't Keep Score

Blackjack: No Fun If You Don't Keep Score

Blackjack: No Fun If You Don't Keep Score

Modulo Rears its Ugly Head

Continuing on Blackjack example I said that we would hold off on keeping score because we needed a sort routine. I have written about the 3 sort routines that the AP exam concentrates on and for the use of scoring I just randomly picked insertion sort. Rather than reuse the object from the previous article I created a new method called 'sortHand'. The main reason for doing this is that the value used to represent the card is not the value needed to score the card.

Back when this program first started modulo was used to take a number from 0 - 51 and turn it into a face value index. That index was used against a string that represents the face of the card for display purposes. Now the same concept is used but instead of a String and int array is used that is initialized to hold the 13 values of the face values of the cards. Modulo 13 (%13) is used to take any card and turn it into it's face value index. It's all captured in the 'cardvalue' method. Finally the scoreHand method takes a hand and walks through the values and tallies a total for the hand.

There is still one thing missing and that is the alternate treatment of Aces. For now Aces = 11 and I am postponing dealing with multiple Aces and the possibility they need to be scored as 1 in some cases (Not too bad really, for many hands this will give the proper score).

public int card_value(int c)
{
    // I need an array of sort values 11,2,3,4,5,6,7,8,9,10,10,10,10
    int card_score[] = {11,2,3,4,5,6,7,8,9,10,10,10,10};
    // I will use modulo 13 again to take a card and convert to face value
    // then use that to index into the card_score array for the sort value
    return card_score[c%13];
}


public void sortHand(int[] hnd)
{ 
    // sort hand make Aces 11 for sorting purposes
    // Use the insertion sort code and modify it by using the card_value
    // method as the way to sort

    int tmp;
    for (int i = 1; i < hnd.length; i++) {
        for (int j = i; 
                j > 0 && 
                this.card_value(hnd[j]) < this.card_value(hnd[j - 1]); 
                j--) {
            // swap values
            tmp = hnd[j];
            hnd[j] = hnd[j-1];
            hnd[j-1] = tmp;
        }
    }
}

public int scoreHand(int[] hnd)
{
    int tmp_hnd[] = new int[hnd.length];
    // Copy hand into a new array to play with without disturbing the
    // original hand
    for (int i = 0; i < hnd.length; i++)
    {
        tmp_hnd[i] = hnd[i];
    }
    this.sortHand(tmp_hnd);
    // tmp_hnd is now sorted must step through it and make a score
    // for now lets just treat values as score_value does and not
    // adjust for aces if the hand goes bust
    int score = 0;
    for (int i : tmp_hnd)
    {
        score += card_value(i);
    }
    return score;
}

// add some println to main to test the code
public static void main(String[] args) {
    CardDeck card = new CardDeck();

    card.display();
    card.shuffle();
    card.display();

    card.dealPlayer();
    card.dealDealer();
    card.dealPlayer();
    card.dealDealer();

    card.displayHands();
    System.out.println("Player score = " + card.scoreHand(card.playerHand));
    System.out.println("Dealer score = " + card.scoreHand(card.dealerHand));
    // Reset hands
    card.resetHands();

Output 1

run:
AH 2D 3S 4C 5H 6D 7S 8C 9H TD JS QC KH AD 2S 3C 4H 5D 6S 7C 8H 9D TS JC QH KD AS 2C 3H 4D 5S 6C 7H 8D 9S TC JH QD KS AC 2H 3D 4S 5C 6H 7D 8S 9C TH JD QS KC 
8C 9H AS 5C 5S AC 6H QC QS JC JD 8H AH 9S AD 3D 3S 7C KC KS 2D TS 7S 3H KD 2S 8D 2C 4S 6D QH 5D TH 9D 9C 6C JS 7D 4C KH TC 4H TD 5H 7H 2H QD 6S 8S 4D 3C JH 
Player Hand  
8C AS 
Dealer Hand:  
9H 5C 

Player score = 217
Dealer score = 212
Bankroll = 1000
Enter the amount you want to bet: 

0
BUILD SUCCESSFUL (total time: 3 minutes 11 seconds)

That didn't work out quite right. The problem is in the way I designed the "hands". They are int arrays but I made them a fixed length of 20 because blackjack hands can vary in the number of cards they can hold in each game. If you look over the original blackjack code you will notice there are 2 field variables dcards and pcards. These track the current number of cards in the hands.

How did the score get so high? It's because the hand arrays use 0 as the filler for unused portion of the hand. If you go over the code carefully you will notice that a card of '0' is equivalent to an Ace. Under the current scoring function an Ace always has a value of 11. The loops in scoreHand go through each of the 20 locations for the given hand. So for the player hand it will be scored as 8 + 11 * 19 = 217 (the 11 aces are counted as 1 ace for the original ace dealt and then 18 fake aces because that's the way I initialized the hand array). The reader should be able to verify that this is the same calculation for the dealer hand (hint 9 + 5 + 11 * 18).

Bad Object Oriented Design

Yes indeed. I have done this purposefully. After I finish this program I am going to rewrite (refactor) it in an Object Oriented fashion. The purpose is two fold. One to show you how to hack things up quickly and see they work just as well as an object oriented design. The second reason is sometimes Objects are more obvious once you see some code in place. Certainly this is not the way you would design for the AP exam, but in real life being able to see an Object embedded in hacked code is a necessary skill to have. I hope it will also show that Object Oriented programming helps to clean the code up and add real world meaning to what is going on in the code.

Continued Hacking

I can fix the problem in an easy but ugly way by modifying the scoreHand method to accept the int field tracking the size of the hand. This is what the fix looks like:

    public int scoreHand(int[] hnd,int size)
    {
        int tmp_hnd[] = new int[size];
        // Copy hand into a new array to play with without disturbing the
        // original hand
        for (int i = 0; i < size; i++)
        {
            tmp_hnd[i] = hnd[i];
        }
        this.sortHand(tmp_hnd);
        // tmp_hnd is now sorted must step through it and make a score
        // for now lets just treat values as score_value does and not
        // adjust for aces if the hand goes bust
        int score = 0;
        for (int i : tmp_hnd)
        {
            score += card_value(i);
        }
        return score;
    }

   // then in main the testing statements are as follows
    public static void main(String[] args) {
        CardDeck card = new CardDeck();

        card.display();
        card.shuffle();
        card.display();

        card.dealPlayer();
        card.dealDealer();
        card.dealPlayer();
        card.dealDealer();

        card.displayHands();
        System.out.println("Player score = " + card.scoreHand(card.playerHand,card.pcards));
        System.out.println("Dealer score = " + card.scoreHand(card.dealerHand,card.dcards));
        // Reset hands
        card.resetHands();

       // ... game code
}

Output 2

run:
AH 2D 3S 4C 5H 6D 7S 8C 9H TD JS QC KH AD 2S 3C 4H 5D 6S 7C 8H 9D TS JC QH KD AS 2C 3H 4D 5S 6C 7H 8D 9S TC JH QD KS AC 2H 3D 4S 5C 6H 7D 8S 9C TH JD QS KC 
8H 6H TD 2H 7S QC 4C 7D 9D KH 3H JH 2C 6S 5S QH 9H AH 5H 5C 9C 4D AC 4H QD 9S 2D KD 2S 7C 8D 5D 3S JD 8S 7H 6C TS QS 3C 4S 8C TH JS KS AS JC TC 6D AD 3D KC 
Player Hand  
8H TD 
Dealer Hand:  
6H 2H 

Player score = 18
Dealer score = 8
Bankroll = 1000
Enter the amount you want to bet: 

Using the scoreHand Method

Now that scoreHand works it can be used in the game control loop. The manual control where the user has to enter HIT or STAND for both dealer and player will still be in effect. But now the game control loop is able to detect when the Player goes BUST (has a hand > 21) or when the dealer goes BUST. Add in some println's to say WINNER and LOSER. Finally adjust the player's bankroll based on the WIN or LOSE situation. There is also one more event that can happen in the game a TIE (aka PUSH). Here the bankroll is left alone and a new hand is started (the bet is "PUSHed" back to the player). So play with the following code and even though the user has to HIT and STAND for the dealer it works almost like a real game of blackjack.

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

        card.display();
        card.shuffle();
        card.display();

        card.dealPlayer();
        card.dealDealer();
        card.dealPlayer();
        card.dealDealer();

        card.displayHands();
        System.out.println("Player score = " + card.scoreHand(card.playerHand, card.pcards));
        System.out.println("Dealer score = " + card.scoreHand(card.dealerHand, card.dcards));
        // Reset hands
        card.resetHands();

        // CardDeck card = new CardDeck();

        String user_inp = " ";
        int bankroll = 1000;
        int bet = 0;           // if the user bets 0 quit the game loop

        // Need a Scanner for user input
        Scanner uinp = new Scanner(System.in);

        // game loop just loop forever
        while (true) {
            // Tell the user the amount of the bank roll 
            System.out.println("Bankroll = " + bankroll);
            // get bet
            System.out.print("Enter the amount you want to bet: ");
//            user_inp = uinp.nextLine();
//            bet = Integer.getInteger(user_inp).intValue();
            bet = uinp.nextInt();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }
            if (bust) {
                System.out.println("BUST!! LOSER!!");
                // deduct bet from bankroll
                bankroll -= bet;
                // reset hands for next game
                card.resetHands();
                continue; // go back to top of main loop and start new game
            }
            // Manually control dealer hand the same way
            // We will swap this out for code that will run the dealer rules 
            // automatically
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                System.out.print("Dealer Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                    if (dscr > 21) {
                        // Player has gone bust
                        break;
                    }
                } else if (user_inp.equals("STAND")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            dscr = card.scoreHand(card.dealerHand, card.dcards);
            System.out.println("Player score: " + scr + "   Dealer: " + dscr);
            if (scr > dscr) {
                System.out.println("You Win!!!");
                bankroll = bankroll + bet;
            }
            else if (dscr > 21) {
                System.out.println("You Win!! Dealer has BUSTED");
                bankroll += bet;
            }
            else if (scr == dscr) {
                System.out.println("PUSH");
            } 
            else {
                System.out.println("LOSER!!!");
                bankroll -= bet;
            }
            // reset hands to play a new game
            card.resetHands();
        }
    }

Output 3

run:
AH 2D 3S 4C 5H 6D 7S 8C 9H TD JS QC KH AD 2S 3C 4H 5D 6S 7C 8H 9D TS JC QH KD AS 2C 3H 4D 5S 6C 7H 8D 9S TC JH QD KS AC 2H 3D 4S 5C 6H 7D 8S 9C TH JD QS KC 
9H JH KD 7S 4H 2S 2H 3C QC 9D KH KC AH 7C 5S 8H 8S 3S 9C 2C AC TD QD QS 6S 8C TS AS 8D KS QH AD 3D JC 5C TH 3H 5D 7D TC 6C 5H 7H JD 4D 4S 2D JS 4C 6D 9S 6H 
Player Hand  
9H KD 
Dealer Hand:  
JH 7S 

Player score = 19
Dealer score = 17
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
6D 3C 
Dealer Hand:  
AC 5D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
6D 3C KD 
Dealer Hand:  
AC 5D 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
6D 3C KD 
Dealer Hand:  
AC 5D AS 

Player score: 19   Dealer: 27
You Win!! Dealer has BUSTED
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
4C TH 
Dealer Hand:  
6D 9C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
4C TH 
Dealer Hand:  
6D 9C 9H 

Player score: 14   Dealer: 24
You Win!! Dealer has BUSTED
Bankroll = 1100
Enter the amount you want to bet: 50
Player Hand  
8D JH 
Dealer Hand:  
TD 9S 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
8D JH QD 
Dealer Hand:  
TD 9S 

BUST!! LOSER!!
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
9H 2H 
Dealer Hand:  
8D 2C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
9H 2H TS 
Dealer Hand:  
8D 2C 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
9H 2H TS 
Dealer Hand:  
8D 2C KH 

Dealer Hand hit or stand? STAND
Player score: 21   Dealer: 20
You Win!!!
Bankroll = 1100
Enter the amount you want to bet: 50
Player Hand  
2H JS 
Dealer Hand:  
8C 9C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
2H JS 7D 
Dealer Hand:  
8C 9C 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? STAND
Player score: 19   Dealer: 17
You Win!!!
Bankroll = 1150
Enter the amount you want to bet: 50
Player Hand  
TH 7D 
Dealer Hand:  
8H 3H 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
TH 7D 
Dealer Hand:  
8H 3H 6C 

Dealer Hand hit or stand? STAND
Player score: 17   Dealer: 17
PUSH
Bankroll = 1150
Enter the amount you want to bet: 0
BUILD SUCCESSFUL (total time: 1 minute 41 seconds)

Automatic Dealer Play

The dealer loop is greatly simplified when automatic play is implemented. There is one condition to check

  • dealer hand <= 16

If it is HIT the hand and check for bust otherwise loop and if it's >16 the program will 'break' out of the loop then and check how the score of the game went

The code is cleaned up to avoid the overuse of the scoreHand method. With the automatic dealer code it became obvious only a few scoreHand statements were necessary if they were strategically placed.

Here is the new main code with the automatic dealer processing:

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

        card.display();
        card.shuffle();
        card.display();

        card.dealPlayer();
        card.dealDealer();
        card.dealPlayer();
        card.dealDealer();

        card.displayHands();
        System.out.println("Player score = " + card.scoreHand(card.playerHand, card.pcards));
        System.out.println("Dealer score = " + card.scoreHand(card.dealerHand, card.dcards));
        // Reset hands
        card.resetHands();

        // CardDeck card = new CardDeck();

        String user_inp = " ";
        int bankroll = 1000;
        int bet = 0;           // if the user bets 0 quit the game loop

        // Need a Scanner for user input
        Scanner uinp = new Scanner(System.in);

        // game loop just loop forever
        while (true) {
            // Tell the user the amount of the bank roll 
            System.out.println("Bankroll = " + bankroll);
            // get bet
            System.out.print("Enter the amount you want to bet: ");
//            user_inp = uinp.nextLine();
//            bet = Integer.getInteger(user_inp).intValue();
            bet = uinp.nextInt();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }
            if (bust) {
                System.out.println("BUST!! LOSER!!");
                // deduct bet from bankroll
                bankroll -= bet;
                // reset hands for next game
                card.resetHands();
                continue; // go back to top of main loop and start new game
            }
            // Automatically Control the dealer loop
            // one simple if statement does it all
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                } 
                else {
                    break;
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            System.out.println("Player score: " + scr + "   Dealer: " + dscr);
            if (scr > dscr) {
                System.out.println("You Win!!!");
                bankroll = bankroll + bet;
            }
            else if (dscr > 21) {
                System.out.println("You Win!! Dealer has BUSTED");
                bankroll += bet;
            }
            else if (scr == dscr) {
                System.out.println("PUSH");
            } 
            else {
                System.out.println("LOSER!!!");
                bankroll -= bet;
            }
            // reset hands to play a new game
            card.resetHands();
        }
    }

Output 4

run:
AH 2D 3S 4C 5H 6D 7S 8C 9H TD JS QC KH AD 2S 3C 4H 5D 6S 7C 8H 9D TS JC QH KD AS 2C 3H 4D 5S 6C 7H 8D 9S TC JH QD KS AC 2H 3D 4S 5C 6H 7D 8S 9C TH JD QS KC 
4C 9D TC 7C AS JD 7D 2C 3C 6S 6H QH 6C 9H 2D AD 5C KH 3H KD 3D JH 6D TD QS 8C 9C QD 7S JC 3S QC JS 9S 4H 4S TH 8H 4D TS 5H 8S 2H AC 5S 7H KS 8D 2S 5D AH KC 
Player Hand  
4C TC 
Dealer Hand:  
9D 7C 

Player score = 14
Dealer score = 16
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
7D 6C 
Dealer Hand:  
KC JD 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
7D 6C KD 
Dealer Hand:  
KC JD 

BUST!! LOSER!!
Bankroll = 950
Enter the amount you want to bet: 50
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand 16 or less: Must HIT
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 2H 

Dealer Hand 16 or less: Must HIT
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 2H JH 

Player score: 17   Dealer: 26
You Win!! Dealer has BUSTED
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
5C QD 
Dealer Hand:  
TH 7S 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
5C QD 4S 
Dealer Hand:  
TH 7S 

Player Hand hit or stand? STAND
Player score: 19   Dealer: 17
You Win!!!
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
2C AH 
Dealer Hand:  
6C 4D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 

Player Hand hit or stand? STAND
Dealer Hand 16 or less: Must HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 6H 

Dealer Hand 16 or less: Must HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 6H TC 

Player score: 21   Dealer: 26
You Win!! Dealer has BUSTED
Bankroll = 1100
Enter the amount you want to bet: 0
BUILD SUCCESSFUL (total time: 6 minutes 45 seconds)

Conclusion

It almost plays like a real game of blackjack. The scoring still has that minor problem of dealing with the situation of when Aces = 1 instead of 11. The programming model for hands needs some work. I would rather add cards to hands dynamically and let the length of the int array be the actual number of cards in the hand. I will let the reader think about how to handle the scoring for Aces and in the meantime below is the full code so far.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package apcompsci;

/**
 *
 * @author Nasty Old Dog
 */
import java.util.Scanner;

public class CardDeck {

    int deck[] = new int[52];
    String faceVal = "A23456789TJQK";
    String suit = "HDSC";

    public CardDeck() {
        for (int i = 0; i < 52; i++) {
            deck[i] = i;
        }
    }

    void shuffle() {
        int rindex;
        int swap;

        for (int i = 0; i < 52; i++) {
            // each time through the loop there are less numbers to randomize
            // 52 - i to be exact. But then everything from 0 to i-1 has already
            // been selected at random so add i to the random number to get the
            // appropriate index
            rindex = (int) ((Math.random() * ((double) (52 - i))) + i);
            swap = deck[i];
            deck[i] = deck[rindex];
            deck[rindex] = swap;
        }
    }

    public String getCardText(int crd) {
        int card_val = crd % 13;
        int card_suit = crd % 4;
        return this.faceVal.substring(card_val, card_val + 1)
                + this.suit.substring(card_suit, card_suit + 1);
        //return this.faceVal.substring(card_val, card_val+1).concat(
        //this.suit.substring(card_suit, card_suit+1));
    }

    void display() {
        int card_val;
        int card_suit;
        for (int i = 0; i < 52; i++) {
            //card_val = deck[i]%13;
            //card_suit = deck[i]%4;
            System.out.print(this.getCardText(deck[i]) + " ");
        }
        System.out.println();
    }
    int playerHand[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int dealerHand[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int dcards = 0; // the number of cards in the dealer hand so far
    int pcards = 0; // the number of cards in the player hand so far
    int deckidx = 0; // the location of the next card to be dealt

    public int deal() {
        if (this.deckidx < 52) {
            return this.deck[this.deckidx++]; // return the top card and increment to the next card
        } else {
            return this.deck[this.deckidx - 1];
        }
    }

    public void dealPlayer() {
        this.playerHand[pcards] = deal();
        this.pcards++;
    }

    public void dealDealer() {
        this.dealerHand[dcards] = deal();
        this.dcards++;
    }

    public void resetHands() {
        for (int i = 0; i < playerHand.length; i++) {
            playerHand[i] = 0;
            dealerHand[i] = 0;
        }
        dcards = 0;
        pcards = 0;
    }

    public int card_value(int c) {
        // I need an array of sort values 11,2,3,4,5,6,7,8,9,10,10,10,10
        int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
        // I will use modulo 13 again to take a card and convert to face value
        // then use that to index into the card_score array for the sort value
        return card_score[c % 13];
    }

    public void sortHand(int[] hnd) {
        // sort hand make Aces 11 for sorting purposes
        // Use the insertion sort code and modify it by using the card_value
        // method as the way to sort

        int tmp;
        for (int i = 1; i < hnd.length; i++) {
            for (int j = i;
                    j > 0
                    && this.card_value(hnd[j]) < this.card_value(hnd[j - 1]);
                    j--) {
                // swap values
                tmp = hnd[j];
                hnd[j] = hnd[j - 1];
                hnd[j - 1] = tmp;
            }
        }
    }

    public int scoreHand(int[] hnd, int size) {
        int tmp_hnd[] = new int[size];
        // Copy hand into a new array to play with without disturbing the
        // original hand
        for (int i = 0; i < size; i++) {
            tmp_hnd[i] = hnd[i];
        }
        this.sortHand(tmp_hnd);
        // tmp_hnd is now sorted must step through it and make a score
        // for now lets just treat values as score_value does and not
        // adjust for aces if the hand goes bust
        int score = 0;
        for (int i : tmp_hnd) {
            score += card_value(i);
        }
        return score;
    }

    public void displayHands() {
        System.out.println("Player Hand  ");
        for (int i = 0; i < this.pcards; i++) {
            System.out.print(this.getCardText(this.playerHand[i]) + " ");
        }
        System.out.println();
        System.out.println("Dealer Hand:  ");
        for (int j = 0; j < this.dcards; j++) {
            System.out.print(this.getCardText(this.dealerHand[j]) + " ");
        }
        System.out.println();
        System.out.println();
    }

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

        card.display();
        card.shuffle();
        card.display();

        card.dealPlayer();
        card.dealDealer();
        card.dealPlayer();
        card.dealDealer();

        card.displayHands();
        System.out.println("Player score = " + card.scoreHand(card.playerHand, card.pcards));
        System.out.println("Dealer score = " + card.scoreHand(card.dealerHand, card.dcards));
        // Reset hands
        card.resetHands();

        // CardDeck card = new CardDeck();

        String user_inp = " ";
        int bankroll = 1000;
        int bet = 0;           // if the user bets 0 quit the game loop

        // Need a Scanner for user input
        Scanner uinp = new Scanner(System.in);

        // game loop just loop forever
        while (true) {
            // Tell the user the amount of the bank roll 
            System.out.println("Bankroll = " + bankroll);
            // get bet
            System.out.print("Enter the amount you want to bet: ");
//            user_inp = uinp.nextLine();
//            bet = Integer.getInteger(user_inp).intValue();
            bet = uinp.nextInt();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }
            if (bust) {
                System.out.println("BUST!! LOSER!!");
                // deduct bet from bankroll
                bankroll -= bet;
                // reset hands for next game
                card.resetHands();
                continue; // go back to top of main loop and start new game
            }
            // Manually control dealer hand the same way
            // We will swap this out for code that will run the dealer rules 
            // automatically
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                } else {
                    break;
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            System.out.println("Player score: " + scr + "   Dealer: " + dscr);
            if (scr > dscr) {
                System.out.println("You Win!!!");
                bankroll = bankroll + bet;
            } else if (dscr > 21) {
                System.out.println("You Win!! Dealer has BUSTED");
                bankroll += bet;
            } else if (scr == dscr) {
                System.out.println("PUSH");
            } else {
                System.out.println("LOSER!!!");
                bankroll -= bet;
            }
            // reset hands to play a new game
            card.resetHands();
        }
    }
}

Author: Nasty Old Dog