Difference between revisions of "Yatagan/Source"
< Yatagan
Jump to navigation
Jump to search
m (→Development Version: Minor edit.) |
m (→Development Version: Minor edit.) |
||
Line 1: | Line 1: | ||
== Development Version == | == Development Version == | ||
− | Codesize: | + | Codesize: 248 |
<syntaxhighlight> | <syntaxhighlight> | ||
/* | /* | ||
− | Yatagan 1.1.4 by Skilgannon & Sheldor ; Release date: 2013/05/ | + | Yatagan 1.1.4 by Skilgannon & Sheldor; Release date: 2013/05/09 |
The yatagan is a short sabre which was used extensively in the Ottoman Empire. | The yatagan is a short sabre which was used extensively in the Ottoman Empire. | ||
− | Codesize: | + | Codesize: 248 bytes without any colors |
Credits: | Credits: | ||
Line 24: | Line 24: | ||
public static final double DESIRED_BULLET_POWER = 2.0; | public static final double DESIRED_BULLET_POWER = 2.0; | ||
− | + | //round to nearest multiple of 0.33333... | |
public static final double BULLET_POWER = (int)(DESIRED_BULLET_POWER*3 + 0.5)/3.0; | public static final double BULLET_POWER = (int)(DESIRED_BULLET_POWER*3 + 0.5)/3.0; | ||
public static final int BULLET_VELOCITY = (int)(20 - 3 * BULLET_POWER); | public static final int BULLET_VELOCITY = (int)(20 - 3 * BULLET_POWER); | ||
− | public static final int MAX_MATCH_LENGTH = | + | public static final int MAX_MATCH_LENGTH = 40; //Keep this under 128 to save a byte. SHELDOR: A maximum match length of 40 will make the bot slower, but it may help APS. |
public static final int ORBIT_DISTANCE = 220; | public static final int ORBIT_DISTANCE = 220; | ||
public static final int DISTANCE_FACTOR = 3000; | public static final int DISTANCE_FACTOR = 3000; | ||
Line 44: | Line 44: | ||
public static final char RANDOM = 29; | public static final char RANDOM = 29; | ||
− | //Global variables. | + | //Global variables. |
static double direction; | static double direction; | ||
static double enemyEnergy; | static double enemyEnergy; | ||
Line 52: | Line 52: | ||
public void run() | public void run() | ||
{ | { | ||
− | + | //Skilgannon: sacrifice this for anti-rambot code | |
− | + | //setAdjustGunForRobotTurn(true); | |
− | + | //Start spinning radar and initialize direction to infinity. | |
setTurnRadarRightRadians(direction = Double.POSITIVE_INFINITY); | setTurnRadarRightRadians(direction = Double.POSITIVE_INFINITY); | ||
} | } | ||
Line 61: | Line 61: | ||
public void onScannedRobot(ScannedRobotEvent e) | public void onScannedRobot(ScannedRobotEvent e) | ||
{ | { | ||
− | + | //Local variables. | |
int integer = MAX_MATCH_LENGTH; | int integer = MAX_MATCH_LENGTH; | ||
double absoluteBearing; | double absoluteBearing; | ||
Line 78: | Line 78: | ||
setAhead(direction); | setAhead(direction); | ||
− | + | //Record the current enemy lateral velocity. | |
enemyHistory = String.valueOf((char) (e.getVelocity() * (Math.sin(e.getHeadingRadians() - (absoluteBearing = e.getBearingRadians() + getHeadingRadians()))))).concat(enemyHistory); | enemyHistory = String.valueOf((char) (e.getVelocity() * (Math.sin(e.getHeadingRadians() - (absoluteBearing = e.getBearingRadians() + getHeadingRadians()))))).concat(enemyHistory); | ||
− | + | //Pattern Matching. | |
− | + | //Find the longest match allowable in the enemy history. | |
− | while((matchPosition = enemyHistory.indexOf(enemyHistory.substring(0, integer | + | while((matchPosition = enemyHistory.indexOf(enemyHistory.substring(0, --integer), 64)) < 0); |
− | + | //Stay mostly perpendicular to the enemy, but try to maintain a distance of ORBIT_DISTANCE pixels. | |
− | + | //If DISTANCE_FACTOR is smaller it tries harder to get to the desired distance, but may 'SpinBot' if it is too small. | |
setTurnRightRadians(Math.cos(e.getBearingRadians() + | setTurnRightRadians(Math.cos(e.getBearingRadians() + | ||
((ORBIT_DISTANCE - (integer = (int)(e.getDistance()))) * (getVelocity() / DISTANCE_FACTOR)) | ((ORBIT_DISTANCE - (integer = (int)(e.getDistance()))) * (getVelocity() / DISTANCE_FACTOR)) | ||
)); | )); | ||
− | //Fire BULLET_POWER power bullets most of the time, but use higher power bullets when the distance is less than ANTI_RAMBOT_DISTANCE. | + | //Fire BULLET_POWER power bullets most of the time, but use higher power bullets when the distance is less than ANTI_RAMBOT_DISTANCE. |
− | setFire(BULLET_POWER + (ANTI_RAMBOT_DISTANCE/integer)); | + | //This greatly improves scores against rambots and other extremely aggressive bots. |
− | + | setFire(BULLET_POWER + (ANTI_RAMBOT_DISTANCE / integer)); | |
+ | |||
+ | //Assume that the enemy will repeat their movements in the ticks following the recording of the original pattern. | ||
+ | //Generate a firing angle based on that assumption. | ||
do | do | ||
{ | { | ||
+ | //Go through the log of enemy movements right after the original pattern was recorded. | ||
+ | //Add the Angular Velocities directly to the absoluteBearing variable. | ||
absoluteBearing += ((short) enemyHistory.charAt(--matchPosition)) / e.getDistance(); | absoluteBearing += ((short) enemyHistory.charAt(--matchPosition)) / e.getDistance(); | ||
} | } | ||
− | while ((integer -= BULLET_VELOCITY) > 0); | + | while ((integer -= BULLET_VELOCITY) > 0); //Keep projecting the enemy's movement forward until our bullet would reach their predicted location. |
− | + | //Aim at the predicted target. | |
setTurnGunRightRadians(Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians())); | setTurnGunRightRadians(Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians())); | ||
− | + | //Infinite radar lock. | |
setTurnRadarLeftRadians(getRadarTurnRemainingRadians()); | setTurnRadarLeftRadians(getRadarTurnRemainingRadians()); | ||
} | } |
Revision as of 14:15, 9 May 2013
Development Version
Codesize: 248
/*
Yatagan 1.1.4 by Skilgannon & Sheldor; Release date: 2013/05/09
The yatagan is a short sabre which was used extensively in the Ottoman Empire.
Codesize: 248 bytes without any colors
Credits:
Pattern Matching code from simonton.WeekendObsession_S and mld.Moebius, heavily modified.
And a general thanks to all open source bot authors and contributors to the RoboWiki.
Yatagan is open source and released under the terms of the RoboWiki Public Code License (RWPCL) - Version 1.1.
See license here: http://robowiki.net/wiki/RWPCL
*/
package jk.sheldor.nano;
import robocode.*;
import robocode.util.Utils;
public class Yatagan extends AdvancedRobot{
public static final double DESIRED_BULLET_POWER = 2.0;
//round to nearest multiple of 0.33333...
public static final double BULLET_POWER = (int)(DESIRED_BULLET_POWER*3 + 0.5)/3.0;
public static final int BULLET_VELOCITY = (int)(20 - 3 * BULLET_POWER);
public static final int MAX_MATCH_LENGTH = 40; //Keep this under 128 to save a byte. SHELDOR: A maximum match length of 40 will make the bot slower, but it may help APS.
public static final int ORBIT_DISTANCE = 220;
public static final int DISTANCE_FACTOR = 3000;
public static final int ANTI_RAMBOT_DISTANCE = 127; //Keep this under 128 to save a byte.
//NB! Generate new RANDOM when changing ORBIT_DISTANCE!
/*public static void main(String[] args){
System.out.println("RANDOM = " + (int)Math.round(3.0/(0.6*Math.sqrt((20 - 3*2.5)/ORBIT_DISTANCE) - 0.04)));
}//*/
public static final char ONE_WAY_ORBIT = 65535;
public static final char REVERSE_ON_ENEMY_FIRE = 0;
public static final char RANDOM = 29;
//Global variables.
static double direction;
static double enemyEnergy;
static int deathCount;
public void run()
{
//Skilgannon: sacrifice this for anti-rambot code
//setAdjustGunForRobotTurn(true);
//Start spinning radar and initialize direction to infinity.
setTurnRadarRightRadians(direction = Double.POSITIVE_INFINITY);
}
public void onScannedRobot(ScannedRobotEvent e)
{
//Local variables.
int integer = MAX_MATCH_LENGTH;
double absoluteBearing;
int matchPosition;
//Orbiting/Oscillating/Random movement, all depending on the size of the number you multiply the random with.
//Use the unsigned feature of chars to make the enemy fire detection more accurate. Credit to Miked0801.
if(
(char) ( chancesOfReversing.charAt(deathCount)*Math.random()
+ enemyEnergy - (enemyEnergy = e.getEnergy()) - (1.1 - 1e-8) ) <= 1)
{
//Reverse direction.
//Calling the onHitWall event to reverse direction saves two bytes. Credit to Simonton.
onHitWall(null);
}
setAhead(direction);
//Record the current enemy lateral velocity.
enemyHistory = String.valueOf((char) (e.getVelocity() * (Math.sin(e.getHeadingRadians() - (absoluteBearing = e.getBearingRadians() + getHeadingRadians()))))).concat(enemyHistory);
//Pattern Matching.
//Find the longest match allowable in the enemy history.
while((matchPosition = enemyHistory.indexOf(enemyHistory.substring(0, --integer), 64)) < 0);
//Stay mostly perpendicular to the enemy, but try to maintain a distance of ORBIT_DISTANCE pixels.
//If DISTANCE_FACTOR is smaller it tries harder to get to the desired distance, but may 'SpinBot' if it is too small.
setTurnRightRadians(Math.cos(e.getBearingRadians() +
((ORBIT_DISTANCE - (integer = (int)(e.getDistance()))) * (getVelocity() / DISTANCE_FACTOR))
));
//Fire BULLET_POWER power bullets most of the time, but use higher power bullets when the distance is less than ANTI_RAMBOT_DISTANCE.
//This greatly improves scores against rambots and other extremely aggressive bots.
setFire(BULLET_POWER + (ANTI_RAMBOT_DISTANCE / integer));
//Assume that the enemy will repeat their movements in the ticks following the recording of the original pattern.
//Generate a firing angle based on that assumption.
do
{
//Go through the log of enemy movements right after the original pattern was recorded.
//Add the Angular Velocities directly to the absoluteBearing variable.
absoluteBearing += ((short) enemyHistory.charAt(--matchPosition)) / e.getDistance();
}
while ((integer -= BULLET_VELOCITY) > 0); //Keep projecting the enemy's movement forward until our bullet would reach their predicted location.
//Aim at the predicted target.
setTurnGunRightRadians(Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians()));
//Infinite radar lock.
setTurnRadarLeftRadians(getRadarTurnRemainingRadians());
}
public void onDeath(DeathEvent e)
{
//When the bot dies, move to the next cell in the table.
deathCount++;
}
public void onHitWall(HitWallEvent e)
{
//Reverse movement direction when the bot hits a wall.
direction = -direction;
}
//The chance that Yatagan will reverse direction when the enemy fires.
//values are referenced by number of deaths experienced
//when chancesOfReversing is 0, reverse on enemy fire only
//when chancesOfReversing is very large, almost never reverse (unless Math.random() is very small)
//when chancesOfReversing is > 3, reverse with probability 3/chancesOfReversing
private static final String chancesOfReversing = ""
+ (char)ONE_WAY_ORBIT + (char)REVERSE_ON_ENEMY_FIRE + (char)ONE_WAY_ORBIT
+ (char)REVERSE_ON_ENEMY_FIRE + (char)ONE_WAY_ORBIT + (char)REVERSE_ON_ENEMY_FIRE
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
;
//Preloaded log of enemy movements for pattern matcher so it doesn't need error checking.
//Skilgannon - this didn't need to be quite as long as it was, only max bullet flight time + one of each possible character
//unless we want to try pre-loading some common movement patterns?
static String enemyHistory = ""
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char)-1 + (char)-2 + (char)-3 + (char)-4 + (char)-5 + (char)-6
+ (char)-7 + (char)-8 + (char) 8 + (char) 7 + (char) 6 + (char) 5
+ (char) 4 + (char) 3 + (char) 2 + (char) 1 + (char) 0 + (char) 0
;
}
Latest Released Version (1.1.1)
/*
Yatagan 1.1.1 by Skilgannon & Sheldor ; Release date: 2013/05/05
The yatagan is a short sabre which was used extensively in the Ottoman Empire.
Codesize: 248 bytes without any colors
Credits:
Pattern Matching code from simonton.WeekendObsession_S and mld.Moebius, heavily modified.
And a general thanks to all open source bot authors and contributors to the RoboWiki.
Yatagan is open source and released under the terms of the RoboWiki Public Code License (RWPCL) - Version 1.1.
See license here: http://robowiki.net/wiki/RWPCL
*/
package jk.sheldor.nano;
import robocode.*;
import robocode.util.Utils;
public class Yatagan extends AdvancedRobot{
public static final double DESIRED_BULLET_POWER = 2.0;//Skilgannon: Let's test this first
//round to nearest multiple of 0.33333...
public static final double BULLET_POWER = (int)(DESIRED_BULLET_POWER*3 + 0.5)/3.0;
public static final int BULLET_VELOCITY = (int)(20 - 3 * BULLET_POWER);
public static final int MAX_MATCH_LENGTH = 30;
public static final int ORBIT_DISTANCE = 220;
public static final int DISTANCE_FACTOR = 3000;
//NB! Generate new RANDOM when changing ORBIT_DISTANCE!
/*public static void main(String[] args){
System.out.println("RANDOM = " + (int)Math.round(3.0/(0.6*Math.sqrt((20 - 3*2.5)/ORBIT_DISTANCE) - 0.04)));
}//*/
public static final char RANDOM = 29;
//Global variables.
static double direction;
static double enemyEnergy;
static int deathCount;
public void run()
{
//Skilgannon: sacrifice this for anti-rambot code
//setAdjustGunForRobotTurn(true);
//Start spinning radar and initialize direction to infinity.
setTurnRadarRightRadians(direction = Double.POSITIVE_INFINITY);
}
public void onScannedRobot(ScannedRobotEvent e)
{
//Local variables.
int integer = MAX_MATCH_LENGTH;
double absoluteBearing;
int matchPosition;
//Orbiting/Oscillating/Random movement, all depending on the size of the number you multiply the random with.
if(
(char) ( chancesOfReversing.charAt(deathCount)*Math.random()
+ enemyEnergy - (enemyEnergy = e.getEnergy()) - (1.1 - 1e-8) ) <= 1)
{
//Reverse direction.
//Calling the onHitWall event saves two bytes.
onHitWall(null);
}
setAhead(direction);
//Record the current enemy lateral velocity.
enemyHistory = String.valueOf((char) (e.getVelocity() * (Math.sin(e.getHeadingRadians() - (absoluteBearing = e.getBearingRadians() + getHeadingRadians()))))).concat(enemyHistory);
//Pattern Matching.
// search for a match
while((matchPosition = enemyHistory.indexOf(enemyHistory.substring(0, integer--), 64)) < 0);
//Stay mostly perpendicular to the enemy, but try to maintain a distance of ORBIT_DISTANCE pixels.
//If DISTANCE_FACTOR is smaller it tries harder to get to the desired distance, but may 'SpinBot' if it is too small
setTurnRightRadians(Math.cos(e.getBearingRadians() +
((ORBIT_DISTANCE - (integer = (int)(e.getDistance()))) * (getVelocity() / DISTANCE_FACTOR))
));
// add in anti-rambot bullet power - smaller than 128 saves a byte
setFire(BULLET_POWER + (127/integer));
do
{
absoluteBearing += ((short) enemyHistory.charAt(--matchPosition)) / e.getDistance();
}
while ((integer -= BULLET_VELOCITY) > 0);
//Aim at the predicted target.
setTurnGunRightRadians(Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians()));
//Infinite radar lock.
setTurnRadarLeftRadians(getRadarTurnRemainingRadians());
}
public void onDeath(DeathEvent e)
{
//When the bot dies, move to the next cell in the table.
deathCount++;
}
public void onHitWall(HitWallEvent e)
{
//Reverse direction when the bot hits a wall.
direction = -direction;
}
//The chance that Yatagan will reverse direction when the enemy fires.
//values are referenced by number of deaths experienced
//when chancesOfReversing is 0, reverse on enemy fire only
//when chancesOfReversing is very large, almost never reverse (unless Math.random() is very small)
//when chancesOfReversing is > 3, reverse with probability 3/chancesOfReversing
private static final String chancesOfReversing = ""
+ (char)0 + (char)60000 + (char)0 + (char)60000 + (char)0 + (char)60000
//100 rounds of deaths should be more than enough
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
+ RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM + RANDOM
;
//Preloaded log of enemy movements for pattern matcher so it doesn't need error checking.
//Skilgannon - this didn't need to be quite as long as it was, only max bullet flight time + one of each possible character
//unless we want to try pre-loading some common movement patterns?
static String enemyHistory = ""
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0 + (char) 0
+ (char)-1 + (char)-2 + (char)-3 + (char)-4 + (char)-5 + (char)-6
+ (char)-7 + (char)-8 + (char) 8 + (char) 7 + (char) 6 + (char) 5
+ (char) 4 + (char) 3 + (char) 2 + (char) 1 + (char) 0 + (char) 0
;
}