/* CSC15 Lab10 : Horse Race Due in one week For this lab you are to use arrays and loops to complete a horse race simulation. Download this file from the homepage. If you are using Hofstra Sun workstations, you do not need to download the gif images (they're in a common directory). However, if you want to write the program on your PC, you have to download "racer.gif" and "hrbackground.gif", and edit lines 228 and 230 of this file appropriately. This file contains two classes, racer and horserace. Your job is to write two functions in the horserace class. However, you need to know what each class consist of. class racer: This class represents a graphical object similar to the goblins program we looked at before. Each racer object represents a horse (and rider) in the race. Here's an example of how to create a racer object: racer myhorse; myhorse = new racer(0,60,"speedy racer",racergif,brush); The first two parameters are the initial x and y coordinates of the (upper left corner) of the horse image. Initially, the x coordinate should be 0. The y coordinate depends on the horse (see below). The third parameter is a string representing the name of the horse. You'll need to create an ARRAY of racer objects. Each racer object has the following public methods that you can call: void draw() // draws horse void moveForward(int step) // increases x coordinate by step. String getname() // returns the name of the racer int position() // returns the current x coordinate of the horse The basic idea is to write a loop in which each horse will moveForward by a random amount until some horse reaches the finish line. class horserace: This is where you will write your functions. However, you should be aware that the class consists of the following variables and functions already provided: int HN; // number of horses in race, default 6 int TW; // track length (width of window), default 800 int TH; // height of window - depends on HN int LW; // lane width, default 60 The HN variable represents the number of horses in the race. This value is the length of the command line argument array String[] args. The array contains strings representing the names of the horses in the race. For example, if the program is executed using java horserace speedy crazy thunder then HN would be 3, and the names of the horses would be "speedy", "crazy" and "thunder". TW and TH are the dimensions of the program's main window, and depends on the HN value. The LW variable controls the distance between the lanes that each horse must stay in. These variables are initialized already. However, your code should be made dependent on these variables, as opposed to constants. For example, use LW instead of 60, since that should be easily changeable. I emphasize that these variables have already been declared inside the class, so you shouldn't declare them again! The following functions are already included, and can be called from your functions: public void nextframe(int n) public void displayStatus(String message) randint returns a random integer between min and max, inclusive. nextframe draws the next animation frame, after delaying for n milliseconds (nextframe should only be called after you've called the draw() function on each racer object). As the race progresses, a message should be displayed at the top that indicates which horse is in the lead, or if there is a tie. You can invoke this by calling the displayStatus function with the appropriate message you want to display. You are to write the following functions: 1. public void race(String[] names) In this function, you should first create an array of HN racer objects. The names of the horses are passed from main to this function in the array String[] names (same as the args array in main). The intitial x coordinates of the horses should always be 0 (representing the starting position). The y coordinates of the nth horse should be set to n*LW+LW. for example, if LW==60 (the default), then the 0th horse will have y coordinate 60, the next horse will have 120, the next one 180, etc ... (use LW, don't use 60!). Do the following: a. You need to declare additional variables. One of these variables should be a boolean variable called stoprace, which should be initially set to false. This variable should be used as the test of your while loop b. Create the array of racers as explained above c. Call the draw() function on each racer object in the array, then call the nextframe function once initially before starting the main loop. This will make sure that the horses are displayed in their starting positions. d. Write a while loop that continues until the stoprace bool variable becomes true. inside this loop, you need to: write an *inner loop* that goes through the array of horses, and call moveForward on each horse object, giving it a random number between 1 and 5 (experiment). If the x position of any horse becomes greater than TW-68 (732), you should set stoprace to true. You probably also want to call the draw() function on each racer object inside this inner loop. After this inner loop, you then need to call the determineLeader function (see below) that determines the current horse in the lead (or tie), then call the displayStatus function to display an appropriate message at the top. Finally, at the end of the (outer) while loop you should called nextframe to display the race graphically. Remember: call nextframe only after the draw() method on each horse has been called. This is a set of guidelines. You need to tweak your program to get it to work nicely. 2. public int determineLeader(racer[] H) This function takes an array of racers as a parameter (the array itself will be created in the second function), and determine which horse is in the lead, or if there is a tie. It returns the array INDEX of the horse in the lead. If there is a tie, it should return -1 (since -1 is not a valid array index). For example, if racer H[3] is in the lead, it should return 3. */ import java.awt.*; import java.awt.event.*; import java.awt.Graphics; import javax.swing.*; class racer { private int x; // screen coordinates private int y; private String name; private Image anigif; // animated gif image of racing object private Graphics brush; public racer(int x0, int y0, String n, Image i, Graphics b) { x = x0; y = y0; name = n; brush = b; anigif = i; try { Thread.sleep(100); } catch (InterruptedException IE) {} } public String getname() { return name; } public int position() { return x; } public void moveForward(int step) { x = x+step; } public void draw() { brush.setColor(Color.black); brush.drawString(name,10,(y+55)); brush.drawImage(anigif,x,y,null); } } // class racer /* ************************************************* */ public class horserace extends JFrame { private Graphics brush; public Graphics display; private Image canvas; // off-screen graphics buffer private Image background; // racing background gif private Image staticbkgrd; // static (stretched) background; private Image racergif; // horse and rider animated gif public int HN = 6; // number of horses (command-line argument) public int TW = 800; // track length; public int TH; // track height - depends on number of racers public int LW = 60; // lane width public void paint(Graphics g) {} // overrides auto-update public static void main(String[] args) // needed for application { horserace session = new horserace(); if (args.length>0) session.HN = args.length; //Integer.parseInt(args[0]); session.TH = (session.HN * session.LW) + session.LW+10; session.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); session.init(); session.race(args); } // main public void init() { setBounds(0,0,TW,TH); show(); background = Toolkit.getDefaultToolkit().getImage("/shared/csc/local/stuff/hrbackground.gif"); prepareImage(background,this); racergif = Toolkit.getDefaultToolkit().getImage("/shared/csc/local/stuff/racer.gif"); prepareImage(racergif,this); canvas = createImage(TW,TH); staticbkgrd = createImage(TW,TH); brush = canvas.getGraphics(); // to double buffer brush.setColor(Color.blue); display = this.getGraphics(); // to screen try { Thread.sleep(750); } catch (InterruptedException IE) {} staticbkgrd.getGraphics().drawImage(background,0,0,TW,TH-30,null); resetbackground(); display.drawImage(canvas,0,0,null); // draws to screen } // init private void resetbackground() { brush.drawImage(staticbkgrd,0,30,null); // draw track lines brush.setColor(Color.blue); for(int i=1;i<=HN+1;i++) { brush.drawLine(0,(i*LW)-5,TW-1,(i*LW)-5); } // finish line: brush.setColor(Color.red); brush.drawLine(TW-15,0,TW-15,TH-1); // finish line } // resetbackground public void nextframe(int delay) // delay in ms { try { Thread.sleep(delay); } catch (InterruptedException IE) {} display.drawImage(canvas,0,0,null); // draws to screen resetbackground(); } // nextframe with ms delay public void displayStatus(String message) { Font oldfont = brush.getFont(); brush.setFont(new Font("Serif",Font.BOLD,24)); brush.drawString(message,TW/3,LW-10); brush.setFont(oldfont); } /* ---***-------------- YOUR CODE GOES BELOW ----------------***--- */ public int randint(int min, int max) { // should return random int between min and max, inclusive // find it in your notes } public void race(String[] names) { } // race public int determineLeader(racer[] H) { } // determineLeader } // class horserace