How to add a runner to an array of results - java

I have been trying to figure out how to add runner information into an array of runner information. It should contain at most 100 runners.
This is part of a larger project that must fulfill these requirements:
Operations (methods):
• A constructor that takes in a race name and distance.
• Getters and setters for both the name and distance instance variables.
• Method to return the count of the number of RunnerResult objects added to the array.
• Method to add a RunnerResult to the array (given an instance of Runner and the runner’s finishing time).
• Methods to get a RunnerResult object; one that takes in the position in which the RunnerResult was added (to directly access the object from the array) and one that takes in a runner name (to use to search for the matching runner). The first runner’s index is 0, the second is 1, etc.
• A method with conditional logic to give a count of all runners for a certain category (youth, adult, senior, male, female, all) triggered by a flag passed in as a whole number (1, 2, 3, 4, 5, 6, respectively, implemented as public constants). A similar method provides the average race result (time to finish race) for each potential category.
• A method with conditional logic finds runners with a race time less than the specified minutes per mile. For example, find all runners who finished the race with a time of less than 8 minutes per mile.
• A toString method that simply gives the race name, race distance, a count of total runners in the race, and the average time of all runners in the race.
So far, this is what I have:
public class Race
{
// instance variables
private String name;
private double distance;
private int nextPos;
private RunnerResult [] results;
// public constants
/**
* Flag to signify YOUTH.
*/
public static final int YOUTH = 1;
/**
* Flag to signify ADULT.
*/
public static final int ADULT = 2;
/**
* Flag to signify SENIOR.
*/
public static final int SENIOR = 3;
/**
* Flag to signify MALE.
*/
public static final int MALE = 4;
/**
* Flag to signify FEMALE.
*/
public static final int FEMALE = 5;
/**
* Flag to signify ALL.
*/
public static final int ALL = 6;
/**
* Array limit.
*/
public static final int MAX_COUNT = 100;
/**
* Constructor for objects of class Race.
*
* #param inName the race name.
* #param inDist the distance of the race.
*
*/
public Race(String inName, double inDist)
{
// initialize the instance variables and
// empty array of results, initalize nextPos
this.name = inName;
this.distance = inDist;
RunnerResult[] results = new RunnerResult[100];
}
/**
* Set the race Name.
*
* #param inName the race name.
*
*/
public void setName(String inName)
{
this.name = inName;
}
/**
* Get the race Name.
*
* #return String The race name.
*
*/
public String getName()
{
return this.name;
}
/**
* Set the race distance.
*
* #param inDist the distance of the Race.
*
*/
public void setDist(double inDist)
{
this.distance = inDist;
}
/**
* Get the race distance.
*
* #return double the distance of the race.
*
*/
public double getDist()
{
return this.distance;
}
/**
* Add a runner to the results
* (runners are NOT entered in order of finish).
*
* #param inChip the runner's chip id.
* #param inRunner a Runner object.
* #param inStart the start time for the runner.
* #param inEnd the end time for the runner.
*
*/
public void addRunner(String inChip, Runner inRunner, Time inStart, Time inEnd)
{
if (this.nextPos < MAX_COUNT)
{
// set the instance field element to a "copy" of passed-in object
// add to array, increment counter
for(int i = 0; i < results.length; i++);
{
RunnerResult[] results = { copyinChip, copyinRunner, copyinStart,
copyinEnd };
i++;
}
}
}
}
I just cannot figure out how to get these values into the array. (I get an incompatible type error. Any input would be greatly appreciated.

two things here.
1.) when you re-declare results, you are not referencing the same object that you declare as a field, but an entirely new object that then has no purpose, because it only lives within addRunner.
2.) When you assign results = { ---, ---, ---, ---}; You aren't adding a new runner to the array. Rather, you are reassigning the entire array every single time you do that loop. You would want to create a new RunnerResult object, add the necessary data to it, and then put that at results[];
An example here:
public void addRunner(String inChip, Runner inRunner, Time inStart, Time inEnd)
{
if (this.nextPos < MAX_COUNT)
{
// set the instance field element to a "copy" of passed-in object
// add to array, increment counter
for(int i = 0; i < results.length; i++);
{
results[i] = new RunnerResult(<your params>);
}
}
}

Related

Creating boats in battleship game

I am creating a battleship game in one of my classes. I am having trouble on creating the "PTBoat" and placing it on the screen. I have a 10x10 board and need help creating an initializing the boats. The size of the PTBoat needs to be 2 spots on the board. I think I have the random direction, column, and row figured out but am stuck on how to call it in the board class. The first portion is the PTBoat class and the second half of code is the Board Class. The main method has been fully written for me so I did not include that.
/**
* Class for the PT Boat of the Battleship Game.
* Superclass: Ship
* Subclasses: none
* Attributes: String name
* int charges;
* name = "PT Boat"
* size = 2
* charges - number of depth charges on this PT Boat
* You must declare the attributes, complete the constructors and
* write any necessary getters and setters
*/
public class PTBoat extends Ship
{
// instance variables
public String PTBoat;
public int charges = 2;
public int size = 2;
/**
* Constructors for objects of class Carrier
*/
public PTBoat(String name, int size)
{
}
public PTBoat(int row, int col, int dir)
{
row = (int)(Math.random() * 10 + 1);
col = (int)(Math.random() * 10 + 1);
dir = (int)(Math.random() * 2 + 1);
}
}
/**
* Board class for the Battleship game.
*
* A board is an nxn array containing one each of: Carrier
* Battleship
* Destroyer
* Submarine
* PTBoat
*/
import java.util.Scanner;
public class Board
{
// class variables
// If the number of ships is changed, the constructor must be
// updated as well
// When debug is true, positions of ships will be shown when the
// board is displayed. This is helpful when testing the game since
// you won't have to guess the ships' locations.
final static boolean debug = true;
final static int board_size = 10;
final static int num_ships = 5;
// Characters printed when the board is displayed. Not all are used.
final static char hit = 'H';
final static char miss = 'M';
final static char used = 'S';
final static char blank = ' ';
final static char sunk = 'X';
// instance variables - replace the example below with your own
private char[][] board = new char[board_size][board_size];
private int num_sunk;
private Ship[] ships = new Ship[num_ships];
private Scanner scanIn;
/**
* Default constructor for objects of class Board
*/
public Board(Scanner s)
{
// initialise instance variables
scanIn = s;
num_sunk = 0;
initializeBoard();
// create the ships
ships[0] = new PTBoat();
hideShip(0);
ships[1] = new Submarine();
hideShip(1);
ships[2] = new Destroyer();
hideShip(2);
ships[3] = new Battleship();
hideShip(3);
ships[4] = new Carrier();
hideShip(4);
}
You have some misconceptions for the class PTBoat, let's start with a few:
One of the attributes should be the name of the ship, in this case, "PT Boat", but you defined this:
public String PTBoat;
So your variable is named PTBoat, the same that the class which is wrong. It should be named "name", like this:
public String name;
The first constructor has two arguments so when called it will be used to give values to the related attributes, like this:
public PTBoat(String name, int size)
{
this.name = name;
this.size = size;
}
The second constructor looks like it's intended to set up the attributes row, col and dir, that you should define in the class. With your code you are reassigning the value of the variables that you receive, which is useless. Later when you instantiate the ship from the Board you should use one of the constructors like this:
ships[0] = new PTBoat("MyAwesomePTBoat", 2);
In your instructions is also mentioned that you need to create getters and setters, so your variables look like they should be private, not public. A getter is a simple method that returns the value of the variable, a setter is used to set the value to a value given. Those methods are public so they can be called from outside the class where they are defined.
Anyway, I would recommend you have a look at any basic Java tutorial to understand better all those concepts.

Java problem - method undefined even though I already defined it in the package

I'm a total beginner in Java and I'm working on an assignment that's largely prefabricated/preformatted code, but I can't get it to work. In Eclipse, I get an error saying "Method cardToString(MyCard) is undefined for the type MyCardTester" before I even run it. I've looked at similar questions on Stackoverflow,
(Eclipse is telling me a method is undefined when it clearly is in fact defined, "The method is not defined for the type" error in simple program in java)
and they have different problems from me. I think that my problem may be with my classpath or run configuration, but those settings seem fine. Here is the code:
Here's the first class:
package EllevensGame;
import EllevensGame.MyCard;
import java.lang.String;
/**
* This is a class that tests the Card class.
*/
public class MyCardTester {
/**
* The main method in this class checks the Card operations for consistency.
* #param args is not used.
*/
public static void main(String[] args) {
MyCard testCard = new MyCard("King", "Hearts", 13);
String printStuff = cardToString(testCard);
System.out.println(printStuff);
}
}
Second class:
package EllevensGame;
/**
* MyCard.java
*
* <code>MyCard</code> represents a playing card.
*/
import java.lang.String;
public class MyCard {
/**
* String value that holds the suit of the card
*/
protected String suit;
/**
* String value that holds the rank of the card
*/
protected String rank;
/**
* int value that holds the point value.
*/
protected int pointValue;
/**
* Creates a new <code>Card</code> instance.
*
* #param cardRank a <code>String</code> value
* containing the rank of the card
* #param cardSuit a <code>String</code> value
* containing the suit of the card
* #param cardPointValue an <code>int</code> value
* containing the point value of the card
*/
public MyCard(String cardRank, String cardSuit, int cardPointValue) {
//MyCard newCard = new MyCard(cardRank, cardSuit, cardPointValue); Not sure if this is right or not
}
/**
* Accesses this <code>Card's</code> suit.
* #return this <code>Card's</code> suit.
*/
public String suit() {
return suit;
}
/**
* Accesses this <code>Card's</code> rank.
* #return this <code>Card's</code> rank.
*/
public String rank() {
return rank;
}
/**
* Accesses this <code>Card's</code> point value.
* #return this <code>Card's</code> point value.
*/
public int pointValue() {
return pointValue;
}
/** Compare this card with the argument.
* #param otherCard the other card to compare to this
* #return true if the rank, suit, and point value of this card
* are equal to those of the argument;
* false otherwise.
*/
public boolean matches(MyCard otherCard) {
if (otherCard.pointValue == (pointValue()) && (otherCard.rank.equals(rank)) && (otherCard.suit.equals(suit))) {
return true;
}
else {return false;}
}
/**
* Converts the rank, suit, and point value into a string in the format
* "[Rank] of [Suit] (point value = [PointValue])".
* This provides a useful way of printing the contents
* of a <code>Deck</code> in an easily readable format or performing
* other similar functions.
*
* #return a <code>String</code> containing the rank, suit,
* and point value of the card.
*/
//#Override
public String cardToString(MyCard newCard) {
String pointstring = String.valueOf(pointValue);
String print = rank + " of " + suit + pointstring;
return print;
}
}
Final note: the code is supposed to create a "card" object for a card game (Ellevens).
Thanks!!
cardToString is a method in MyCard, you must invoke it through the reference. Change
String printStuff = cardToString(testCard);
to
String printStuff = testCard.cardToString(testCard);
Although it might be better to make that method return a String based on the this instance (which would make more sense).
public String cardToString() {
return rank + " of " + suit + pointValue;
}
And then
String printStuff = testCard.cardToString();
I then fixed your constructor
public MyCard(String cardRank, String cardSuit, int cardPointValue) {
this.rank = cardRank;
this.suit = cardSuit;
this.pointValue = cardPointValue;
}
And ran it getting
King of Hearts13

Retrieve data from an ArrayList item

Apologies in advance, I am new to Java and I am using someone else's code for the most part so please bear with me. I have looked around but couldn't find anything to help my problem
I've retrieved an ArrayList from a method and then I've attempted to write a foreach loop to retrieve a specific piece of data from what is an 'Observation' below.
For whatever reason it won't allow me to retrieve any of the data stored inside an observation when accessing through the ArrayList.
ArrayList<Observation>[] npcPositions = stateObs.getNPCPositions();
Vector2d playerPosition = stateObs.getAvatarPosition();
int npcCount = npcPositions.length;
for (int i = 0; i <= npcCount; i++)
{
if (playerPosition.x == npcPositions[i].position)
{
}
}
position being a value within the Observation but I get the error that it cannot be resolved or is not a field. Part of the observation class is below and I can not access any of these variables doing what I'm currently doing.
public class Observation implements Comparable<Observation>
{
/**
* Category of this observation (static, resource, npc, etc.).
*/
public int category;
/**
* Type of sprite of this observation.
*/
public int itype;
/**
* unique ID for this observation
*/
public int obsID;
/**
* Position of the observation.
*/
public Vector2d position;
/**
* Reference to the position used for comparing this
* observation with others.
*/
public Vector2d reference;
So what do I need to use to access those variables. I noticed that I have to use [] when I want to store data from stateObs.getNPCPositions and that seems to be the reason why other examples weren't working for me but I am unsure on how to fix it.
UPDATE
The original issue seems to be fixed, however when attempting to retrieve the length of the ArrayList, I get nullpointerexception. How can I get the number of items to be able to run through them in the loop each time.
UPDATE #2
/**
* Returns a list of observations of NPC in the game. As there can be
* NPCs of different type, each entry in the array corresponds to a sprite type.
* Every ArrayList contains a list of objects of type Observation.
* Each Observation holds the position, unique id and
* sprite id of that particular sprite.
*
* #return Observations of NPCs in the game.
*/
public ArrayList<Observation>[] getNPCPositions()
{
return model.getNPCPositions(null);
}
/**
* Returns a list of observations of NPC in the game. As there can be
* NPCs of different type, each entry in the array corresponds to a sprite type.
* Every ArrayList contains a list of objects of type Observation, ordered asc. by
* distance to the reference passed. Each Observation holds the position, sprite type id and
* sprite id of that particular sprite.
*
* #param reference Reference position to use when sorting this array,
* by ascending distance to this point.
* #return Observations of NPCs in the game.
*/
public ArrayList<Observation>[] getNPCPositions(Vector2d reference)
{
return model.getNPCPositions(reference);
}
This:
ArrayList<Observation>[] npcPositions = stateObs.getNPCPositions();
is getting an array of ArrayList. You can get a single ArrayList from index i of the array using:
ArrayList<Observation> list = npcPositions[i];
You can get the Observation at index j of your list using:
Observation obs = list.get(j);
Or you can use them in combination:
Observation obs = npcPositions[i].get(j);
In line:
npcPositions[i].position
Is an array of ArrayList which does not have any property position. Possibly you would try:
npcPositions[i].get(0).position
Edited:
As you said that this line gives NPE:
int npcCount = npcPositions.length;// possibly npcPositions is null
Below line is executed to get the array list:
public ArrayList<Observation>[] getNPCPositions()
{
return model.getNPCPositions(null);//<-- note this, possibly model is also null
}
I am not sure what you are doing in the first two lines of your code, but assumming that what you are doing is correct then the problem lies with your if statement. You are trying to test if a Vector2D.x is equal to a Vector2D which can never happen. try doing this
for(int i = 0; i < npcCount; < i++)
{
if(playerPosition == npcPositions.get(i).position)
{
//do something here
}
}
or you can try this
for(int i = 0; i < npcCount; < i++)
{
if(playerPosition.x == npcPositions.get(i).position.x)
{
//do something here
}
}

JasperReport: How to use subreport return values as input for Main Report Variable Calculation

Scenario:
I've two reports: Main Report (let's call it, A) and sub-report (let's call it, B).
Report A contains sub-report B at the detail band, so sub-report B is displayed for each element at the Report A datasource. Sub-report B also returns a variable to the Main report A.
What I want is to sum those return values from sub-report B and totalize them at the Main report summary.
To do that, I have tried to create a new report variable that sum those returns values... Something like this:
However, I've found that such variables expression are always evaluated before the band detail is rendered, so I always miss the first sub-report return value...
Sadly, the evaluation time (as this link says) cannot be changed on those kind of variables, so I'm stuck...
After been struggling with this for some hours... and searching the internet for a solution... I came with a Workaround (the enlightening forums were these ones: one and two).
First, you need to define a java Class Helper that allows you calculate some arithmetic operation, in my case a Sum operation. I defined these classes:
package reports.utils;
import java.util.Map;
/**
* Utility that allows you to sum Integer values.
*/
public class SumCalculator {
/**
* Stores a map of {#code SumCalculator} instances (A Map instance per thread).
*/
private static final ThreadLocalMap<String, SumCalculator> calculatorsIndex = new ThreadLocalMap<>();
/**
* The sum total.
*/
private int total = 0;
/**
* No arguments class constructor.
*/
private SumCalculator() {
super();
}
/**
* Instance a new {#code SumCalculator} with the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return the new {#code SumCalculator} instance
*/
public static SumCalculator get(String id) {
Map<String, SumCalculator> map = calculatorsIndex.get();
SumCalculator calculator = map.get(id);
if (calculator == null) {
calculator = new SumCalculator();
map.put(id, calculator);
}
return calculator;
}
/**
* Destroy the {#code SumCalculator} associated to the given ID.
*
* #param id {#code SumCalculator}'s ID
* #return {#code null}
*/
public static String destroy(String id) {
Map<String, SumCalculator> map;
map = calculatorsIndex.get();
map.remove(id);
if (map.isEmpty()) {
calculatorsIndex.remove();
}
return null;
}
/**
* Resets the {#code SumCalculator} total.
*
* #return {#code null}
*/
public String reset() {
total = 0;
return null;
}
/**
* Adds the given integer value to the accumulated total.
*
* #param i an integer value (can be null)
* #return {#code null}
*/
public String add(Integer i) {
this.total += (i != null) ? i.intValue() : 0;
return null;
}
/**
* Return the accumulated total.
*
* #return an Integer value (won't be null, never!)
*/
public Integer getTotal() {
return this.total;
}
}
package reports.utils;
import java.util.HashMap;
import java.util.Map;
/**
* Thread Local variable that holds a {#code java.util.Map}.
*/
class ThreadLocalMap<K, V> extends ThreadLocal<Map<K, V>> {
/**
* Class Constructor.
*/
public ThreadLocalMap() {
super();
}
/* (non-Javadoc)
* #see java.lang.ThreadLocal#initialValue()
*/
#Override
protected Map<K, V> initialValue() {
return new HashMap<>();
}
}
Second, at your jasper report, you need to define four text fields:
1) A text field that iniatializes your calculator; it should be (ideally) at the title section of the report and should have an expression like this: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").reset(). This text field should have the evaluation time: NOW.
2) A text field that calls the increment function (i.e. SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").add($V{SUB_REPORT_RETURN_VALUE}). This text field will reside at your detail band, after the subreport element; and it should have the evaluation time: BAND (this is very important!!)
3) A text field that prints the calculator total. This text field will reside at your summary band, it will evaluate to NOW. Its expression will be: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").getTotal()
4) A text field that destroy the calculator. This text field will also reside at your summary band and must appear after the text field 3. The text field should have an expression like: SumCalculator.destroy("$V{SUB_REPORT_RETURN_VALUE}"). This text field should have the evaluation time: NOW.
Also, the text fields: 1, 2, and 4, should have the attribute "Blank when Null", so they will never be printed (that's why those java operations always return null).
And That's it. Then, your report can look something like this:
if i understand the problem, you can not summarize the amount returned by the sub report in the main report, i had the same problem and i solved in this way.
1.- Create a class which extends from net.sf.jasperreports.engine.JRDefaultScriptlet. and override the method beforeReportInit()
this is the code from this class.
package com.mem.utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
public class SumarizacionSubtotales extends JRDefaultScriptlet {
private final Log log = LogFactory.getLog(getClass());
private Double total;
public Double getTotal() {
return total;
}
public Double add(Double cantidad) {
if(log.isDebugEnabled())log.debug("AGREGANDO LA CANTIDAD : " + cantidad);
this.total += cantidad;
return cantidad;
}
#Override
public void beforeReportInit() throws JRScriptletException {
if(log.isDebugEnabled())log.debug("beforeReportInit");
total = 0.0D;
}
}
2.- add your project's jar in your ireport's classpath.
3.- Replace the class of the REPORT scriptlet.
in the properties with your class.
3.- add in the group footer where you want to print the value returned by the sub-report a textfield with the following expression.
$P{REPORT_SCRIPTLET}.add( $V{sum_detalles} )
In this case $V{sum_detalles} is a variable in the main report which contains the value returned by the sub-report.
4.- Add in the Last page footer another textfield with the following expression.
$P{REPORT_SCRIPTLET}.getTotal()

java synchronization mechanism

A web application queries an external server. If more than 80% of the requests to the server send within the past 'n' minutes fails, then the web applicatoin should back out from querying the server and perform other logic. I could think of an atomic integer being incremented by the failed requests. But i dont think atomic integer supports any action to be executed if the value of the atomic integer reaches a particular value. Is there any smarter way to do this in java?
Well, after updating your atomic integer, you could check its value and if the 80% is met, then you could take action (like flagging that server as 'weak responding or so'). If you are working in a multi-threaded environment, there is nothing wrong with your solution.
Another solution is to have the threads call a synchronized method to increase a non-atomic integer and perform the check. That integer would have to be an attribute of the class to which this method belongs.
If you want to monitor events in the last 'N' minutes you need more than just an integer. You need to know what was happening 'N' minutes ago so you can keep your success level estimate correct.
Here is one way to do it:
import java.util.LinkedList;
/**
* Class that monitors outcomes for until the proportion of successes in a
* specified time window falls below a trigger level, at which point an action
* is invoked.
*
* #author Simon
*/
public class SuccessMonitor {
/** An outcome */
static class Outcome {
/** Time of outcome */
final long eventTime = System.currentTimeMillis();
/** True for success, false for failure */
boolean outcome;
}
/** The action to invoke when there are two few successes */
private final Runnable action_;
/** The history of outcomes in the time window */
private final LinkedList<Outcome> events_ = new LinkedList<Outcome>();
/** Number of successes in the time window */
private int goodCount_ = 0;
/** Synchronization lock */
private final Object lock_ = new Object();
/** Length of the time window in milliseconds */
private final long trackTime_;
/** The success proportion at which to invoke the action */
private final double triggerLevel_;
/**
* New monitor
*
* #param trackTime
* number of milliseconds to retain history for
* #param triggerLevel
* the level at which to invoke the action
* #param action
* the action
*/
public SuccessMonitor(long trackTime, double triggerLevel, Runnable action) {
trackTime_ = trackTime;
triggerLevel_ = triggerLevel;
action_ = action;
}
private void check(boolean result) {
// create a new outcome
Outcome out = new Outcome();
out.outcome = result;
double level;
synchronized (lock_) {
// add the new outcome
goodCount_ += (result) ? 1 : 0;
events_.addLast(out);
// remove expired outcomes
long expire = System.currentTimeMillis() - trackTime_;
while( (!events_.isEmpty())
&& (events_.getFirst().eventTime < expire) ) {
out = events_.removeFirst();
goodCount_ -= (out.outcome) ? 1 : 0;
}
// Calculate the success level.
if (events_.isEmpty()) {
// if empty assume ok
level = 1.0;
} else {
// calculate success level
level = (double) goodCount_ / events_.size();
}
}
// if level has fallen too low, invoke action
if (level < triggerLevel_) action_.run();
}
/**
* Notify this monitor of a failure.
*/
public void fail() {
check(false);
}
/**
* Reset this monitor, causing it to discard all currently stored history.
*/
public void reset() {
synchronized (lock_) {
events_.clear();
goodCount_ = 0;
}
}
/**
* Notify this monitor of a success.
*/
public void success() {
check(true);
}
}

Categories