What is Fruit Day?
Rules
Example 1: MyFirstRobot
Example 2: Focus - Let's defeat MyFirstRobot
Example 3: FocusKiller - Beat 'Focus' perfectly!
Fight Result
Knowing Opponent's Strategy
Base Robot Class Details: Fruitday
Common Help For All Sub-platforms
Upload A Robot
Advanced Rules
Debugging
Member Variables, Initialization, and Using Java Utilities
Fruit Day is a sub-platform in Robotypo. Fruit Day hosts fights between Fruit Day robots.
You can create your own Fruit Day robots and upload them to this platform, and challenge other robots. A Fruit Day
Robot is simply a Java program, which normally consists of only a few lines of code.
Even you are not familiar with Java, you may create robots based on examples. Neither Java tool, nor IDE is a must.
Robots fight with others. Each match has two robots, and consists of multiple rounds. Before each round, each robot sets its strategy for the round. Your robot never knows for sure what the opponent's strategy is, and vice versa. It is up to you to create a strategy, and if necessary, analyze opponent's strategy and adjust yours to win.
- The team: The match consists of two teams (one robot controls one team). Each team has 3 peasants. Each peasant has 100 HP.
- Action: The match consists of 1000 rounds. In each round, each peasant chooses one and only one action. The action can be either HIT or HIDE.
- HIT: Choose a peasant (0, 1, or 2) in the opponent team to hit. If a peasant chooses to hit, then others can hit him in this round, too. The HIT action is assured to hit the target if it does not hide.
- HIDE: If a peasant chooses to hide, then others can not hit him in this round, and he can not hit others, too.
- Out-of-play: Each time a peasant is hit, its HP is reduced by one. If the HP decreases to 0, then the peasant can not throw fruit any more. It is considered as out-of-play.
- End of game: If all peasants in a team are out-of-play, the game ends and the opponent team wins. If there are too many rounds passed, the game ends, too. In this case, the winner is the team which has more total HP.
- Coward: If a peasant hides more than 3 rounds continuously, it is called coward and it is out-of-play.
Before each round, the strategy() method of each robot is called. In this method, your robot needs to set actions for each peasant in your team. When setting the strategy, a robot never knows for sure what the opponent's strategy is. So it is up to you to analysis opponent's strategy, and adjust yours. In the round, hit or miss is calculated, and member variables (e.g. HP) are updated to reflect the changes.
Example 1: MyFirstRobotTop Back
Example 2: Focus - Let's defeat MyFirstRobot
Example 3: FocusKiller - Beat 'Focus' perfectly!
Top Backpublic class MyFirstRobot extends Fruitday {
//This is the method called before each round.
public void strategy() {
for (int i = 0; i < 3; i++) { //For each peasant in our team,
Peasant p = myTeam[i];
p.action = random.nextInt(3); //Hit a random opponent peasant.
//You can also tell peasant to hide, like this:
//p.action = HIDE;
}
}
}
A simple strategy is enough to defeat MyFirstRobot: if everyone hit the same opponent, it will be hit many times and will be out of play soon. So the new robot - Focus - is created:
Top Back/**
* With the robot "Focus", all peasants in our team hit one
* opponent peasant intensively, so it will be out-of-play
* quickly. That's good for us.
*/
public class Focus extends Fruitday {
int focus = 0; //A member variable which stores our focus
public void strategy() {
//Get the opponent peasant at our focus
Peasant p = opponentTeam[focus];
//If it is out-of-play...
if (p.hp == 0
//OR: (we are smart) if it is hiding in the previous round...
|| p.action == HIDE) { //(The p.action stores the action of the peasant in the PREVIOUS round)
//Move the focus to the next one.
if (++focus > 2)
focus = 0;
}
//All fire at the focus!
for (int i = 0; i < 3; i++)
myTeam[i].action = focus;
}
}
'Focus' is smart, but it is too predictable. Let's defeat it PERFECTLY:
/**
* The robot Focus is good. However it is too predictable.
* Let's defeat it, simply, and *perfectly*.
*/
public class FocusKiller extends Fruitday {
int focus = 0;
public void strategy() {
for (int i = 0; i < 3; i++)
//If I'm at opponent's focus, I hide, otherwise I hit.
myTeam[i].action = i == focus ? HIDE : focus;
//Move focus.
if (++focus > 2)
focus = 0;
}
}
The fight result looks like "0:32". It means that after the fight, the first robot has 0 HP left, and the second robot has 32 HP left in total. The robot who has more total HP wins. In this case, it is the second robot. If a number is -1, error occurred in the corresponding robot, probably exception is thrown, or it is timeout during calculation.
The detailed fight result shows the exact action of each peasant. The result consists of blocks of each round, looks like this:
_0_ _1_ _2_ [1] HP 98 100 99 Action 0 0 0 Action 2 0 0 HP 97 100 100 [2] HP 98 100 96 Action 0 0 0 Action 2 2 2 HP 94 100 100
The number between [ ] is the round number. In this example, Round 1 and 2 are shown.
Details about Round 1 shown the example:The first row represents the HP of peasants in team 1.
The second row represents the actions of peasants in team 1.
The third row represents the actions of peasants in team 2.
The fourth row represents the HP of peasants in team 2.
The 3 columns to the right are for peasant 0, 1, and 2 respectively.
Note that HP is the HP after the round. In this example, all 3 peasants in team 1 hit at position 0. So in team 2, the peasant at position 0 has 97 HP (100-3). The peasant 0 in team 2 hits at position 2. So peasant 2 in team 1 has 99 HP (100-1). The peasant at position 1 and 2 in team 2 hit at position 0, so peasant 0 in team 1 has hp 98 (100-2).
You can record and analysis the strategy of your opponent robot, by reading the opponentTeam member in the robot class. Before each round (in the strategy() method), the member variables myTeam and opponentTeam represent the state at the end of the previous round. So myTeam[i].action is the action of your peasant (at position i), and opponentTeam[i].action is your opponent's action at position i.
You can analysis the strategy of your opponent robot. Before each round (at the beginning of each strategy() method call), the following member variables represent the state at the end of the previous round:
- opponentTeam
- myTeam
Each team object is an array of three elements, with type Peasant. For example:
- myTeam[0].action: the action this peasant was set. Could be HIDE (-1), or 0, 1, 2, which represents hitting at position 0, 1, 2 respectively.
- myTeam[0].hp: The HP left of peasant 0.
- myTeam[0].cowardCount: The count of continuous hidding.
All previous history records can also be retrieved from the history member variable. history[0] represents the state of round 0, history[i] represents the state of round 1, and so on. For example:
- history[0].myTeam: represents my team state after round 0. history[0].myTeam[0] refers to the first peasant in the team.
- history[0].opponentTeam: opponent team state after round 0
- history[1].myTeam: myTeam state in round 1
- ...
Further, you can create class member variables to form your own data structures and store your own data.
Further, you can create class member variables to form your own data structures and store your own data. For example, recording the opponent's actions of the last two rounds...
Read the next section Base Class Details: Fruitday for more details.
Read the comments for details.
- Peasant[] myTeam
- Peasant[] opponentTeam
- Random random
- int round
/**
* The base class for Fruitday robots.
*/
public abstract class Fruitday {
public static final int TOTAL_ROUNDS = 1000;
public static final int MAX_HP = 100;
/**
* Peasant actions
*/
public static final int HIDE = -1;
public static final int HIT0 = 0;
public static final int HIT1 = 1;
public static final int HIT2 = 2;
/**
* Max continuous HIDE count. If a peasant hides
* more than this number continuously, it's out of play.
*/
public static final int COWARD_LIMIT = 3;
/**
* A Peasant represents one peasant in
* a Fruitday team.
*/
public static class Peasant {
/**
* The action for this peasant. This value needs to be
* set in the <code>strategy()</code> method.
* Possible values are:
* <li> HIDE: hide.</li>
* <li> 0: hit the first peasant in the opponent team.</li>
* <li> 1: hit the second peasant in the opponent team.</li>
* <li> 2: hit the third peasant in the opponent team.</li>
*/
public int action;
/**
* The hit points left for this peasant. If <code>hp</code> is 0, the
* peasant is out of play, and can not throw fruit anymore.
* This is a read only value, and changing it has no effect.
*/
public int hp;
/**
* The coward count for this peasant. Read only.
* This value goes up each time when a peasant hides. If it's more
* than 3, this peasant is considered as a coward and is out of play.
* By throwing at one opponent peasant (set <code>action</code>), this value
* is reset to 0.
* This is a read only value, and changing it has no effect.
*/
public int cowardCount;
/**
* Copy data from the given peasant
* @param p
*/
public void copy(Peasant p);
}
/**
* The 3 peasants in our team. In each round, you need to
* set <code>action</code> of each peasant in the <code>strategy()</code> method.
* Their member variables represent the state at the end of the previous round.
* Read them for strategy.
*/
public Peasant[] myTeam;
/**
* The 3 peasants in the opponent team.
* Their member variables represent the state at the end of the previous round.
* These values are read only, and changing them has no effect.
*/
public Peasant[] opponentTeam;
/**
* Utility for generating random values.
*/
protected Random random;
/**
* Helper. Stores the current round number.
*/
public int round;
/**
* Set the hit or hide strategy (the <code>action</code> member) for
* each peasant in our team (<code>myTeam</code>).
*
* This method is called before each round.
*
* Read <code>opponentTeam</code> to analysis the opponent.
*/
public abstract void strategy();
//////////////////////////////////////////////////////////
// Helper for history records
//////////////////////////////////////////////////////////
public static class Record {
public Peasant[] myTeam;
public Peasant[] opponentTeam;
}
/**
* Stores all previous records.
*/
public Record[] history;
}
This part of help applies to app sub-platforms in Robotypo. It tells you some common rules of creating robots.
Click My Robots! in the left navigation area, you may need to login with Google account or an Open ID. Then click the Create button. Example code is already there. You can create your robots base on that.
Besides the basic rules, there are some other advanced rules:
Top Back
- Time limit: Each strategy() call must not take too long, and the accumulated time a robot consumes must not take too long. Exceeding the limit will result exception from the robot. This rule protects the system from being blocked by deadlock robots. Normally the time is enough. For example, the time limit per round for each robot is about 3 seconds, and the total accumulated time limit for each robot is about 15 seconds. However, since robot code runs in a complex and secured environment, it runs much slower than on your PC. So optimize your code, and use simple structure as much as possible (e.g. int[]).
- Exception: If the action is out of range, (not HIDE, 0, 1, or 2), then exception occurs and the robot loses. Also, avoid modifying things except the action. For example, surely it is OK to set myTeam to null from perspective of Java language, but that will cause your robot exceptions.
When you need this, you're likely creating some really good robots. Refer to the guide Setup Debug Environment for details.
Since each robot is a Java class, you can create member variables to record and analyze opponent strategy. However, note that all opponent information of the previous round is already stored in some member variables, and you do not need to create additional member variables for that. Refer to the base class document of each platform for details. In addition, custom funtions, inner classes, and Java utilities can also be used. For example, the collection classes in package java.util. They are imported by default.
If you want to do some custom initialization, you can create a class constructor function to do this, or just inside a non-static initialization block (recommended). For example:
public class MyRobot extends ... {
// A custom class
static class MyData {
//...
}
// A custom member variable
List<MyData> items = new ArrayList<MyData>();
// Initialization block
{
// Your class initialization code here
}
//A custom function
void analyzeOpponentStrategy() {
//...
}
public void strategy() {
analyzeOpponentStrategy();
// Other stuff
// ...
}
}
This part of help applies to app sub-platforms in Robotypo. It tells you some common rules of creating robots.
Click My Robots! in the left navigation area, you may need to login with Google account or an Open ID. Then click the Create button. Example code is already there. You can create your robots base on that.
Besides the basic rules, there are some other advanced rules:
Top Back
- Time limit: Each strategy() call must not take too long, and the accumulated time a robot consumes must not take too long. Exceeding the limit will result exception from the robot. This rule protects the system from being blocked by deadlock robots. Normally the time is enough. For example, the time limit per round for each robot is about 3 seconds, and the total accumulated time limit for each robot is about 15 seconds. However, since robot code runs in a complex and secured environment, it runs much slower than on your PC. So optimize your code, and use simple structure as much as possible (e.g. int[]).
- Exception: If the action is out of range, (not HIDE, 0, 1, or 2), then exception occurs and the robot loses. Also, avoid modifying things except the action. For example, surely it is OK to set myTeam to null from perspective of Java language, but that will cause your robot exceptions.
When you need this, you're likely creating some really good robots. Refer to the guide Setup Debug Environment for details.
Since each robot is a Java class, you can create member variables to record and analyze opponent strategy. However, note that all opponent information of the previous round is already stored in some member variables, and you do not need to create additional member variables for that. Refer to the base class document of each platform for details. In addition, custom funtions, inner classes, and Java utilities can also be used. For example, the collection classes in package java.util. They are imported by default.
If you want to do some custom initialization, you can create a class constructor function to do this, or just inside a non-static initialization block (recommended). For example:
public class MyRobot extends ... {
// A custom class
static class MyData {
//...
}
// A custom member variable
List<MyData> items = new ArrayList<MyData>();
// Initialization block
{
// Your class initialization code here
}
//A custom function
void analyzeOpponentStrategy() {
//...
}
public void strategy() {
analyzeOpponentStrategy();
// Other stuff
// ...
}
}