Advertisement
Guest User

russianaicup thevlad source

a guest
Nov 25th, 2012
185
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 66.68 KB | None | 0 0
  1. import model.*;
  2. import java.util.*;
  3. import java.io.*;
  4. import javax.swing.*;
  5.  
  6. import java.awt.Color;
  7. import java.awt.Dimension;
  8. import java.awt.Font;
  9. import java.awt.Graphics;
  10. import java.awt.Graphics2D;
  11. import java.awt.Image;
  12. import java.awt.geom.AffineTransform;
  13. import java.awt.image.BufferedImage;
  14.  
  15. public final class MyStrategy implements Strategy {
  16.        
  17.     public static class Vector2D
  18.     {
  19.         public double x;
  20.         public double y;
  21.        
  22.         public Vector2D()
  23.         {
  24.             this.x = 0;
  25.             this.y = 0;
  26.         }
  27.        
  28.         public Vector2D(double x0, double y0)
  29.         {
  30.             this.x = x0;
  31.             this.y = y0;
  32.         }
  33.        
  34.         public void normalize()
  35.         {
  36.             double l = Math.sqrt(this.x*this.x + this.y*this.y);
  37.             if (l < 1E-6)
  38.             {
  39.                 this.x = 0;
  40.                 this.y = 0;
  41.                 throw new ArithmeticException("normalize, divide by zero");
  42.             }
  43.            
  44.             double invL = 1.0 / l;
  45.             this.x *= invL;
  46.             this.y *= invL;
  47.         }
  48.        
  49.     }
  50.  
  51.     public static Vector2D fromAngle(double angle)
  52.     {
  53.         if (angle < 0.0)
  54.             angle += 2*Math.PI;
  55.         return new Vector2D(Math.cos(angle), Math.sin(angle));
  56.     }
  57.    
  58.     public static double length(Vector2D v)
  59.     {
  60.         return Math.sqrt(v.x*v.x + v.y*v.y);
  61.     }
  62.    
  63.     public static double length(double x, double y)
  64.     {
  65.         return Math.sqrt(x*x + y*y);
  66.     }
  67.    
  68.     public static double toAngle(Vector2D v)
  69.     {
  70.         return Math.atan2(v.y, v.x);            
  71.     }
  72.    
  73.     public static Vector2D normalize(Vector2D v)
  74.     {
  75.         Vector2D a = new Vector2D(v.x, v.y);
  76.         a.normalize();
  77.         return a;
  78.     }
  79.            
  80.     public static Vector2D add(Vector2D a, Vector2D b)
  81.     {
  82.         return new Vector2D(a.x + b.x, a.y + b.y);
  83.     }
  84.    
  85.     public static Vector2D sub(Vector2D a, Vector2D b)
  86.     {
  87.         return new Vector2D(a.x - b.x, a.y - b.y);
  88.     }
  89.    
  90.     public static Vector2D mul(Vector2D a, double s)
  91.     {
  92.         return new Vector2D(a.x*s, a.y*s);
  93.     }
  94.    
  95.     public static Vector2D mul(double s, Vector2D a)
  96.     {
  97.         return new Vector2D(a.x*s, a.y*s);
  98.     }
  99.    
  100.     public static double dotProduct(Vector2D a, Vector2D b)
  101.     {
  102.         return a.x*b.x + a.y*b.y;
  103.     }
  104.    
  105.     public static double distance(Vector2D a, Vector2D b)
  106.     {
  107.         double x = b.x - a.x;
  108.         double y = b.y - a.y;
  109.         return Math.sqrt(x*x + y*y);
  110.     }
  111.    
  112.     public static Vector2D perpendicular(Vector2D a)
  113.     {
  114.         return new Vector2D(-a.y, a.x);
  115.     }
  116.    
  117.     public static boolean isClouse(Vector2D a, Vector2D b, double eps)
  118.     {
  119.         return (Math.abs(a.x - b.x) < eps) && (Math.abs(a.y - b.y) < eps);
  120.     }      
  121.  
  122.     public static final int worldWidth  = 1280;
  123.     public static final int worldHeight = 800;
  124.        
  125.     public static double median(ArrayList<Double> inputList)
  126.     {
  127.         ArrayList<Double> doubleList = new ArrayList<Double>(inputList);
  128.         Collections.sort(doubleList);
  129.         return doubleList.get((doubleList.size() - 1)/2);
  130.     }
  131.    
  132.     public static double mean(ArrayList<Double> inputList)
  133.     {
  134.         ArrayList<Double> doubleList = new ArrayList<Double>(inputList);
  135.         if (doubleList.size() == 0)
  136.             return 0.0;
  137.        
  138.         double sum = 0.0;
  139.         for (int i = 0; i < doubleList.size(); ++i)
  140.         {
  141.             sum += doubleList.get(i);
  142.         }
  143.         return sum/doubleList.size();
  144.     }
  145.        
  146.     // nearest point on line
  147.     public static double nearestPointAtSegment(Vector2D p, Vector2D a, Vector2D b)
  148.     {
  149.         Vector2D ap = sub(p, a);
  150.         Vector2D ab = sub(b, a);
  151.         double ab2 = ab.x*ab.x + ab.y*ab.y;
  152.         double ap_ab = ap.x*ab.x + ap.y*ab.y;
  153.         double t = ap_ab / ab2;
  154.         if (t >= 0.0 && t <= 1.0)
  155.         {
  156.             return t;
  157.         }
  158.         else
  159.         {
  160.             double distA = distance(p, a);
  161.             double distB = distance(p, b);
  162.             if (distA < distB)
  163.                 return 0.0;
  164.             else
  165.                 return 1.0;
  166.         }
  167.     }
  168.  
  169.  
  170.     public static double nearestPointAtRay(Vector2D p, Vector2D a, Vector2D d)
  171.     {
  172.         Vector2D ap = sub(p, a);
  173.         Vector2D ab = d;
  174.         double ab2 = ab.x*ab.x + ab.y*ab.y;
  175.         double ap_ab = ap.x*ab.x + ap.y*ab.y;
  176.         double t = ap_ab / ab2;
  177.         return t;
  178.     }
  179.  
  180.     public static double normalizeAngle(double a)
  181.     {
  182.         return toAngle(fromAngle(a));
  183.     }
  184.        
  185.     public static Vector2D interpolate(Vector2D a, Vector2D b, double t, boolean isClamp)
  186.     {
  187.         if (isClamp)
  188.         {
  189.             if (t > 1.0)
  190.                 t = 1.0;
  191.             if (t < 0.0)
  192.                 t = 0.0;
  193.         }
  194.         return add(mul((1.0 - t), a), mul(t, b));
  195.     }
  196.        
  197.     public static double interpolate(double a, double b, double t, boolean isClamp)
  198.     {
  199.         if (isClamp)
  200.         {
  201.             if (t > 1.0)
  202.                 t = 1.0;
  203.             if (t < 0.0)
  204.                 t = 0.0;
  205.         }
  206.  
  207.         return (1.0 - t)*a + b*t;
  208.     }
  209.        
  210.     public static double orientation(Vector2D va, Vector2D vb)
  211.     {
  212.         double c = va.x*vb.y - va.y*vb.x;
  213.         if (c > 0)
  214.             return +1;
  215.         else
  216.             return -1;
  217.     }
  218.  
  219.     // two normalized vectors
  220.     public static double angleBetween(Vector2D a, Vector2D b)
  221.     {
  222.         Vector2D va = normalize(a);
  223.         Vector2D vb = normalize(b);
  224.         double c = va.x*vb.y - va.y*vb.x;
  225.         if (c > 0)
  226.             return -Math.acos(va.x*vb.x + va.y*vb.y);
  227.         else
  228.             return Math.acos(va.x*vb.x + va.y*vb.y);
  229.     }
  230.        
  231.     // a - curentAngle, b - targetAngle
  232.     public static double angleBetween(double a, double b)
  233.     {
  234.         Vector2D va = fromAngle(a);
  235.         Vector2D vb = fromAngle(b);        
  236.         double c = va.x*vb.y - va.y*vb.x;
  237.         if (c > 0)
  238.             return Math.acos(va.x*vb.x + va.y*vb.y);
  239.         else
  240.             return -Math.acos(va.x*vb.x + va.y*vb.y);
  241.     }
  242.  
  243.     public static double degToRad(double deg)
  244.     {
  245.         return deg*(Math.PI/180.0);
  246.     }
  247.            
  248.     public static class DebugCanvas
  249.     {
  250.         public JFrame frame;
  251.  
  252.         public BufferedImage  buffer;
  253.         public BufferedImage  paintBuffer;
  254.         public BufferedImage  buffer1;
  255.         public BufferedImage  buffer2;
  256.         public Graphics2D     g = null;
  257.         public DebugPanel     panel;
  258.        
  259.         public class DebugPanel extends JPanel
  260.         {
  261.             public void paintComponent(Graphics pg)
  262.             {
  263.                 if (enableDebug)
  264.                 {
  265.                     if (g != null)
  266.                     {
  267.                         pg.drawImage(paintBuffer, 0, 0, null);
  268.                         synchronized(DebugCanvas.this)
  269.                         {
  270.                             paintBuffer = null;
  271.                         }
  272.                     }
  273.                 }
  274.             }
  275.         }
  276.                
  277.         public void onBegin()
  278.         {
  279.             if (enableDebug)
  280.             {
  281.                 //AffineTransform aft = new AffineTransform();
  282.                 //aft.setTransform(1.0, 0.0, 0.0, -1.0, 0.0, this.buffer.getHeight());
  283.                 //this.g.setTransform(aft);
  284.                 //Font font = new Font("Serif", )
  285.             }
  286.         }
  287.        
  288.         public void onEnd()
  289.         {
  290.             if (enableDebug)
  291.             {
  292.                
  293.             }          
  294.         }
  295.        
  296.         public void create(int w, int h)
  297.         {
  298.             if (enableDebug)
  299.             {
  300.                 this.panel = new DebugPanel();
  301.                 this.frame = new JFrame("DebugCanvas");
  302.                 this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  303.                 this.frame.setResizable(false);
  304.                
  305.                 this.panel.setPreferredSize(new Dimension(w, h));
  306.                 this.frame.setContentPane(this.panel);
  307.                 this.frame.pack();
  308.                 this.frame.setVisible(true);            
  309.    
  310.                 this.buffer1 = new java.awt.image.BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  311.                 this.buffer2 = new java.awt.image.BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
  312.                 this.buffer = this.buffer1;
  313.                 this.g = this.buffer.createGraphics();
  314.                 this.onBegin();
  315.             }
  316.         }
  317.        
  318.         public void drawImage(Image image)
  319.         {
  320.             if (enableDebug)
  321.             {
  322.                 Image scaledImage =image.getScaledInstance(this.buffer.getWidth(), this.buffer.getHeight(), Image.SCALE_FAST);
  323.                 this.g.drawImage(scaledImage, 0, 0, null);
  324.             }
  325.         }
  326.        
  327.         public void drawPolyLine(ArrayList<Vector2D> polyLine)
  328.         {
  329.             if (enableDebug)
  330.             {
  331.                 for (int i = 0; i + 1 < polyLine.size(); ++i)
  332.                 {
  333.                     this.line(polyLine.get(i), polyLine.get(i + 1));
  334.                 }
  335.             }
  336.         }
  337.                
  338.         public void drawWorld(World world)
  339.         {
  340.             if (enableDebug)
  341.             {
  342.                 this.setColor(Color.BLACK);
  343.                 this.text(String.format("Tick: %d", world.getTick()), 5, 15);
  344.    
  345.                 for (Tank tank: world.getTanks())
  346.                 {
  347.                     drawTank(tank);
  348.                 }
  349.                
  350.                 for (Shell shell: world.getShells())
  351.                 {
  352.                     drawShell(shell);
  353.                 }
  354.                
  355.                 for (Bonus bonus: world.getBonuses())
  356.                 {
  357.                     drawBonus(bonus);
  358.                 }
  359.             }
  360.         }
  361.        
  362.         public void drawBonus(Bonus bonus)
  363.         {
  364.             if (enableDebug)
  365.             {
  366.                 this.setColor(Color.BLACK);
  367.                 Vector2D bonusPos = new Vector2D(bonus.getX(), bonus.getY());
  368.                 Vector2D bonusTextPos = new Vector2D(bonusPos.x - 20.0, bonusPos.y);
  369.                 this.rectangle(bonusPos, bonus.getWidth(), bonus.getHeight(), bonus.getAngle());
  370.                 this.setColor(Color.BLACK);
  371.                 if (bonus.getType() == BonusType.AMMO_CRATE)
  372.                 {
  373.                     this.setColor(Color.BLUE);
  374.                     this.text("ammo", bonusTextPos);
  375.                 }
  376.                 else if (bonus.getType() == BonusType.MEDIKIT)
  377.                 {
  378.                     this.setColor(Color.GREEN);
  379.                     this.text("med", bonusTextPos);
  380.                 }
  381.                 else if (bonus.getType() == BonusType.REPAIR_KIT)
  382.                 {
  383.                     this.setColor(Color.RED);
  384.                     this.text("repair", bonusTextPos);
  385.                 }              
  386.             }
  387.         }
  388.        
  389.         public void drawShell(Shell shell)
  390.         {
  391.             if (enableDebug)
  392.             {
  393.                 this.setColor(Color.RED);
  394.                 Vector2D shellPos = new Vector2D(shell.getX(), shell.getY());
  395.                 this.rectangle(shellPos, shell.getWidth(), shell.getHeight(), shell.getAngle());
  396.             }
  397.         }
  398.        
  399.         public void drawTank(Tank tank)
  400.         {
  401.             if (enableDebug)
  402.             {
  403.                 this.setColor(Color.BLACK);
  404.                 Vector2D tankPos = new Vector2D(tank.getX(), tank.getY());
  405.                 this.rectangle(tankPos, tank.getWidth(), tank.getHeight(), tank.getAngle());
  406.                
  407.                 this.text(String.format("hp (%d, %d) r (%d)", tank.getCrewHealth(), tank.getHullDurability(), tank.getRemainingReloadingTime()),
  408.                         roundInt(tankPos.x - 40), roundInt(tankPos.y - 15));
  409.                
  410.                 this.setColor(Color.MAGENTA);
  411.                 Vector2D tankVel = new Vector2D(tank.getSpeedX(), tank.getSpeedY());
  412.                 this.vector(tankPos, tankVel, 10.0);
  413.        
  414.                 this.setColor(Color.GREEN);
  415.                 double turretAngle = normalizeAngle(tank.getAngle() + tank.getTurretRelativeAngle());
  416.                 this.vector(tankPos, fromAngle(turretAngle), tank.getVirtualGunLength());              
  417.             }
  418.         }
  419.        
  420.         public void drawMove(Tank self, Move move)
  421.         {
  422.             double w = self.getWidth();
  423.             double h = self.getHeight();
  424.             Vector2D front = fromAngle(self.getAngle());
  425.             Vector2D flang = normalize(perpendicular(front));
  426.             Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  427.  
  428.             Vector2D leftP  = add(selfPos, mul(-h*0.5, flang));
  429.             Vector2D leftV  = mul(w*0.5, front);
  430.             Vector2D rightP = add(selfPos, mul(h*0.5, flang));
  431.             Vector2D rightV = mul(w*0.5, front);
  432.            
  433.             if (move.getLeftTrackPower() < 0.0)
  434.             {
  435.                 this.setColor(Color.CYAN);
  436.                 this.vector(leftP, mul(self.getEngineRearPowerFactor()*move.getLeftTrackPower(), leftV));
  437.             }
  438.             else
  439.             {
  440.                 this.setColor(Color.BLUE);
  441.                 this.vector(leftP, mul(move.getLeftTrackPower(), leftV));
  442.             }
  443.            
  444.             if (move.getRightTrackPower() < 0.0)
  445.             {
  446.                 this.setColor(Color.CYAN);
  447.                 this.vector(rightP, mul(self.getEngineRearPowerFactor()*move.getRightTrackPower(), rightV));
  448.             }
  449.             else
  450.             {
  451.                 this.setColor(Color.BLUE);
  452.                 this.vector(rightP, mul(move.getRightTrackPower(), rightV));
  453.             }
  454.         }
  455.        
  456.         public void rectangle(Vector2D pos, double w, double h, double angle)
  457.         {
  458.             if (enableDebug)
  459.             {
  460.                 Vector2D front = fromAngle(angle);
  461.                 Vector2D flang = normalize(perpendicular(front));
  462.                
  463.                 Vector2D p0 = add(pos, add(mul(w*0.5, front),  mul(h*0.5, flang)));
  464.                 Vector2D p1 = add(pos, add(mul(w*0.5, front),  mul(-h*0.5, flang)));
  465.                 Vector2D p2 = add(pos, add(mul(-w*0.5, front), mul(-h*0.5, flang)));
  466.                 Vector2D p3 = add(pos, add(mul(-w*0.5, front), mul(h*0.5, flang)));
  467.                
  468.                 this.line(p0, p1);
  469.                 this.line(p1, p2);
  470.                 this.line(p2, p3);
  471.                 this.line(p3, p0);
  472.             }
  473.         }
  474.        
  475.         public void text(String str, Vector2D pos)
  476.         {
  477.             if (enableDebug)
  478.             {
  479.                 this.text(str, roundInt(pos.x), roundInt(pos.y));
  480.             }
  481.         }
  482.        
  483.         public void text(String str, int x, int y)
  484.         {
  485.             if (enableDebug)
  486.             {
  487.                 g.drawString(str, x, y);
  488.             }
  489.         }
  490.        
  491.         public void text(String str, double x, double y)
  492.         {
  493.             if (enableDebug)
  494.             {
  495.                 g.drawString(str, (float)x, (float)y);
  496.             }
  497.         }
  498.        
  499.         public void clear()
  500.         {
  501.             if (enableDebug)
  502.             {
  503.                 this.g.setBackground(Color.WHITE);
  504.                 this.g.clearRect(0, 0, this.buffer.getWidth(), this.buffer.getHeight());
  505.             }
  506.         }
  507.          
  508.         public void present()
  509.         {
  510.             if (enableDebug)
  511.             {
  512.                 this.onEnd();
  513.                 this.g.dispose();
  514.                 boolean spinWait = true;
  515.                 while (spinWait)
  516.                 {
  517.                     synchronized (this)
  518.                     {
  519.                         if (this.paintBuffer == null)
  520.                         {
  521.                             if (this.buffer == this.buffer1)
  522.                             {
  523.                                 this.paintBuffer = this.buffer1;
  524.                                 this.buffer = this.buffer2;
  525.                             }
  526.                             else if (this.buffer == this.buffer2)
  527.                             {
  528.                                 this.paintBuffer = this.buffer2;
  529.                                 this.buffer = this.buffer1;
  530.                             }
  531.                             spinWait = false;
  532.                         }
  533.                     }
  534.                     try
  535.                     {
  536.                         Thread.sleep(1);
  537.                     }
  538.                     catch (Exception ex)
  539.                     {
  540.                     }
  541.                 }
  542.                 this.g = this.buffer.createGraphics();
  543.                 this.onBegin();
  544.                 this.panel.repaint();
  545.             }
  546.         }
  547.        
  548.         public static int roundInt(double x)
  549.         {
  550.             return (int)Math.round(x);
  551.         }
  552.        
  553.         public void setColor(Color c)
  554.         {
  555.             if (enableDebug)
  556.             {
  557.                 this.g.setColor(c);
  558.             }
  559.         }
  560.        
  561.         public void line(Vector2D a, Vector2D b)
  562.         {
  563.             if (enableDebug)
  564.             {
  565.                 this.g.drawLine(roundInt(a.x), roundInt(a.y), roundInt(b.x), roundInt(b.y));
  566.             }
  567.         }
  568.        
  569.         public void vector(Vector2D pos, Vector2D v)
  570.         {
  571.             if (enableDebug)
  572.             {
  573.                 this.vector(pos, v, 1.0);
  574.             }
  575.         }
  576.        
  577.         public void vector(Vector2D pos, Vector2D v0, double scale)
  578.         {
  579.             if (enableDebug)
  580.             {
  581.                 Vector2D v = mul(scale, v0);
  582.                 if (length(v) < 1)
  583.                 {
  584.                     this.line(pos, pos);
  585.                     return;
  586.                 }
  587.                 Vector2D endPos = add(pos, v);
  588.                 this.line(pos, endPos);
  589.                 Vector2D perp = mul(7.0, normalize(perpendicular(v)));
  590.                 double l = length(v) - 7.0;
  591.                 if (l < 0.0)
  592.                     l = 0.0;
  593.                 Vector2D joinPos   = add(pos, mul(l, normalize(v)));
  594.                 Vector2D arrowPos1 = add(joinPos, perp);
  595.                 Vector2D arrowPos2 = add(joinPos, mul(-1.0, perp));
  596.                
  597.                 this.line(arrowPos1, endPos);
  598.                 this.line(arrowPos2, endPos);
  599.             }
  600.         }              
  601.     }  
  602.    
  603.     public static class KinematicState
  604.     {
  605.         public double   q;
  606.         public double   f;
  607.         public double   u;
  608.         public double   a;
  609.         public Vector2D p;
  610.        
  611.         public KinematicState(double q, double f, double u, double a, Vector2D p)
  612.         {
  613.             this.q = q;
  614.             this.f = f;
  615.             this.u = u;
  616.             this.a = a;
  617.             this.p = p;
  618.         }
  619.        
  620.         //  dx/dt = u*cos(q), dy/dt = u*sin(q), dq/dt = f, du/dt = a
  621.         public KinematicState advance(double t, Tank tank)
  622.         {
  623.             double q1 = normalizeAngle(q + f*t);
  624.             double u1 = u + a*t;
  625.             double a0 = a;          
  626.             if (u1 > 4.0)
  627.             {
  628.                 u1 = 4.0;
  629.                 a0 = (4.0 - u)/t;
  630.             }
  631.             else if (u1 < -2.6)
  632.             {
  633.                 u1 = -2.6;
  634.                 a0 = (-2.6 - u)/t;
  635.             }
  636.                
  637.             double x = 0.0;
  638.             double y = 0.0;
  639.             if (Math.abs(f) > 1E-5)
  640.             {
  641.                 double x0 = (f*u*Math.sin(q) + a0*Math.cos(q))/(f*f);
  642.                 double y0 = (a0*Math.sin(q) - f*u*Math.cos(q))/(f*f);
  643.                
  644.                 double x1 = (f*(a0*t + u)*Math.sin(q + f*t) + a0*Math.cos(q + f*t))/(f*f);
  645.                 double y1 = (a0*Math.sin(q + f*t) - f*(a0*t + u)*Math.cos(q + f*t))/(f*f);
  646.                 x = x1 - x0;
  647.                 y = y1 - y0;
  648.             }
  649.             else
  650.             {
  651.                 x = 0.5*a*t*t*Math.cos(q) + u*t*Math.cos(q);
  652.                 y = 0.5*a*t*t*Math.sin(q) + u*t*Math.sin(q);
  653.             }
  654.            
  655.             //return new KinematicState(q1, f, u1, a,  new Vector2D(x, y));
  656.            
  657.             // try to fix geometry to center of mass
  658.             Vector2D front0    = fromAngle(q);
  659.             Vector2D frontFix0 = mul(tank.getWidth()*0.5, front0);
  660.             Vector2D front1    = fromAngle(q1);
  661.             Vector2D frontFix1 = mul(tank.getWidth()*0.5, front1);
  662.             return new KinematicState(q1, f, u1, a,  new Vector2D(frontFix0.x + p.x + x - frontFix1.x, frontFix0.y + p.y + y - frontFix1.y));
  663.         }      
  664.     }
  665.        
  666.     public void initSystem()
  667.     {
  668.         if (enableDebug == true)
  669.         {
  670.             try
  671.             {
  672.                 String userName = System.getProperty("user.name");
  673.                 if (!userName.equals("vlad"))
  674.                     enableDebug = false;
  675.             }
  676.             catch (Exception ex)
  677.             {
  678.                 enableDebug = false;
  679.             }
  680.         }
  681.  
  682.         if (enableDebug == true)
  683.         {
  684.             debug.create(worldWidth, worldHeight);
  685.         }
  686.     }
  687.    
  688.    
  689.     public DebugCanvas debug = new DebugCanvas();    
  690.     static boolean enableDebug = false;
  691.  
  692.    
  693. //    public void complexMove(Tank self, World world, Move move)
  694. //    {
  695. //      if (world.getTick() == 0)
  696. //      {
  697. //          init();
  698. //      }
  699. //
  700. //      
  701. //      debug.clear();      
  702. //      debug.drawWorld(world);
  703. //      
  704. //      /*
  705. //        double turretAngle = Util.normalizeAngle(self.getAngle() + self.getTurretRelativeAngle()); //
  706. //        
  707. //      Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  708. //      double minDistanceToEnemy = Double.MAX_VALUE;
  709. //      double flyTime = 0.0;
  710. //      Vector2D predictedEnemyPos = new Vector2D(0.0, 0.0);
  711. //      Tank selectedTank = null;
  712. //      for (Tank tank: world.getTanks())
  713. //      {
  714. //          if (!tank.isTeammate())
  715. //          {
  716. //              Vector2D enemyPos = new Vector2D(tank.getX(), tank.getY());
  717. //              Vector2D enemyVel = new Vector2D(tank.getSpeedX(), tank.getSpeedY());
  718. //              
  719. //              double distanceToEnemy = Vector2D.distance(selfPos, enemyPos); // + Util.angleBetween(turretAngle, Vector2D.toAngle(Vector2D.sub(enemyPos, selfPos)))/self.getTurretTurnSpeed();\
  720. //              flyTime = distanceToEnemy/19.0;
  721. //              predictedEnemyPos = Vector2D.add(enemyPos, Vector2D.mul(flyTime, enemyVel));
  722. //              if (distanceToEnemy < minDistanceToEnemy)
  723. //              {
  724. //                  selectedTank = tank;
  725. //                  minDistanceToEnemy = distanceToEnemy;
  726. //              }
  727. //              
  728. //              if (enemyId != 0 && tank.getId() == enemyId)
  729. //              {
  730. //                  selectedTank = tank;
  731. //                  enemyId = tank.getId();
  732. //              }
  733. //          }
  734. //      }
  735. //      
  736. //      Vector2D enemyPos = predictedEnemyPos; // new Vector2D(selectedTank.getX(), selectedTank.getY());        
  737. //        double enemyAngle  = Vector2D.toAngle(Vector2D.sub(enemyPos, selfPos));
  738. //        double angleDelta = Util.angleBetween(turretAngle, enemyAngle);
  739. //        double turretTurnSpeed = self.getTurretTurnSpeed();
  740. //        
  741. //        if (enableLog)
  742. //        {
  743. //          log(String.format("Turret: enemy (%f, %f), self (%f, %f)", enemyPos.x, enemyPos.y, selfPos.x, selfPos.y));
  744. //          log(String.format("Turret: enemy id %d, turret %f, enemy angle: %f, delta: %f", selectedTank.getId(), turretAngle, enemyAngle, angleDelta));
  745. //        }
  746. //        
  747. //        
  748. //        if (Math.abs(angleDelta) < 0.05)
  749. //        {
  750. //          move.setFireType(FireType.PREMIUM_PREFERRED);
  751. //          this.prevFireType = FireType.PREMIUM_PREFERRED;
  752. //        }
  753. //        else
  754. //        {
  755. //          if (angleDelta > 0.0)
  756. //              move.setTurretTurn(3.0);
  757. //          else
  758. //              move.setTurretTurn(-3.0);
  759. //          
  760. //          
  761. //          if (prevFireType != FireType.NONE)
  762. //          {
  763. //              move.setFireType(FireType.NONE);
  764. //              this.prevFireType = FireType.NONE;
  765. //          }
  766. //        }
  767. //        */
  768. //                
  769. //        //trajectory.updateStep(self);
  770. //              
  771. //      //Vector2D trackPowers = trajectory.getTrackPowers();
  772. //      Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  773. //      this.posHistory.add(selfPos);
  774. //      
  775. //      double speed = Vector2D.length(self.getSpeedX(), self.getSpeedY());
  776. //      double deltaSpeed = 0.0;
  777. //      this.speedHistory.add(speed);
  778. //      double deltaAcceleration = 0.0;
  779. //      
  780. //      double angularSpeed = self.getAngularSpeed();
  781. //      this.angleHistory.add(self.getAngle());
  782. //      double deltaAngularSpeed = 0.0;
  783. //      
  784. //      if (this.posHistory.size() >= 2)
  785. //      {
  786. //          deltaSpeed = Vector2D.length(Vector2D.sub(this.posHistory.get(this.posHistory.size() - 1), this.posHistory.get(this.posHistory.size() - 2)));
  787. //      }
  788. //      
  789. //      if (this.angleHistory.size() >= 2)
  790. //      {
  791. //          deltaAngularSpeed = this.angleHistory.get(this.angleHistory.size() - 1) - this.angleHistory.get(this.angleHistory.size() - 2);
  792. //      }
  793. //      
  794. //      if (this.speedHistory.size() >= 2)
  795. //      {
  796. //          deltaAcceleration = this.speedHistory.get(this.speedHistory.size() - 1) - this.speedHistory.get(this.speedHistory.size() - 2);
  797. //      }
  798. //      
  799. //      
  800. //      boolean change = false;
  801. //      if (world.getTick() % 30 == 0)
  802. //      {
  803. //          if (rand.nextBoolean())
  804. //          {
  805. //              this.leftPower = 1.0;
  806. //              this.rightPower = Util.interpolate(0.0, 1.0, rand.nextDouble(), true);
  807. //          }
  808. //          else
  809. //          {
  810. //              this.leftPower = Util.interpolate(0.0, 1.0, rand.nextDouble(), true);
  811. //              this.rightPower = 1.0;
  812. //          }
  813. //          change = true;
  814. //      }
  815. //      
  816. //      // override
  817. //      if (world.getTick() < 100)
  818. //      {
  819. //          leftPower = 1.0;
  820. //          rightPower = -self.getEngineRearPowerFactor()*1.0;
  821. //      }
  822. //      else
  823. //      {
  824. //          leftPower = -1.0;
  825. //          rightPower = -1.0;
  826. //      }
  827. //
  828. //      double q = self.getAngle();
  829. //      double u = speed;
  830. //      double f = self.getAngularSpeed();
  831. //
  832. //      Vector2D frontPos = new Vector2D();
  833. //      ArrayList<Vector2D> predictK1 = new ArrayList();
  834. //      for (int i = 0; i < 30; ++i)
  835. //      {
  836. //          double k = 0.043;
  837. //          double pa = 0.0;
  838. //          double pb = 0.0;
  839. //          double kNew = 0.0;
  840. //          if (leftPower > 0)
  841. //              pa = 2.0;
  842. //          else
  843. //              pa = 1.4; // 1.3
  844. //          
  845. //          if (rightPower > 0)
  846. //              pb = 2.0;
  847. //          else
  848. //              pb = 1.4; // 1.3
  849. //          
  850. //          double uMax = pa*leftPower + pb*rightPower;
  851. //          double fK   = 0.0141;
  852. //          double fMax   = 0.0;
  853. //          if (leftPower > rightPower)
  854. //          {
  855. //              fMax = fK*(leftPower - rightPower);
  856. //          }
  857. //          else
  858. //          {
  859. //              fMax = -fK*(rightPower - leftPower);    
  860. //          }
  861. //          double a    = uMax*k;
  862. //          Vector2D p = Kinematic.kinematic(q, u, 0.5*(f + fMax), a, k, i*1.0);
  863. //          
  864. //          if (i == 0 && Vector2D.length(p) > 3.0)
  865. //          {
  866. //              int break34 = 0;
  867. //          }
  868. //          
  869. //          Vector2D front = Vector2D.fromAngle(self.getAngle());
  870. //          frontPos = Vector2D.add(selfPos, Vector2D.mul(self.getWidth()*0.5, front));
  871. //          predictK1.add(Vector2D.add(frontPos, p));
  872. //      }
  873. //      
  874. //      if (change)
  875. //      {
  876. //          double errorD = Vector2D.length(Vector2D.sub(frontPos, new Vector2D(predictX, predictY)));
  877. //          predictX = predictK1.get(predictK1.size() - 1).x;
  878. //          predictY = predictK1.get(predictK1.size() - 1).y;
  879. //      }
  880. //      
  881. //      debug.setColor(Color.RED);
  882. //      debug.line(new Vector2D(predictX, predictY), new Vector2D(predictX, predictY));
  883. //      debug.text("p", new Vector2D(predictX, predictY));
  884. //      
  885. //      debug.setColor(Color.BLACK);
  886. //      debug.text(String.format("(s: %f, as: %f, da: %f)", speed, angularSpeed, deltaAcceleration), 100, 20);
  887. //      
  888. //      debug.setColor(Color.ORANGE);
  889. //      debug.drawPolyLine(this.posHistory);
  890. //      
  891. //      debug.setColor(Color.MAGENTA);
  892. //      debug.drawPolyLine(predictK1);
  893. //      
  894. //      
  895. //      move.setLeftTrackPower(leftPower);
  896. //      move.setRightTrackPower(rightPower);
  897. //      
  898. //      debug.drawMove(self, move);
  899. //      debug.present();
  900. //    }
  901.            
  902.     public static class TankEntry
  903.     {
  904.         public long                 id;
  905.         public ArrayList<Vector2D>  posHistory = new ArrayList<Vector2D>();
  906.         public ArrayList<Double>    angleHistory = new ArrayList<Double>();
  907.         public ArrayList<Double>    angularSpeedHistory = new ArrayList<Double>();
  908.         public ArrayList<Double>    speedHistory = new ArrayList<Double>();
  909.         public ArrayList<Double>    accelHistory = new ArrayList<Double>();
  910.         public ArrayList<Vector2D>  velocityHistory = new ArrayList<Vector2D>();
  911.         public Tank                 thisTank;
  912.     }
  913.        
  914.     public void initSelf(Tank self, World world, Move move)
  915.     {
  916.         for (Tank tank: world.getTanks())
  917.         {
  918.             this.tankEntryById.put(tank.getId(), new TankEntry());          
  919.         }      
  920.     }
  921.    
  922.     public double getTankSpeed(Tank tank)
  923.     {
  924.         Vector2D velocity = new Vector2D(tank.getSpeedX(), tank.getSpeedY());
  925.         double speed = length(velocity);
  926.         Vector2D front = fromAngle(tank.getAngle());
  927.         if (dotProduct(front, velocity) < 0.0)
  928.             speed = -speed;
  929.         return speed;
  930.     }
  931.    
  932.     public double getTankAccel(Tank tank)
  933.     {
  934.         ArrayList<Double> accelHistory = this.tankEntryById.get(tank.getId()).accelHistory;
  935.         if (accelHistory.size() >= 1)
  936.         {
  937.             return accelHistory.get(accelHistory.size() - 1);
  938.         }
  939.         return 0.0;
  940.     }
  941.  
  942.     public double getTankAccelSmooth(Tank tank)
  943.     {
  944.         ArrayList<Double> accelHistory = this.tankEntryById.get(tank.getId()).accelHistory;
  945.         int smoothSize = 5;
  946.         if (accelHistory.size() >= smoothSize)
  947.         {
  948.             double sum = 0.0;
  949.             for (int i = accelHistory.size() - smoothSize; i < accelHistory.size(); ++i)
  950.             {
  951.                 sum += accelHistory.get(i);
  952.             }
  953.             return sum/smoothSize;
  954.         }
  955.         else if (accelHistory.size() >= 1)
  956.         {
  957.             return accelHistory.get(accelHistory.size() - 1);
  958.         }
  959.         return 0.0;
  960.     }
  961.    
  962.     public double getTankRadius(Tank tank)
  963.     {
  964.         return length(new Vector2D(tank.getHeight()*0.5, tank.getWidth()*0.5));
  965.     }
  966.        
  967.     public KinematicState predictKinematic(Tank tank, double dt)
  968.     {
  969.         KinematicState initialState = new KinematicState(tank.getAngle(), tank.getAngularSpeed(), getTankSpeed(tank), getTankAccelSmooth(tank),
  970.                                                          new Vector2D(tank.getX(), tank.getY()));
  971.         return initialState.advance(dt, tank);
  972.     }
  973.    
  974.     public double predictSpeed(double a, double b, double u, double t)
  975.     {
  976.         return (1.0/60.0)*(((a*b*(Math.pow(b, t) - 1.0) + (b - 1.0)*u*Math.pow(b, t))/(b - 1.0)));
  977.     }
  978.    
  979.     public double predictDistance(double a, double b, double u, double t)
  980.     {
  981.         return (1.0/60.0)*((Math.pow(b, t)*(a*b+ (b-1.0)*u)-b*(a*(b-1.0)*t+a+u)+u)/((b-1.0)*(b-1.0)));
  982.     }
  983.    
  984.     public Vector2D predictMinMax(Tank tank, Vector2D selfPos, double hitTime)
  985.     {
  986.         Vector2D tankPos   = new Vector2D(tank.getX(), tank.getY());
  987.        
  988.         Vector2D tankVel   = new Vector2D(tank.getSpeedX(), tank.getSpeedY());
  989.         Vector2D tankDir   = fromAngle(tank.getAngle());
  990.         double   tankSpeed = length(tankVel)*Math.signum(dotProduct(tankDir, tankVel));
  991.         double   dist      = length(sub(tankPos, selfPos));
  992.        
  993.         double health = (1.0*tank.getCrewHealth())/tank.getCrewMaxHealth();
  994.         double frontA = tank.getEnginePower()*(0.5 + 0.5*health)/(10.0*60.0);
  995.         double backA  = -tank.getEnginePower()*tank.getEngineRearPowerFactor()*(0.5 + 0.5*health)/(10.0*60.0);
  996.         double b = 1.0 - (0.5/10.0);
  997.        
  998.         Vector2D perpRay   = normalize(perpendicular(sub(tankPos, selfPos)));
  999.         if (dotProduct(tankDir, perpRay) < 0.0)
  1000.             perpRay = mul(-1.0, perpRay);
  1001.  
  1002.         double tankRadius = getTankRadius(tank);
  1003.         double frontDistance = dotProduct(perpRay, mul(tankDir,  tankRadius + predictDistance(frontA, b, tankSpeed, hitTime)));
  1004.         double backDistance  = dotProduct(perpRay, mul(tankDir, -tankRadius + predictDistance(backA, b, tankSpeed, hitTime)));
  1005.        
  1006.         debug.setColor(Color.RED);
  1007.         debug.text(String.format("f: %f, b: %f", frontDistance, backDistance), 100, 40);
  1008.        
  1009.         debug.setColor(Color.MAGENTA);
  1010.         debug.line(add(mul(frontDistance, tankDir), tankPos),  add(mul(backDistance, tankDir), tankPos));
  1011.        
  1012.         double delta = (frontDistance - tank.getWidth()) - (backDistance  + tank.getWidth());
  1013.         Vector2D p1 = mul(frontDistance - tank.getWidth(), tankDir);
  1014.         Vector2D p2 = mul(backDistance  + tank.getWidth(), tankDir);
  1015.        
  1016.         Vector2D r;
  1017.         if (delta > 0.5*tank.getWidth() && tankSpeed > 0.5)
  1018.             r = mul(0.5, add(add(mul(frontDistance, tankDir), tankPos), tankPos));
  1019.         else
  1020.             r = add(mul(0.5, add(p1, p2)), tankPos);
  1021.                    
  1022.         debug.setColor(Color.BLUE);
  1023.         debug.text("f", add(p1, tankPos));
  1024.         debug.text("b", add(p2, tankPos));
  1025.        
  1026.         debug.setColor(Color.RED);
  1027.         debug.text("o", r);
  1028.         return r;
  1029.     }
  1030.  
  1031.     public boolean isAlive(Tank tank)
  1032.     {
  1033.         return tank.getCrewHealth() > 0 && tank.getHullDurability() > 0;
  1034.     }
  1035.  
  1036.     // hit probability
  1037.     public double hitProb(double dist, double certainHitDistance)
  1038.     {
  1039.         double prob = certainHitDistance/dist;
  1040.         if (prob > 1.0)
  1041.             prob = 1.0;
  1042.        
  1043.         return prob;
  1044.     }
  1045.    
  1046.     public double miePhase(double q, double g)
  1047.     {
  1048.         return (1.0 - g*g)/Math.pow(1.0 + g*g - 2.0*g*Math.cos(q), 3.0/2.0);    
  1049.     }
  1050.    
  1051.     public double phaseHitProb(double q, double g)
  1052.     {
  1053.         return miePhase(q, g)/miePhase(0.0, g);
  1054.     }
  1055.    
  1056.     public double dangerHeuristic(World world, Vector2D p, Tank self, boolean isSelf)
  1057.     {  
  1058.         double expectedDamage = 0.0;
  1059.         int aliveEnemyCount = 0;
  1060.         Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  1061.         for (Tank tank: world.getTanks())
  1062.         {
  1063.             Vector2D tankPos = new Vector2D(tank.getX(), tank.getY());
  1064.             if (isAlive(tank) && tank.isTeammate() == false)
  1065.             {
  1066.                 double forwardness = 0.2;
  1067.                 Vector2D deltaPos = sub(p, tankPos);
  1068.                 Vector2D selfDir;
  1069.                 if (isSelf == false)
  1070.                 {
  1071.                     selfDir = sub(p, selfPos);
  1072.                 }
  1073.                 else
  1074.                 {
  1075.                     selfDir = fromAngle(self.getAngle());
  1076.                 }
  1077.                
  1078.                 Vector2D tankTurret = fromAngle(getTurretAngle(tank));
  1079.                 double selfHitAngle = angleBetween(selfDir, tankTurret);
  1080.                 double dist = distance(tankPos, p);
  1081.                 //double angle = angleBetween(deltaPos, tankTurretV);
  1082.                 //double phaseHitProb = phaseHitProb(Math.abs(angle), forwardness);
  1083.                 double distProb = (300.0/dist);
  1084.                 if (distProb > 1.0)
  1085.                     distProb = 1.0;
  1086.                
  1087.                 double angleProb = 0.0;
  1088.                 if (Math.abs(angleBetween(deltaPos, tankTurret)) < Math.PI/2.0)
  1089.                 {
  1090.                     angleProb = Math.abs(Math.cos(selfHitAngle));
  1091.                 }
  1092.                 else
  1093.                 {
  1094.                     angleProb = 0.7*distProb;
  1095.                 }
  1096.                
  1097.                 double hitProbability = 0.0;
  1098.                 if (dist > 400.0)
  1099.                     hitProbability = angleProb*distProb;
  1100.                 else
  1101.                     hitProbability = distProb;
  1102.                
  1103.                
  1104.                 double tankHealth = (1.0*tank.getCrewHealth())/tank.getCrewMaxHealth();
  1105.                 //double overpower = selfHealth - tankHealth;
  1106.                 //if (overpower < 0.0)
  1107.                 //  overpower = 0.0;
  1108.                 //double dangerDist = interpolate(250.0, 75.0, 1.5*overpower, true);
  1109.                 //if (dist < dangerDist)
  1110.                 //{
  1111.                 //  hitProbability = interpolate(1.0, 0.8, dist/dangerDist, true);
  1112.                 //}
  1113.                 //else
  1114.                 //{
  1115.                 //  hitProbability = 0.8*hitProb(dist, 300.0)*phaseHitProb;
  1116.                 //  hitProbability = 0.8*hitProb(dist, 300.0)*phaseHitProb;
  1117.                 //}
  1118.                
  1119.                 if (tank.getPremiumShellCount() > 0)
  1120.                     expectedDamage += 35*hitProbability;
  1121.                 else
  1122.                     expectedDamage += 20*hitProbability;
  1123.                
  1124.                 aliveEnemyCount += 1;
  1125.             }
  1126.             else if (isAlive(tank) && tank.isTeammate() == true && tank.getId() != self.getId())
  1127.             {
  1128.                 double dist = distance(tankPos, p);
  1129.                 if      (dist < 100.0)
  1130.                     expectedDamage += 20.0*interpolate(1.0, 0.0, dist/100.0, true);
  1131.                 /*
  1132.                 else if (dist > 150.0 && dist < 300.0)
  1133.                     expectedDamage += 20.0*interpolate(-0.5, 0.0, (dist-150.0)/150.0, true);
  1134.                     */
  1135.             }
  1136.         }
  1137.        
  1138.         if (world.getTick() < 250)
  1139.         {
  1140.             ArrayList<Vector2D>  cornerPoints = new ArrayList<Vector2D>();
  1141.             cornerPoints.add(new Vector2D(100.0, 100.0));
  1142.             cornerPoints.add(new Vector2D(worldWidth - 100.0, 100.0));
  1143.             cornerPoints.add(new Vector2D(100.0, worldHeight - 100.0));
  1144.             cornerPoints.add(new Vector2D(worldWidth - 100.0, worldHeight - 100.0));
  1145.        
  1146.             Vector2D nearestCorner = new Vector2D(self.getX(), self.getY());
  1147.             double   minDist = Double.MAX_VALUE;
  1148.             for (Vector2D corner: cornerPoints)
  1149.             {
  1150.                 double dist = distance(corner, p);              
  1151.                 if (dist < minDist)
  1152.                 {
  1153.                     minDist = dist;
  1154.                     nearestCorner = corner;
  1155.                 }
  1156.             }
  1157.            
  1158.             double dist = distance(p, nearestCorner);
  1159.             if (dist < 800.0)
  1160.             {
  1161.                 expectedDamage += 20.0*interpolate(-2.0, 0.0, dist/800.0, true);
  1162.             }
  1163.         }
  1164.        
  1165.         return expectedDamage;
  1166.     }
  1167.  
  1168.     public enum ObstacleType
  1169.     {
  1170.         NONE,
  1171.         ALIVE_TANK,
  1172.         DEAD_TANK,
  1173.         TEAMMATE_TANK,
  1174.         BONUS,
  1175.         OBSTACLE,
  1176.     }
  1177.    
  1178.     public static class WorldObstacle
  1179.     {
  1180.         public double x;
  1181.         public double y;
  1182.         public double width;
  1183.         public double height;
  1184.         public double angle;
  1185.         public long   id;
  1186.         public ObstacleType type;  
  1187.     }
  1188.    
  1189.     public ArrayList<WorldObstacle> getWorldObstacles(World world)
  1190.     {
  1191.         ArrayList<WorldObstacle> worldObstacles = new ArrayList<WorldObstacle>();
  1192.         for (Tank tank: world.getTanks())
  1193.         {
  1194.             WorldObstacle wo = new WorldObstacle();
  1195.             wo.x = tank.getX();
  1196.             wo.y = tank.getY();
  1197.             wo.width = tank.getWidth();
  1198.             wo.height = tank.getHeight();
  1199.             wo.angle = tank.getAngle();
  1200.             wo.id = tank.getId();
  1201.             if (isAlive(tank))
  1202.             {
  1203.                 if (tank.isTeammate() == true)
  1204.                 {
  1205.                     wo.type = ObstacleType.TEAMMATE_TANK;
  1206.                 }
  1207.                 else
  1208.                 {
  1209.                     wo.type = ObstacleType.ALIVE_TANK;
  1210.                 }
  1211.             }
  1212.             else
  1213.             {
  1214.                 wo.type = ObstacleType.DEAD_TANK;
  1215.             }
  1216.            
  1217.             worldObstacles.add(wo);
  1218.         }
  1219.        
  1220.         for (Bonus bonus: world.getBonuses())
  1221.         {
  1222.             WorldObstacle wo = new WorldObstacle();
  1223.             wo.x = bonus.getX();
  1224.             wo.y = bonus.getY();
  1225.             wo.width = bonus.getWidth();
  1226.             wo.height = bonus.getHeight();
  1227.             wo.angle = bonus.getAngle();
  1228.             wo.id = bonus.getId();
  1229.             wo.type = ObstacleType.BONUS;
  1230.            
  1231.             worldObstacles.add(wo);
  1232.         }
  1233.        
  1234.         for (Obstacle obstacle: world.getObstacles())
  1235.         {
  1236.             WorldObstacle wo = new WorldObstacle();
  1237.             wo.x = obstacle.getX();
  1238.             wo.y = obstacle.getY();
  1239.             wo.width = obstacle.getWidth();
  1240.             wo.height = obstacle.getHeight();
  1241.             wo.angle = obstacle.getAngle();
  1242.             wo.id = obstacle.getId();
  1243.            
  1244.             wo.type = ObstacleType.OBSTACLE;
  1245.             worldObstacles.add(wo);
  1246.         }
  1247.    
  1248.         return worldObstacles;
  1249.     }
  1250.    
  1251.     public double travelTimeFront(Tank tank, Vector2D p)
  1252.     {
  1253.         Vector2D tankPos = new Vector2D(tank.getX(), tank.getY());
  1254.         Vector2D deltaPos = sub(p, tankPos);
  1255.         double turnAngle = angleBetween(fromAngle(tank.getAngle()), deltaPos);
  1256.         double distance = length(deltaPos);
  1257.        
  1258.         return distance/(4.0*0.8) + Math.abs(turnAngle)/0.017;
  1259.     }
  1260.    
  1261.     public double travelTimeBack(Tank tank, Vector2D p)
  1262.     {
  1263.         Vector2D tankPos = new Vector2D(tank.getX(), tank.getY());
  1264.         Vector2D deltaPos = sub(p, tankPos);
  1265.         double turnAngle = angleBetween(mul(-1.0, fromAngle(tank.getAngle())), deltaPos);
  1266.         double distance = length(deltaPos);
  1267.         return distance/(2.6*0.9) + Math.abs(turnAngle)/0.017;
  1268.     }
  1269.    
  1270.     public ArrayList<Vector2D> samplePotentialTargetPoints(Tank self, int n)
  1271.     {
  1272.         Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  1273.         int i = 0;
  1274.         int c = 0;
  1275.         ArrayList<Vector2D> pointList = new ArrayList<Vector2D>();
  1276.        
  1277.         while (i < n && c < 10*n)
  1278.         {
  1279.             c += 1;
  1280.             double angle = rand.nextGaussian()*Math.PI/4.0;
  1281.             if (angle > Math.PI/2.0)
  1282.                 angle = Math.PI/2.0;
  1283.             else if (angle < -Math.PI/2.0)
  1284.                 angle = -Math.PI/2.0;
  1285.            
  1286.             if (rand.nextBoolean())
  1287.             {
  1288.                 angle += Math.PI;
  1289.                 angle = normalizeAngle(angle);
  1290.             }
  1291.            
  1292.             double dist = rand.nextDouble()*500.0 + 70.0;
  1293.            
  1294.             Vector2D p = add(selfPos, mul(dist, fromAngle(angle)));
  1295.             double ribbonX = 100.0;
  1296.             double ribbonY = 100.0;
  1297.             if (p.x < (worldWidth - ribbonX) && p.x > ribbonX && p.y < (worldHeight - ribbonY) && p.y > ribbonY && dist > selfRadius)
  1298.             {
  1299.                 pointList.add(p);
  1300.                 i += 1;
  1301.             }
  1302.         }
  1303.        
  1304.         return pointList;
  1305.     }
  1306.    
  1307.     public Image drawDangerHeuristic(World world, Tank self)
  1308.     {
  1309.         double scale = 32.0;
  1310.         int width  = (int)Math.round(worldWidth/scale);
  1311.         int height = (int)Math.round(worldHeight/scale);
  1312.         BufferedImage heuristicImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  1313.        
  1314.         for (int y = 0; y < height; ++y)
  1315.         {
  1316.             for (int x = 0; x < width; ++x)
  1317.             {
  1318.                 Vector2D p = new Vector2D(x*scale, y*scale);
  1319.                 double heuristic = this.dangerHeuristic(world, p, self, false);
  1320.                 heuristicImage.setRGB(x, y, grayRgb(heuristic/100.0));
  1321.             }
  1322.         }
  1323.        
  1324.         return heuristicImage;
  1325.     }
  1326.    
  1327.     public int grayRgb(double a)
  1328.     {
  1329.         int c = (int)(255.0*a);
  1330.         if (a > 255)
  1331.             a = 255;
  1332.         if (a < 0)
  1333.             a = 0;
  1334.        
  1335.         return (c << 16) + (c << 8) + c;
  1336.     }
  1337.    
  1338.     public double getTurretAngle(Tank tank)
  1339.     {
  1340.         return normalizeAngle(tank.getAngle() + tank.getTurretRelativeAngle());
  1341.     }
  1342.    
  1343.     enum MoodState
  1344.     {
  1345.         DEFENCIVE,
  1346.         AGRESSIVE,
  1347.     }
  1348.    
  1349.     public enum TargetType
  1350.     {
  1351.         NONE,
  1352.         BONUS_MEDIKIT,
  1353.         BONUS_REPAIR,
  1354.         BONUS_AMMO,
  1355.     }
  1356.    
  1357.     public static class UtilityTarget
  1358.     {
  1359.         public Vector2D   pos;
  1360.         public double     utilityFront;
  1361.         public double     utilityBack;
  1362.         public TargetType type;
  1363.        
  1364.         public UtilityTarget(Vector2D pos)
  1365.         {
  1366.             this.pos = pos;
  1367.             this.utilityFront = 0.0;
  1368.             this.utilityBack  = 0.0;
  1369.             this.type = TargetType.NONE;
  1370.         }
  1371.     }
  1372.        
  1373.     public double        selfRadius;
  1374.     public double        selfWidth;
  1375.     public double        selfHeight;
  1376.     public double        selfHealth;
  1377.     public double        selfDurability;
  1378.     public Random        rand = new Random(1234);
  1379.     Map<Long, TankEntry> tankEntryById = new LinkedHashMap<Long, TankEntry>();
  1380.     public long          selfId;
  1381.     public static long       enemyTargetId = -1;
  1382.     public static  boolean   updateTargetsFlag = false;
  1383.    
  1384.     public ArrayList<UtilityTarget> potentialTargets = new ArrayList<UtilityTarget>();
  1385.     public ArrayList<UtilityTarget> utilityTargets = new ArrayList<UtilityTarget>();
  1386.     public double bonusUtilityScale = 600.0;
  1387.     public double damageUtilityScale = 100.0;
  1388.     public Vector2D firePredcitedPos = new Vector2D(0.0, 0.0);          
  1389.    
  1390.     public void updateUtility(World world, Tank self)
  1391.     {
  1392.         this.utilityTargets = new ArrayList<UtilityTarget>(potentialTargets);
  1393.        
  1394.         for (UtilityTarget uT: this.utilityTargets)
  1395.         {
  1396.             uT.utilityFront = 0.0;
  1397.             uT.utilityBack  = 0.0;
  1398.         }
  1399.        
  1400.         // add bonuses to targets
  1401.         for (Bonus bonus: world.getBonuses())
  1402.         {
  1403.             UtilityTarget uT = new UtilityTarget(new Vector2D(bonus.getX(), bonus.getY()));
  1404.             uT.type = TargetType.NONE;
  1405.             double travelCostFront = travelTimeFront(self, uT.pos);
  1406.             double travelCostBack  = travelTimeBack(self, uT.pos);
  1407.            
  1408.             if (bonus.getType() == BonusType.MEDIKIT)
  1409.             {
  1410.                 uT.type = TargetType.BONUS_MEDIKIT;
  1411.                 double utility = 1.5*(2.0 - selfHealth)*bonusUtilityScale;
  1412.                 uT.utilityFront = utility/travelCostFront;
  1413.                 uT.utilityBack  = utility/travelCostBack;
  1414.             }
  1415.             else if (bonus.getType() == BonusType.REPAIR_KIT)
  1416.             {
  1417.                 uT.type = TargetType.BONUS_REPAIR;
  1418.                 double utility = 1.5*(1.7 - selfDurability)*bonusUtilityScale;
  1419.                 uT.utilityFront = utility/travelCostFront;
  1420.                 uT.utilityBack  = utility/travelCostBack;
  1421.             }
  1422.             else if (bonus.getType() == BonusType.AMMO_CRATE)
  1423.             {
  1424.                 uT.type = TargetType.BONUS_AMMO;
  1425.                 double utility = 1.5*(1.0 - (1.0 - selfHealth)*(1.0 - selfDurability))*bonusUtilityScale;
  1426.                 uT.utilityFront = utility/travelCostFront;
  1427.                 uT.utilityBack  = utility/travelCostBack;
  1428.             }
  1429.            
  1430.             this.utilityTargets.add(uT);            
  1431.         }
  1432.        
  1433.         // evaluate potential damage utility
  1434.         Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  1435.         double   selfDamage = dangerHeuristic(world, selfPos, self, true);
  1436.         for (UtilityTarget uT: this.utilityTargets)
  1437.         {
  1438.             double travelCostFront = travelTimeFront(self, uT.pos);
  1439.             double travelCostBack  = travelTimeBack(self, uT.pos);
  1440.             double utilityFront = damageUtilityScale*(selfDamage - dangerHeuristic(world, uT.pos, self, false))/travelCostFront;
  1441.             double utilityBack  = damageUtilityScale*(selfDamage - dangerHeuristic(world, uT.pos, self, false))/travelCostBack;
  1442.             uT.utilityFront += utilityFront;
  1443.             uT.utilityBack  += utilityBack;
  1444.             if (enableDebug)
  1445.             {
  1446.                 debug.setColor(Color.GREEN);
  1447.                 debug.text(String.format("* (%.3f; %.3f)", dangerHeuristic(world, uT.pos, self, false), uT.utilityFront), uT.pos);
  1448.             }
  1449.         }      
  1450.     }
  1451.    
  1452.     public double tankPathLength(Tank self, int k)
  1453.     {
  1454.         TankEntry entry = this.tankEntryById.get(self.getId());
  1455.         ArrayList<Vector2D>  posHistory = entry.posHistory;
  1456.        
  1457.         int s = posHistory.size() - k;
  1458.         if (s < 0)
  1459.             s = 0;
  1460.        
  1461.         if (posHistory.size() < 3)
  1462.             return 0.0;
  1463.        
  1464.         double distSum = 0.0;
  1465.         for (int i = s; i + 1 < posHistory.size(); ++i)
  1466.         {
  1467.             distSum += distance(posHistory.get(i), posHistory.get(i + 1));
  1468.         }
  1469.         return distSum;
  1470.     }
  1471.    
  1472.     public int antiStuckFix = 0;
  1473.    
  1474.    
  1475.     double shellHitTime(double dist, ShellType shellType)
  1476.     {
  1477.         if (shellType == ShellType.REGULAR)
  1478.         {
  1479.             /*
  1480.             double a = 1.0 - dist*0.005/16.666666;
  1481.             if (a < 1E-3)
  1482.                 return 500.0;
  1483.             return Math.log(a)/Math.log(0.995);
  1484.             */
  1485.             return dist/16.0;
  1486.         }
  1487.         else
  1488.         {
  1489.             /*
  1490.             double a = 1.0 - dist*0.01/13.333333;
  1491.             if (a < 1E-3)
  1492.                 return 500.0;
  1493.             return Math.log(a)/Math.log(0.99);
  1494.             */
  1495.             return dist/13.0;
  1496.         }
  1497.     }
  1498.    
  1499.     public void simpleMove(Tank self, World world, Move move)
  1500.     {
  1501.         if (world.getTick() == 0)
  1502.         {
  1503.             initSystem();
  1504.             initSelf(self, world, move);
  1505.         }
  1506.                
  1507.         Vector2D selfPos = new Vector2D(self.getX(), self.getY());
  1508.         selfId = self.getId();
  1509.         selfWidth  = self.getWidth();
  1510.         selfHeight = self.getHeight();
  1511.         selfRadius = length(new Vector2D(self.getHeight()*0.5, self.getWidth()*0.5));
  1512.         this.selfHealth  = (1.0*self.getCrewHealth())/self.getCrewMaxHealth();
  1513.         this.selfDurability = (1.0*self.getHullDurability())/self.getHullMaxDurability();
  1514.         ArrayList<Bonus> bonusList = new ArrayList<Bonus>(Arrays.asList(world.getBonuses()));
  1515.         ArrayList<Tank>  tankList = new ArrayList<Tank>(Arrays.asList(world.getTanks()));
  1516.    
  1517.         debug.clear();
  1518.        
  1519.         // update history
  1520.         for (Tank tank: world.getTanks())
  1521.         {
  1522.             TankEntry entry = this.tankEntryById.get(tank.getId());
  1523.             entry.thisTank = tank;
  1524.             entry.posHistory.add(new Vector2D(tank.getX(), tank.getY()));
  1525.             entry.angleHistory.add(tank.getAngle());
  1526.             entry.angularSpeedHistory.add(tank.getAngularSpeed());
  1527.             entry.speedHistory.add(getTankSpeed(tank));
  1528.             entry.velocityHistory.add(new Vector2D(tank.getSpeedX(), tank.getSpeedY()));
  1529.            
  1530.             if (entry.speedHistory.size() >= 2)
  1531.             {
  1532.                 int sz = entry.speedHistory.size();
  1533.                 entry.accelHistory.add(entry.speedHistory.get(sz - 1) - entry.speedHistory.get(sz - 2));
  1534.             }
  1535.             else
  1536.             {
  1537.                 entry.accelHistory.add(0.0);
  1538.             }
  1539.         }      
  1540.        
  1541.         // draw kinematic prediction
  1542.         if (enableDebug)
  1543.         {
  1544.             for (Tank tank: world.getTanks())
  1545.             {  
  1546.                 ArrayList<Vector2D> predictLine = new ArrayList<Vector2D>();
  1547.                
  1548.                 Vector2D tankPos  = new Vector2D(tank.getX(), tank.getY());
  1549.                 Vector2D front    = fromAngle(tank.getAngle());
  1550.                 Vector2D frontPos = add(tankPos, mul(self.getWidth()*0.5, front));
  1551.                  
  1552.                 double   timeToHit = distance(selfPos, tankPos)/15.0;
  1553.                 Vector2D hitPoint = predictKinematic(tank, timeToHit).p;
  1554.                
  1555.                 ArrayList<Vector2D> predictPath = new ArrayList<Vector2D>();
  1556.                 for (int t = 0; t < 30; t += 1)
  1557.                 {
  1558.                     predictPath.add(predictKinematic(tank, t).p);
  1559.                 }
  1560.                
  1561.                 if (tank.getId() != self.getId())
  1562.                 {
  1563.                     debug.setColor(Color.RED);
  1564.                     debug.text("h", hitPoint);
  1565.                 }
  1566.                
  1567.                 debug.setColor(Color.GREEN);
  1568.                 debug.drawPolyLine(predictPath);
  1569.             }
  1570.         }
  1571.        
  1572.        
  1573.         // evaluate world state and make planing
  1574.         updateTargetsFlag = false;
  1575.         if (world.getTick() % 150 == 0)
  1576.         {
  1577.             updateTargetsFlag = true;
  1578.             this.potentialTargets.clear();
  1579.             for (Vector2D p:  samplePotentialTargetPoints(self, 50))
  1580.             {
  1581.                 this.potentialTargets.add(new UtilityTarget(p));
  1582.             }
  1583.         }
  1584.  
  1585.         // find new enemy
  1586.         // enemyTargetId - static, so all tanks attack same target
  1587.         if (updateTargetsFlag || isAlive(this.tankEntryById.get(this.enemyTargetId).thisTank) == false)
  1588.         {
  1589.  
  1590.             long newEnemyTargetId = 0;
  1591.             Tank teamMate = self;
  1592.             for (Tank tank: world.getTanks())
  1593.             {  
  1594.                 if (tank.isTeammate() == true && tank.getId() != self.getId() && isAlive(tank) == true)
  1595.                 {
  1596.                     teamMate = tank;
  1597.                 }
  1598.             }
  1599.            
  1600.             // find target with minimal distance sum to self and team mate
  1601.             Vector2D teamMatePos = new Vector2D(teamMate.getX(), teamMate.getY());
  1602.             double minDistance = Double.MAX_VALUE;          
  1603.             for (Tank tank: world.getTanks())
  1604.             {
  1605.                 if (isAlive(tank) && tank.isTeammate() == false)
  1606.                 {
  1607.                     Vector2D tankPos = new Vector2D(tank.getX(), tank.getY());
  1608.  
  1609.                     double dist = distance(selfPos, tankPos) + distance(teamMatePos, tankPos);
  1610.                     if (dist < minDistance)
  1611.                     {
  1612.                         minDistance = dist;
  1613.                         newEnemyTargetId = tank.getId();
  1614.                     }
  1615.                 }
  1616.             }
  1617.            
  1618.             // if we already have enemy target
  1619.             if (this.enemyTargetId != -1)
  1620.             {
  1621.                 Tank oldEnemy = this.tankEntryById.get(this.enemyTargetId).thisTank;
  1622.                 Vector2D oldEnemyPos = new Vector2D(oldEnemy.getX(), oldEnemy.getY());
  1623.                 Tank newEnemy = this.tankEntryById.get(newEnemyTargetId).thisTank;
  1624.                 Vector2D newEnemyPos = new Vector2D(newEnemy.getX(), newEnemy.getY());
  1625.                 double distNew = distance(selfPos, newEnemyPos) + distance(teamMatePos, newEnemyPos);
  1626.                 double distOld = distance(selfPos, oldEnemyPos) + distance(teamMatePos, oldEnemyPos);
  1627.                
  1628.                 // evaluate is better to switch or keep old target
  1629.                 if ((distNew < distOld*0.7) || (isAlive(oldEnemy) == false))
  1630.                 {
  1631.                     this.enemyTargetId = newEnemyTargetId;
  1632.                 }
  1633.             }
  1634.             else
  1635.             {
  1636.                 this.enemyTargetId = newEnemyTargetId;
  1637.             }
  1638.                                    
  1639.             updateTargetsFlag = false;          
  1640.         }
  1641.        
  1642.         debug.drawImage(this.drawDangerHeuristic(world, self));
  1643.        
  1644.         debug.drawWorld(world);
  1645.  
  1646.         // update utility calculations
  1647.         updateUtility(world, self);
  1648.        
  1649.         // find max utility target, for two movement choice: moving frontal, or moving back
  1650.         // each utility target calculated "utility" base on this two movement choices
  1651.         UtilityTarget maxFrontUtilityTarget = new UtilityTarget(selfPos);
  1652.         double maxFrontUtility = -Double.MAX_VALUE;
  1653.         for (UtilityTarget uT: this.utilityTargets)
  1654.         {
  1655.             if (uT.utilityFront > maxFrontUtility)
  1656.             {
  1657.                 maxFrontUtilityTarget = uT;
  1658.                 maxFrontUtility       = uT.utilityFront;
  1659.             }
  1660.         }
  1661.        
  1662.         UtilityTarget maxBackUtilityTarget = new UtilityTarget(selfPos);
  1663.         double maxBackUtility = -Double.MAX_VALUE;
  1664.         for (UtilityTarget uT: this.utilityTargets)
  1665.         {
  1666.             if (uT.utilityBack > maxBackUtility)
  1667.             {
  1668.                 maxBackUtilityTarget = uT;
  1669.                 maxBackUtility = uT.utilityBack;
  1670.             }
  1671.         }
  1672.        
  1673.         // some debug visualisation
  1674.         debug.setColor(Color.RED);
  1675.         debug.text("*", maxFrontUtilityTarget.pos);
  1676.        
  1677.         debug.setColor(Color.MAGENTA);
  1678.         debug.text("O", maxBackUtilityTarget.pos);
  1679.        
  1680.         // find enemy tank by id
  1681.         Tank       enemyTank = this.tankEntryById.get(this.enemyTargetId).thisTank;
  1682.         Vector2D   enemyPos = new Vector2D(enemyTank.getX(), enemyTank.getY());
  1683.        
  1684.         debug.setColor(Color.MAGENTA);
  1685.         debug.text("E", enemyPos);
  1686.  
  1687.         double moveAngleDelta = 0.0;
  1688.         double leftPower  = 0.0;
  1689.         double rightPower = 0.0;
  1690.         boolean isMoveBack = false;
  1691.        
  1692.         debug.setColor(Color.BLACK);
  1693.         debug.text(String.format("(%f, %f)", maxFrontUtility, maxBackUtility), 100, 20);
  1694.        
  1695.                
  1696.         // find max utility and choose movment type
  1697.         if (maxFrontUtility > maxBackUtility)
  1698.         {
  1699.             debug.setColor(Color.GREEN);
  1700.             debug.text("FRONT", selfPos.x, selfPos.y + 20);
  1701.             Vector2D moveError = sub(maxFrontUtilityTarget.pos, selfPos);
  1702.             moveAngleDelta = angleBetween(self.getAngle(), toAngle(moveError));
  1703.            
  1704.             // move    
  1705.             isMoveBack = false;
  1706.         }
  1707.         else
  1708.         {
  1709.             debug.setColor(Color.BLUE);
  1710.             debug.text("BACK", selfPos.x, selfPos.y + 20);
  1711.             Vector2D moveError = sub(maxBackUtilityTarget.pos, selfPos);
  1712.             moveAngleDelta = angleBetween(mul(-1.0, fromAngle(self.getAngle())), moveError);
  1713.            
  1714.             isMoveBack = true;
  1715.         }
  1716.        
  1717.         // basic movement
  1718.         if (isMoveBack)
  1719.         {
  1720.             if (moveAngleDelta < 0.0)
  1721.             {
  1722.                 rightPower = -1.0;
  1723.                 leftPower =interpolate(-1.0, 0.75, 3.0*Math.abs(moveAngleDelta)/Math.PI, true);
  1724.             }
  1725.             else
  1726.             {
  1727.                 rightPower = interpolate(-1.0, 0.75, 3.0*Math.abs(moveAngleDelta)/Math.PI, true);
  1728.                 leftPower = -1.0;
  1729.             }          
  1730.         }
  1731.         else
  1732.         {
  1733.             if (moveAngleDelta > 0.0)
  1734.             {
  1735.                 leftPower  = 1.0;
  1736.                 rightPower = interpolate(1.0, -1.0, 2.5*Math.abs(moveAngleDelta)/Math.PI, true);
  1737.             }
  1738.             else
  1739.             {
  1740.                 leftPower  = interpolate(1.0, -1.0, 2.5*Math.abs(moveAngleDelta)/Math.PI, true);
  1741.                 rightPower = 1.0;
  1742.             }
  1743.         }
  1744.        
  1745.         //Vector2D moveTarget = maxUtilityTarget.pos;
  1746.                
  1747.        
  1748.         // try to predict enemy movement, ie point that our tank turret try to target
  1749.         double shellSpeed = 16.0;
  1750.         if (self.getPremiumShellCount() > 0)
  1751.             shellSpeed = 13.0;
  1752.        
  1753.         double   distanceToEnemy = distance(selfPos, enemyPos);
  1754.         double   hitTime = distanceToEnemy/shellSpeed;
  1755.         Vector2D turretTargetPos = enemyPos;
  1756.         if (distanceToEnemy < 700.0)
  1757.         {
  1758.             turretTargetPos = predictMinMax(enemyTank, selfPos, hitTime);
  1759.         }
  1760.         else
  1761.         {
  1762.             turretTargetPos = interpolate(enemyPos, predictKinematic(enemyTank, hitTime).p, 0.7, true);
  1763.         }
  1764.        
  1765.         double turretTargetAngle = angleBetween(sub(turretTargetPos, selfPos), fromAngle(getTurretAngle(self)));
  1766.         double turretSpeed = 3.14/180.0;
  1767.         double turretTurn = 0.0;
  1768.        
  1769.         // simple move turret base on angle delta
  1770.         if (turretTargetAngle > 0.0)
  1771.         {
  1772.             turretTurn = +1.0;
  1773.         }
  1774.         else
  1775.         {
  1776.             turretTurn = -1.0;
  1777.         }
  1778.                  
  1779.         move.setTurretTurn(turretTurn);
  1780.                
  1781.        
  1782.         boolean isFire = false;
  1783.         // move turret
  1784.         // use angular speed to improve accuracy
  1785.  
  1786.         // calculate error if fire with current turret orientation and target position
  1787.         // if error to large, wait for next tick
  1788.         Vector2D turretD = fromAngle(getTurretAngle(self));
  1789.         double turretT = nearestPointAtRay(turretTargetPos, selfPos, turretD);
  1790.         if (turretT > 0)
  1791.         {
  1792.             Vector2D pointAtRay = add(selfPos, mul(turretT, turretD));
  1793.             if (distance(pointAtRay, turretTargetPos) < 5.0)
  1794.             {
  1795.                 isFire = true;
  1796.             }
  1797.         }
  1798.  
  1799.         // check if path of fired shell free from obstacles (bonuses, dead tanks, teammates, etc)
  1800.         boolean haveObstacle = false;
  1801.         for (WorldObstacle obstacle: getWorldObstacles(world))
  1802.         {
  1803.             if (obstacle.id == selfId)
  1804.                 continue;
  1805.            
  1806.             if (obstacle.type == ObstacleType.ALIVE_TANK)
  1807.                 continue;
  1808.            
  1809.             Vector2D obstaclePos = new Vector2D(obstacle.x, obstacle.y);
  1810.             double obstacleRadius = length(new Vector2D(obstacle.height*0.5, obstacle.width*0.5));
  1811.            
  1812.             Vector2D td = fromAngle(getTurretAngle(self));
  1813.             double tt = nearestPointAtRay(obstaclePos, selfPos, td);
  1814.             if (tt > 0)
  1815.             {
  1816.                 Vector2D pointAtRay = add(selfPos, mul(tt, td));
  1817.                 if (distance(pointAtRay, obstaclePos) < obstacleRadius)
  1818.                 {
  1819.                     haveObstacle = true;
  1820.                     break;
  1821.                 }
  1822.             }
  1823.         }
  1824.  
  1825.  
  1826.        
  1827.        
  1828.         if (isFire && self.getRemainingReloadingTime() == 0)
  1829.         {
  1830.             this.firePredcitedPos = turretTargetPos;
  1831.         }
  1832.        
  1833.         debug.setColor(Color.BLUE);
  1834.         debug.text("o", this.firePredcitedPos);
  1835.        
  1836.         // fire if we can
  1837.         if (isFire == true && haveObstacle == false)
  1838.         {
  1839.             move.setFireType(FireType.PREMIUM_PREFERRED);
  1840.         }
  1841.         else
  1842.         {
  1843.             move.setFireType(FireType.NONE);
  1844.         }
  1845.  
  1846.         // shell avoidance logic
  1847.         // find shell ray with nearest distance to self
  1848.         double nearestShellDistance = Double.MAX_VALUE;
  1849.         Vector2D nearestShellRayPoint = new Vector2D(0.0, 0.0);
  1850.         Shell  nearestShell = null;
  1851.         for (Shell shell: world.getShells())
  1852.         {
  1853.             Vector2D d  = fromAngle(shell.getAngle());
  1854.             Vector2D sp = new Vector2D(shell.getX(), shell.getY());
  1855.            
  1856.             double t = nearestPointAtRay(selfPos, sp, d);
  1857.             if (t > 0.0)
  1858.             {
  1859.                 Vector2D rp = add(sp, mul(t, d));
  1860.                 Vector2D delta = sub(rp, selfPos);
  1861.                 double dist = length(delta);
  1862.                 if (dist < nearestShellDistance)
  1863.                 {
  1864.                     nearestShellRayPoint = rp;
  1865.                     nearestShell = shell;
  1866.                     nearestShellDistance = dist;
  1867.                 }
  1868.             }
  1869.         }
  1870.        
  1871.        
  1872.         if (nearestShell != null)
  1873.         {
  1874.             debug.setColor(Color.CYAN);
  1875.             debug.line(selfPos, nearestShellRayPoint);
  1876.  
  1877.             // check if distance to shell ray is really near
  1878.             if (nearestShellDistance < selfRadius*1.5)
  1879.             {
  1880.                 // try to calculate two variants of actions
  1881.                 // 1. move front at full speed
  1882.                 // 2. move back at full speed
  1883.                 // partially based on physic reverse engeenering at gamedev.ru
  1884.                 Vector2D d  = fromAngle(nearestShell.getAngle());
  1885.                 Vector2D sp = new Vector2D(nearestShell.getX(), nearestShell.getY());
  1886.                 Vector2D selfDir   = fromAngle(self.getAngle());
  1887.                 Vector2D selfVel   = new Vector2D(self.getSpeedX(), self.getSpeedY());
  1888.                 double   selfSpeed = length(selfVel)*Math.signum(dotProduct(selfDir, selfVel));
  1889.  
  1890.                 double   nt = nearestPointAtRay(selfPos, sp, d);
  1891.                 Vector2D np = add(sp, mul(nt, d));
  1892.                 double   nd   = dotProduct(selfDir, sub(np, selfPos));
  1893.                 double  dist = distance(selfPos, sp);
  1894.                 double  ht = this.shellHitTime(dist, nearestShell.getType());
  1895.                
  1896.                 double health = (1.0*self.getCrewHealth())/self.getCrewMaxHealth();
  1897.                 double frontA = self.getEnginePower()*(0.5 + 0.5*health)/(10.0*60.0);
  1898.                 double backA  = -self.getEnginePower()*self.getEngineRearPowerFactor()*(0.5 + 0.5*health)/(10.0*60.0);
  1899.                 double b = 1.0 - (0.5/10.0);
  1900.  
  1901.                
  1902.                 double frontDelta = predictDistance(frontA, b, selfSpeed, ht) - self.getWidth() - nd;
  1903.                 double backDelta  = predictDistance(backA, b, selfSpeed, ht) + self.getWidth() - nd;
  1904.                 if (frontDelta > 0.0)
  1905.                 {
  1906.                     leftPower = 1.0;
  1907.                     rightPower = 1.0;
  1908.                 }
  1909.                 else if (backDelta < 0.0)
  1910.                 {
  1911.                     leftPower = -1.0;
  1912.                     rightPower = -1.0;
  1913.                 }
  1914.                 else if (nd > 0.5*self.getWidth())
  1915.                 {
  1916.                     leftPower  = -1.0;
  1917.                     rightPower = -1.0;
  1918.                 }
  1919.                 else
  1920.                 {
  1921.                     leftPower  = 1.0;
  1922.                     rightPower = 1.0;
  1923.                 }
  1924.                  
  1925.                 debug.setColor(Color.MAGENTA);
  1926.                 debug.text(String.format("(%f, %f), %f", frontDelta, backDelta, nd), 40, 200);              
  1927.             }          
  1928.         }
  1929.        
  1930.        
  1931.         // at start always move back
  1932.         if (world.getTick() < 10.0)
  1933.         {
  1934.             leftPower = -1.0;
  1935.             rightPower = -1.0;
  1936.         }
  1937.  
  1938.         move.setLeftTrackPower(leftPower);
  1939.         move.setRightTrackPower(rightPower);
  1940.        
  1941.         debug.drawMove(self, move);
  1942.         debug.present();
  1943.     }
  1944.    
  1945.     @Override
  1946.     public void move(Tank self, World world, Move move)
  1947.     {
  1948.         try
  1949.         {
  1950.             this.simpleMove(self, world, move);
  1951.         }
  1952.         catch (Exception ex)
  1953.         {
  1954.             enableDebug = false;
  1955.         }
  1956.     }
  1957.    
  1958.  
  1959.     @Override
  1960.     public TankType selectTank(int tankIndex, int teamSize)
  1961.     {
  1962.         return TankType.MEDIUM;
  1963.     }
  1964. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement