import java.util.Random; /* Rules of Constructors. Java has some quirky rules regarding constructors. When you write a class without a constructor, it is given a default constructor that's equivalent to the following class someclass { // public someclass() { super(); } // automatic default constructor // no other constructor in class. } The keyword 'super' refers to the superclass constructor: remember that every class extends the 'Object' superclass even if there's no 'extends' clause. super() calls the constructor of the (closest) superclass. In fact, super() is called implicitly so sometimes you don't see it being called. HOWEVER, the strange rule is that if you do write another constructor, which takes some parameters, then the default constructor IS NOT CREATED FOR YOU: class A { public A(int x) { ... } } This means to create an instance of A you must call new A(x) for some integer x, and not new A(); Furthermore, when you write a subclass of A, you are now obliged to also write a constructor AND explicitly call super: public class B extends A { public B(int x, int y...) { super(x); ... } } If you leave out the call to super(x), it will implicitly call super(), which will fail because there's no such constructor in the superclass. */ interface Playable // should be made public and placed in different file { void win(); void lose(); void printrecord(); void play(team x); double winningpercentage(); } class team implements Playable, Comparable { public static Random Rnd = new Random(); // random number generator protected int wins; protected int losses; public final String name; // name of team public team(String n) { name=n; wins=losses=0; }//constructor public void win() { wins++; } public void lose() { losses++; } public void printrecord() { System.out.println(name+": "+wins+"-"+losses); } public double winningpercentage() { int total = wins+losses; if (total==0) return 0; // don't divide by zero else return wins*1.0/total; } public int compareTo(team other) // compare by winning percentage { double p = this.winningpercentage(); // 'this' for emphasis double q = other.winningpercentage(); if (potherscore) { this.win(); other.lose(); System.out.println("I win, you suck"); } else { this.lose(); other.win(); System.out.println("You win, but you still suck"); } }//play }//team class // interface for teams that can tie as well as win/lose interface Cantie extends Playable { void tie(); } // subclass for football teams, with several differences from team: class fbteam extends team implements Cantie { protected int ties; public void tie() { ties++; } public fbteam(String n) { super(n); ties=0; } // alternate constructor can set intial w-l-t record public fbteam(String n, int w, int l, int t) { super(n); wins=w; losses=l; ties = t; } // must override winningpercentage function @Override public double winningpercentage() { int total = wins+losses+ties; if (total==0) return 0; // don't divide by zero else return (wins + ties*0.5)/total; } // do we also have to override compareTo? NO because of DYNAMIC DISPATCH @Override public void printrecord() { System.out.println(name+": "+wins+"-"+losses+"-"+ties); } // don't have to re-define compareTo, it will automatically // dispatch to the correct version of winningpercentage() // returns a random value >0, <1 with bias towards average m: public static double biasedrandom(double m) { double x = Math.random(); if (m<=0 || m>=1) return x; // defaults to mean = 0.5 else return Math.pow(x,1/m-1); } // this is because the definite integral of x**(1/m-1) for x from // 0 to 1 is m, i.e, the average value of a point on the curve // defined by x**(1/m-1) on the interval between 0 and 1 is m. // now for a more interesting play function @Override public void play(team other) { fbteam opponent = (fbteam)other; // may throw runtime casting error // typical football scores: int[] Scores={0,3,6,7,10,13,14,16,17,20,21,23,24,27,28,30,31,34,35,37,38,41,42,44,45,47,48,49,51,52,55,56,58,59}; double p = this.winningpercentage(); // which function is this calling? double q = opponent.winningpercentage(); // give every team a chance by setting min and max percentages if (p<.05) p = .05; if (p>.95) p=.95; if (q<.05) q = .05; if (q>.95) q=.95; // generage two biased random numbers, biased to p, q double pr = biasedrandom(p); double qr = biasedrandom(q); // scale pr, qr to Scores.length, and pick out scores int myscore = Scores[ (int)(pr*Scores.length) ]; int opscore = Scores[ (int)(qr*Scores.length) ]; System.out.println(name+" "+myscore+", "+opponent.name+" "+opscore); if (myscore>opscore) // win { win(); opponent.lose(); } else if (myscore sorter = new rsorts(Tm); // sorting algorithms sorter.quicksort(); for(team t:Tm) t.printrecord(); //System.exit(0); // terminates program // now for something more interesting///////////// fbteam[] Fts = new fbteam[14]; Fts[0] = new fbteam("Giants",0,3,0); Fts[1] = new fbteam("Jets",1,2,0); Fts[2] = new fbteam("Cowboys",2,1,0); Fts[3] = new fbteam("Patriots",2,1,0); Fts[4] = new fbteam("49ers",3,0,0); Fts[5] = new fbteam("Steelers",2,1,0); Fts[6] = new fbteam("Packers",2,1,0); Fts[7] = new fbteam("Eagles",2,1,0); Fts[8] = new fbteam("Chiefs",3,0,0); Fts[9] = new fbteam("Bills",2,1,0); Fts[10]= new fbteam("Seahawks",1,2,0); Fts[11]= new fbteam("Broncos",2,1,0); Fts[12]= new fbteam("Chargers",0,3,0); Fts[13]= new fbteam("Raiders",2,1,0); // that's enough... int teams = Fts.length; for(int j=0;j(Fts); // using "coerced covariance" sorter.quicksort(); // sorts (no need to assign to var) System.out.println("=== final standings ==="); for(team ft:Fts) ft.printrecord(); }//main }// main public class /* Please note the following subtle point: fbteam inherits the compareTo function from the superclass team, because the algorithm used is still valid: compare the winning percentages of the two teams. Look at the code for compareTo: it calls this.winningpercentage() and other.winningpercentage(). The *statically known* type of both 'this' and 'other' are team. That is, there is no way to know what kind of teams these really are by just looking at the code for compareTo. So the version of the winningpercentage function to call *also cannot be determined statically, at compile time*. We can only know what kind of teams 'this' and 'other' are at the point of call - during *run time*. This is called "dynamic dispatch" (as opposed to static dispatch), and to me is the most important feature of an object oriented programming language. The syntax of classes and objects add nothing essentially new to programming without this feature. */