View Single Post
Old 22-06-2004, 04:00   #1 (permalink)
Datapunter
Pro Punter
 
Datapunter's Avatar
 
Join Date: 23 Oct 2003
Location: Westdorpe
Age: 43
Posts: 5,530
Default Lesson 8 - Our first application, a systems calculator

Lesson 8 ( Word document )

Punters Lounge JAVA programming course.
Lesson 8 - Our first application, a systems calculator.

So far we have been learning about the language and its time to put it all to some practical use.

Our first application will be a systems calculator. I’m going to write the functional and technical design and then I will explain making the whole program step by step. However after reading the design I invite you to simply have a go yourself first. That will be a good test of your programming abilities so far.

Now you may not be interested in calculating systems, or you may point out that you can do this just as easily in Excel. Well, that is fine, but i urge you to do this lesson anyhow. The point is that you take the next step in thinking as a programmer. Its practice in thinking about program structures. How to build those FOR and WHILE loops, what conditions to put in the IF ELSE statements. The fact that we write a systems calculator is irrelevant to the point and exercise of this lesson.

And ROOKIES remember; there is nothing you are supposed to be able to do at this moment. Some people will write this program in one evening, others will need several evenings. Some will do it on their own, others will need to be guided. Your learning curve is unique to you alone, embrace it and simply give it the time it takes.


8.1 Functional design Systems Calculator

The program must read a betting record from a file and make statistical calculations on the bets made so far. This information is to be displayed on the screen and written to a file as well so it can be used in other applications.

The program must generate a theoretical calculation using level stakes so that can be used as a reference and a calculation on the actual bets made.


8.2 Technical design Systems Calculator

Input file
The input file must contain following information, all separated with a comma.
- Bet description
- Win or Lose
- Decimal Odds
- Stake

Example.
Arsenal – Liverpool,Win,1.66,20
O'Sullivan world champion,Win,1.23,5
Ayr1620 My Little Pony,Lost,4.5,10


Following items need to be calculated:
Both level stakes and actual bets calculation
- Strike rate ( winning bets divided by total of bets as a percentage )
- Average odds ( the average odds of all the bets )
- Yield ( total return divided by total stake expressed as a percentage )
Level stakes calculation
- Ending bank ( at level stake of 1 and a starting bank of 100 units )
- Profit or Loss ( the actual amount won or lost )
Actual bets calculation
- Ending bank ( the actual starting bank to be contained in a variable, say 100 units )
- Profit or Loss ( the actual amount won or lost )


The screen and output file must simply contain a listing of the calculations made like this:

Level stakes calculation
Winning bets : 10
Losing bets : 10
Strike rate : 50%
Average odds : 1.45
Start bank : 100
End bank : 115
Profit/Loss : 15
Yield : 15%

Actual bet record
Winning bets : 10
Losing bets : 10
Strike rate : 50%
Average odds : 1.45
Start bank : 300
End bank : 400
Profit/Loss : 100
Yield : 25%


8.3 Programming design thoughts.

Before I start programming I make a sketch our outline of how I’m going to build the application. Now this is not the best way to do it, it is not the right way to do it, it is certainly not the only way to do it. It is simply the way I do it. There are as much methods and resulting programs as there are programmers. You simply need to find a way that works for you.


* The input file is a simple ASCII file that can be read line by line, so we’ll need a loop reading each line using a buffer. ( to use the readLine() method from the BufferReader object )

* Will not read the entire file into an array. The calculations are straightforward and can be made as each line is read. If it was necessary to go through the info several times then I would use an array.

* Each line contains both text and numerical info and will have to be parsed. So will create a separate method to do the parsing.

Parse : To break (a sentence) down into its component parts of speech with an explanation of the form, function, and syntactical relationship of each part.

In our case, break the line up in its individual components and store those components in the appropriate variables.


* Output file is a simple combination of the calculated results and text, so straightforward FileWriter object, using a BufferedWriter for speed.




8.4 Completing Object Oriented Programming.

Before we start programming this is a good time to complete the subject of Object oriented programming. There is a part we have not seen yet and that is the first two lines of the programs we have written so far. In case of our system calculator they look like this:

public class SysCalc {

public static void main(String[ ] arguments) throws Exception {


First line has the name of our program SysCalc. The word class tells the Java compiler that this is the beginning of the definition of a class. A class is a blueprint of an object. When we create new objects we do so using the class of that object. So we define one class called SysCalc and then using that class we can create objects of the type SysCalc.

The second keyword here is public. These are the possible keywords when defining a class:

public, abstract, final, extends super, implements interface

By default, so if you write no keyword, the class will only be accessible from classes in the same package. If you wish the class to be accessible from other packages you need to use the public keyword. Packages are a method to group programs or classes. We've seen an aspect of packages in some of our exercises. To use a class from a package you have to include that package in your program so the compiler knows you will be using a class from that package, like this:

import java.util.*

So tell the compiler that in this program you will be using classes from the java.util.* package. If you do not include this then you will get a class not found error. Besides using the standard Java packages it is also possible to create your own packages.

This course is intended for individual programmers writing small single-user applications. Therefore i will not go further into this subject. You can have a look at the full explanation here:

http://java.sun.com/docs/books/tutor...classdecl.html


For our purposes it is sufficient to remember that the first line: class SysCalc is the definition of our program class. Should you ever find yourself writing commercial applications or working on larger applications with a group of programmers you will need to review this in detail.


Now, about the second line in our program:

public static void main(String[ ] arguments) throws Exception {

Lets look at this line back to front. As mentioned before the words throws Exception are part of Java's error handling system. And again i will explain in a later chapter, just remember for now that depending on the objects you use these keywords are required.

Now the part between the brackets (String[ ] arguments) has also been covered in a previous chapter. It's the declaration of a String array that will contain the parameters given to the program at the time the program gets started. See Lesson 5.

Next we get to the name of the method we are declaring here: main() As covered before objects consist of methods and states. In this case we create a method called main(). If you write the class for an object you intend to run as a program then you must define a method called main(). When you start a program, the interpreter on your operating system will automatically search for a method called main(), and execute from that point. If you write a class without a method main() then you can only access or use any object from that class from inside other objects. So an application consists of a collection of objects defined by classes where one of those classes must contain a method main() being the starting point when the application is run.

Now we come to the words public static void

void indicates the type of data the method returns to the calling object. In this case void indicates that this method will, after completion, not return anything. The return type can be any type of data or object. If you do declare a return type then you must end the method with a return statement like this:

class myobject {
int mymethod() {
int myint = 15;
return myint;
} // end of the method
} // end of the class defining myobject


In this case we declare a method called mymethod() and declare a return type of integer. The method must now end with a return statement returning an object of the integer type.

The calling object uses this like this:

myobject mine = new myobject;
int myint = 0;
myint = mine.mymethod();


So after the method mymethod() runs inside the mine object it returns a value of the type int.


static is used to identify the member of a class, variable or method, as being a class member. By default, so without writing static, a member of a class becomes an instance member. This means that each time you create an object from a class, instantiate, you create a new version of its members. When you declare a member as static then all objects created from the class will refer to a single instance of that member, variable or method.

For example you can have the Scoreboard object. Each time you create a Scoreboard object you want a new copy of its variables because the scores are unique. But the methods used are always the same and there is no need to have a new instance each time. We can use a single copy of a method like goals(). This we do by making it static. No matter how many objects are created from the class there will be only one occurrence of a static member. It follows that static members can only access static variables and not the individual members of each object created.

A lot more can be said about this but again for our purpose we are going to keep things simply. To make a member private is a matter of design. As we design our first applications i will go into this some further.


public , the first word on the line identifies who has access to this member of the class. Possible words are private, protected, public and package. These keywords determine who can use this class's member. Again will not go into this because it is not really required for the purpose of this course. Suffice to note at this moment that identifying a member as public will allow you to access from any other part of your application. Should you find yourself programming in a group you will need to review this in detail.

http://java.sun.com/docs/books/tutor...sscontrol.html


This completes the whole Object Oriented Programming subject. There is a lot more to say about it but that would be beyond the scope of this course. If it is your intention to create a simple application for yourself, then what you have learned up to this point about Object Oriented programming will suffice. If you wish to expand your programming skills to bigger applications you will have to review the subject completely. In this case there are tutorials and books available that are far better at explaining Object Oriented programming than i will ever be.

Time to get to work.



Lets start with the skeleton of our application and fill in the parts as we go along.

// define a class being our program
class SysCalc {
    /* define a method main() since we want to run this object as a program
    * public being the main() method it must be made public
    * static no reason why this method should ever occur more than once so static
    * void the main method does not return anything, so return type is void
    * throws Exception are required keywords when using file objects.
    */
    public static void main(String[ ] arguments) throws Exception {

      // define reader objects to read from the betting record

      // create a loop reading each line from the betting record
      while (there are lines left to read) {

        // read a line and parse the components into variables
        // make the calculations

      } // end of loop reading each line in the bet record

      // take the end result of the calculations and display on the screen
      // take the end result of the calculations and write to an output file

    } // end of the main() method, therefore end of the program

    /* define a method ParseLine
    * not public, the method will only be accessed from inside the same class
    * static no reason why this method should ever occur more than once so static
    * void the method does not return anything, so return type is void
    * throws Exception is optional, no objects in this method that require Exception handling
    *
    * note the parameter for this method is a single string called PL, this is the line from
    * our bet record that we want to parse into usable variables
    */
    static void ParseLine(String PL) {

      // put the components of a line into variables

    } // end of the method ParseLine

} // end of the definition of the SysCalc class


First lets look at some variables we are going to need to do all the calculating in our main program. Obviously we will get Odds, Stake and Win or Lose from the line in our bet record. Then we need to calculate the results. For this we need a number of variables like this:

public static void main(String[ ] arguments) throws Exception {

// Defining variables for the main method
float Winners = 0; // number of winning bets
float Losers = 0; // number of losing bets
float TotOdds = 0; // total of all odds
float AvrOdds = 0; // Average of odds

float LsBank = 100; // level stakes bank
float LsStaked = 0; // total staked at level stakes
float LsReturned = 0; // total returned at level stakes

float MyBank = 100; // total bank at actual stakes
float MyStaked = 0; // total staked at actual stakes
float MyReturned = 0; // total returned at actual stakes

Note you rarely create these in one go. Usually you start with one calculation, define the variables required and then add variables as you go along.

Next lets look at reading our bet record. For that we will need a buffer and a FileReader and File object. And a String object to temporarily hold the contents of the line. This can then be used to loop through the file line by line:

String aBet = "";
BufferedReader BetRecord = new BufferedReader (new FileReader (new File("mybets.txt")));

// also create the output file here, keeping file objects close together for readability
BufferedWriter SysResult = new BufferedWriter(new FileWriter (new File ("sysresult.csv")));
// while , read a line and put the line in the string variable, is successful
while ( (aBet = BetRecord.readLine()) != null ) {
// read a line and parse the components into variables
// make the calculations
}

REMEMBER, when you run the program you MUST have an existing file that is called mybets.txt and looks like this:

File: mybets.txt

bet1,Win,1.25,12
bet2,Lose,2.5,10
bet3,Win,4,6
bet4,Lose,1.5,3
bet5,Lose,1.8,1

( bet-description comma Win-or-Lose comma decimal-odds comma Stake )

It could be an imaginary bet record or something created from real life.

Now, lets look at parsing that bet info from a string into usable variables. For this i'm going to define 3 class variables like this:

class SysCalc {
// variables defined as public for the whole class
static String WinLose = ""; // variable to hold Lose or Win
static float Odds = 0; // variable to hold the Odds
static float Stake = 0; // variable to hold the Stake

So right after the class definition i create 3 variables, a String and 2 floats to hold the values for WinLose, Odds and Stake, and i make them static. Now because i declare them inside the class definition and not inside a method these variables will be accessible from any method inside this class. Because i make them static there will ever only be one variable like this in existence and any static method will be able to access these variables and modify there state.

Now we go to the ParseLine method and we parse the string from our file into these variables. This we do using the string methods like indexOf() and substring().

static void ParseLine(String PL) {
    int start;
    int end;
    String temp;

    start = PL.indexOf(",");
    // search for the first comma
    end = PL.indexOf(",",start+1); // search for the second comma,
    // starting after the position of the first comma put the part of the string between
    // the first and second comma into WinLose
    WinLose = PL.substring(start+1,end);

    // note : we are completely skipping everything before the first comma
    // being the description of our bet.

    // number between second and third comma is Odds,
    // converting from String to Float
    start = end+1;
    end = PL.indexOf(",",start);
    temp = PL.substring(start,end);
    Odds = Float.parseFloat(temp);


    // number between third comma and end of the string is Stake,
    // converting from String to Float
    start = end+1;
    temp = PL.substring(start);
    Stake = Float.parseFloat(temp);
} // this bracket is the end of method ParseLine


Now if we look at our loop we see we now have everything needed to calculate the results of the system:

// while , read a line and put the line in the string variable, is successful
while ( (aBet = BetRecord.readLine()) != null ) {

ParseLine(aBet);


// ParseLine has filled the variables Odds Stake and WinLose, so together with the
// variables defined earlier we can make the calculations
}


So we can now complete the loop of our bet record and make the calculations:
I'm assuming here the comments are sufficient to understand what is being calculated, if its not clear go back to the technical design and see if you simply identify each item from the technical design in the code below.

while ( (aBet = BetRecord.readLine()) != null ) {
    ParseLine(aBet);

    LsStaked = LsStaked + 1;
    // Level stakes : total staked
    MyStaked = MyStaked + Stake; // Actual stakes : total staked
    // to calculate the average odds add all the odds, later divide by the number of bets
    TotOdds = TotOdds + Odds;

    // if the String WinLose equals "Lose" we have a losing bet
    if ( WinLose.compareTo("Lose") == 0) {

      Losers = Losers + 1;
      // both level and actual stakes
      LsBank = LsBank - 1; // Bank at level stakes
      MyBank = MyBank - Stake; // Bank at actual stakes

    // if the String WinLose is not equal to "Lose" we have a winning bet
    } else {

      Winners = Winners + 1;
      // both level and actual stakes
      LsBank = ( LsBank - 1 ) + ( Odds * 1 ); // Bank at level stakes
      LsReturned = LsReturned + ( Odds * 1 ); // Return at level stakes
      MyBank = ( MyBank - Stake ) + ( Odds * Stake ); // Bank at actual stakes
      MyReturned = MyReturned + ( Odds * Stake ); // Return at actual stakes
    }

}
// end of WHILE loop, reading a line from the input file

// we have read all the lines from the file so we can close it.
BetRecord.close();


Now we come to the part where we've calculated the result of the system and we need to display that result on the screen.

// write the calculations to the screen, level stakes
System.out.println("Level stakes calculation");
System.out.println("Winning bets = " + Winners);
System.out.println("Losing bets = " + Losers);
System.out.println("Strike rate = " + (Winners / (Winners+Losers))*100);
System.out.println("Average odds = " + TotOdds / (Winners+Losers));
System.out.println("Start Bank = 100");
System.out.println("End bank = " + LsBank);
System.out.println("Profit/loss = " + (LsBank - 100));
System.out.println("Staked = " + LsStaked);
System.out.println("Return = " + LsReturned);
System.out.println("Yield = " + ((LsReturned/LsStaked)-1)*100);
System.out.println("");


// write the calculations to the screen, actual stakes
System.out.println("Actual stakes calculation");
System.out.println("Winning bets = " + Winners);
System.out.println("Losing bets = " + Losers);
System.out.println("Strike rate = " + (Winners/(Winners+Losers))*100);
System.out.println("Average odds = " + TotOdds / (Winners+Losers));
System.out.println("Start Bank = 100");
System.out.println("End bank = " + MyBank);
System.out.println("Profit/loss = " + (MyBank - 100));
System.out.println("Staked = " + MyStaked);
System.out.println("Return = " + MyReturned);
System.out.println("Yield = " + ((MyReturned/MyStaked)-1)*100);


And let's not forget to write the result to a file so we can use it in another application if we wish:

// write the calculations to out output file
SysResult.write("Level stakes calculation"); SysResult.newLine();
SysResult.write("Winning bets," + Winners); SysResult.newLine();
SysResult.write("Losing bets," + Losers); SysResult.newLine();
SysResult.write("Strike rate," + (Winners / (Winners+Losers))*100); SysResult.newLine();
SysResult.write("Average odds," + TotOdds / (Winners+Losers)); SysResult.newLine();
SysResult.write("Start Bank,100"); SysResult.newLine();
SysResult.write("End bank," + LsBank); SysResult.newLine();
SysResult.write("Profit/loss," + (LsBank - 100)); SysResult.newLine();
SysResult.write("Staked," + LsStaked); SysResult.newLine();
SysResult.write("Return," + LsReturned); SysResult.newLine();
SysResult.write("Yield," + ((LsReturned/LsStaked)-1)*100); SysResult.newLine();

SysResult.write(""); SysResult.newLine();

SysResult.write("Actual stakes calculation"); SysResult.newLine();
SysResult.write("Winning bets," + Winners); SysResult.newLine();
SysResult.write("Losing bets," + Losers); SysResult.newLine();
SysResult.write("Strike rate," + (Winners/(Winners+Losers))*100); SysResult.newLine();
SysResult.write("Average odds," + TotOdds / (Winners+Losers)); SysResult.newLine();
SysResult.write("Start Bank,100"); SysResult.newLine();
SysResult.write("End bank," + MyBank); SysResult.newLine();
SysResult.write("Profit/loss," + (MyBank - 100)); SysResult.newLine();
SysResult.write("Staked," + MyStaked); SysResult.newLine();
SysResult.write("Return," + MyReturned); SysResult.newLine();
SysResult.write("Yield," + ((MyReturned/MyStaked)-1)*100); SysResult.newLine();

// all written to the output file so we can close it
SysResult.close();



And there we have our full program.

Now i could go on endlessly explaining things, but i'm not going to. I'm going to finish with a full listing, (which of course you can download or copy and paste) and some assignments. Right now it's simply up to you to go through the program and see if you get the different parts. Any parts you don't get, go back to the lesson where those objects where handled and review it.


Now i would like to point out that, if there is any part you don't get, it is very unlikely you will get it by reading things over and over again. You'll have to do it by simply writing small programs to figure out the part you don't get. This is the point where you really need to start doing the work.


And remember, DO NOT HESITATE TO CONTACT ME, a couple of emails can work miracles, a simple chat session of half an hour can save you day's, yes day's, of figuring things out on your own. And if you might be worried about imposing on me, don't, i'm the one telling you to contact me aren't i, so use the offer.


( if you are reading this some time after the course took place, summer 2004, send me an email anyway, worst thing that can happen is you don't get a reply, simply click on my username on the Punters Lounge and select "send private message", would love to hear from you )

On the next page some assignments and then a full listing of the program as described here.

In these assignments we will create several versions of the program in this lesson. You may continue with the name SysCalc and chance it each time. But i advise you to copy SysCalc and continue with the names from the different assignments.

So take SysCalc.java and copy it to Lesson81.java and don't forget to change the name on the first line from class SysCalc to class Lesson81.



Assignment 8.1 ( Lesson81.java )

First lets see if you can reproduce some results. Run the program with this file and see if the results are the same. So you need to chance the name of the input file. You could chance the program so it asks for the name or you give the name as a parameter, thats up to you.

File : PlaceMarket.txt

Its the bet record of a system on the Horse Racing Place market. Not profitable as is but thats not the point. See if you get the same results.


Level stakes calculation
Winning bets 80
Losing bets 101
Strike rate 44.198895
Average odds 2.45232
Start Bank 100
End bank 90.58003
Profit/loss -9.419968
Staked 181
Return 171.58006
Yield -5.2043858

Actual stakes calculation
Winning bets 80
Losing bets 101
Strike rate 44.198895
Average odds 2.45232
Start Bank 100
End bank 96.09004
Profit/loss -3.909958
Staked 207.55002
Return 203.64008
Yield -1.8838584

Run the program with a bet record of your own and see if the results are, as you would expect. Remember you can always make a record yourself. All you need is a file with this format:

bet1,Win,1.25,12
bet2,Lose,2.5,10
bet3,Win,4,6
bet4,Lose,1.5,3
bet5,Lose,1.8,1
and so on….



At this point i'd like you to consider why you are doing the course. If you are doing the course simply because you want to get some info from some webpages then you may skip the next assignments. You can always come back to them later.

If it is however your intention to do a bit more than that and you are interested in programming in a more general way then do continue.


Assignment 8.2 ( Lesson82.java )

We take the previous program and add a check for bankruptcy. After all when the bank has reached 0 we have nothing left to bet with and the program should stop. Lets simply check if there is enough in the bank to cover the stake for the next bet and if not we declare a bankruptcy.

How can we test this ? By using a bet record file that goes bankrupt, like this:

File : bankrupt.txt

bet1,Lose,10,50
bet2,Lose,10,40
bet3,Lose,10,10
bet4,Lose,10,10
bet5,Lose,10,10

Obviously after the 3rd bet we have no more money and the program should declare bankruptcy for actual stakes and not continue with the 4th bet. Running the Lesson81 program with this bet record will result in a negative bank for actual stakes. Something that is of course not possible in real life.

Depending on how you designed your program adding this condition may not be that easy. After all bankruptcy may occur for actual stakes but not for level stakes. You may need to re-think your entire program flow. I did. Unfortunately something any programmer has to deal with.





Using this file you will see bankruptcy on level stakes after 100 bets.

File : BRlevel.txt

bet1,Lose,10,0.25
bet2,Lose,10,0.25
bet3,Lose,10,0.25
bet4,Lose,10,0.25
and so on for 150 bets……

Since the size of the stake is only 0.25 the actual stake calculation will continue after 100 bets but level stakes should declare a bankruptcy.



I will continue to use Placemarket.txt as bet record, but all assignments are valid for any other bet record of course.


Assignment 8.3 ( Lesson83.java )

Now that we calculate level stakes and actual stakes and check for bankruptcy lets add another staking method. Namely fixed profit staking. This is where the stakes size depends on the available odds and is set in such a way that each bet wins a fixed amount, like 1 unit.


So for example to win 1 unit with odds of 1.3 you need to stake 3.33 calculated like this:

Stake = Win / ( Odds - 1 ) or Stake = 1 / ( 1.3 - 1 )

If you use my Placemarket bet record with this assignment then the actual stakes result and the results for fixed profits should be exactly the same. I actually used fixed profits on that system. This way you can check if your calculations are right.

Running on Placemarket.txt should give this result:

Fixed profits calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 96.09004
Profit/loss -3.90996
Staked 207.55
Return 203.6401
Yield -1.88386


Assignment 8.4 ( Lesson84.java )

And while we are at it lets add another staking plan. This time percentile bank staking. This is where the size of the stake is a fixed percentile of the bank. Like 1%.

Running on Placemarket.txt should give this result :

Percentile bank calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 89.7364
Profit/loss -10.2636
Staked 164.8565
Return 154.5929
Yield -6.22578


Assignment 8.5 ( Lesson85.java )

Now we could go on with progressive staking or even Martingale but you get the picture.

As last assignment take the previous program and add the subtraction of a fixed percentile in commission of all the winnings. At 5% results should look like this:

Level stakes calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 86.001
Profit/loss -13.999
Staked 181
Return 167.001
Yield -7.73426

Actual stakes calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 92.0898
Profit/loss -7.9102
Staked 207.55
Return 199.6399
Yield -3.81117

Fixed profits calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 92.0898
Profit/loss -7.9102
Staked 207.55
Return 199.6399
Yield -3.81117

Percentile bank calculation
Winning bets 80
Losing bets 101
Strike rate 0
Average odds 2.45232
Start Bank 100
End bank 85.79464
Profit/loss -14.2054
Staked 161.5659
Return 147.3606
Yield -8.79231



The Word document has a full listing of the program, i've not done that here because its a lot of work to post accurately.
You can download the source code from here:
SysCalc.java
Datapunter is offline