Guest User

Honeypot Tank AI

a guest
Aug 11th, 2015
1,535
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var api = require('./API.js');
  2.  
  3. /* Configuration */
  4.     var verbose = false;
  5.     var avatars = ["▲","◄","▼","►"];
  6.     var icon = {
  7.         target: "x",
  8.         obstacle_unknown: "▒",
  9.         obstacle_wall: "▓",
  10.         unknown: "░",
  11.         empty: " "
  12.     };
  13.  
  14. /** FRMEWORK **/
  15.  
  16. /* Robot data */
  17. // Tank object default conditions
  18.     var tank = {
  19.         max_range: 4, // Maximum shooting distance. Long shots can miss moving targets and waste time
  20.        
  21.         // ezpz GPS
  22.         lidar: { front: 0, back: 0, left: 0, right: 0 },
  23.         o_lidar: { up: 0, down: 0, left: 0, right: 0 }, // lidar information aligned to map's u/d/l/r
  24.         lidar_object: { front: false, back: false, left: false, right: false },
  25.         traveled: { o_up: 0, o_down: 0, o_left: 0, o_right: 0 },
  26.         status: {},
  27.         rotation: 0,
  28.         coords: [0, 0], // 0,0 = top left
  29.         x: 0,
  30.         y: 0
  31.     };
  32.     tank.reset = function(){
  33.         tank.status = {
  34.             turning_around: false,
  35.             shots_fired: tank.status.shots_fired || 0,
  36.             shots_fired_in_a_row: 0,
  37.             ticks: tank.status.ticks || 0,
  38.             tick: { action_done: false },
  39.             directive: { active: false, name: false, direction: false, distance: 0, steps: 0 },
  40.             combat: { active: false, time_since_last_shot: 0,
  41.                 chasing: false, chase_remaining: false, chase_target_seen_count: 0, last_shot_range: 0
  42.             }
  43.         };
  44.         tank.expected_lidar = { front: false, back: false, left: false, right: false };
  45.     }
  46.     tank.reset();
  47.     tank.directives = ["explore", "explore_half", "investigate"];
  48.  
  49.  
  50. // Map object default conditions
  51.     var map = Array("");
  52.     var map_mins = [1,1];
  53.  
  54.  
  55. /* Mapping functions */
  56.     function build_map(){
  57.         notice("Updating map.");
  58.         lidars = [tank.lidar.front, tank.lidar.left, tank.lidar.back, tank.lidar.right];
  59.         r = tank.rotation;
  60.         o_up = lidars[(4 - r) % 4];
  61.         o_left = lidars[(5 - r) % 4];
  62.         o_down = lidars[(6 - r) % 4];
  63.         o_right = lidars[(7 - r) % 4];
  64.         tank.o_lidar = {up: o_up, down: o_down, left: o_left, right: o_right };
  65.        
  66.         y = tank.coords[1];
  67.         x = tank.coords[0];
  68.         h = (o_up > y ? o_up : y) + 1 + (map.length - y -1 > o_down ? map.length - y - 1 : o_down);
  69.         w = (o_left > x ? o_left : x) + 1 + (map[0].length - x - 1 > o_right ? map[0].length - x - 1 : o_right);
  70.         if(map_mins[0] < w) map_mins[0] = w;
  71.         if(map_mins[1] < h) map_mins[1] = h;
  72.    
  73.         increase_map_if_needed(h, w, o_up, o_down, o_right, o_left);
  74.         ray_trace(o_up, o_down, o_right, o_left);
  75.     }
  76.     function increase_map_if_needed(h, w, o_up, o_down, o_right, o_left){
  77.         if(map.length >= h && map[0].length >= w) return;
  78.    
  79.         x = tank.coords[0];
  80.         y = tank.coords[1];
  81.         m_height = map.length;
  82.         m_width = map[0].length;
  83.         y_pos = y_neg = x_pos = x_neg = 0;
  84.        
  85.         if(m_height < h){
  86.             if(y < o_up) y_pos = o_up - y;
  87.             if(y_pos + m_height < h) y_neg = h - y_pos - m_height;
  88.         }
  89.         if(m_width < w){
  90.             if(x < o_left) x_neg = o_left - x;
  91.             if(x_neg + m_width < w) x_pos = w - x_neg - m_width;
  92.         }
  93.        
  94.         subnotice("Increase internal map size from [" + map[0].length + ", " + map.length +"] to [" + w + ", " + h + "] by adding " +
  95.             "[x+:" + x_pos + ", x-:" + x_neg + ", y+:" + y_pos + ", y-:" + y_neg + "]");
  96.         increase_map(y_pos, y_neg, x_pos, x_neg);
  97.         tank.coords[0] = x + x_neg;
  98.         tank.coords[1] = y + y_pos;
  99.     }
  100.     function increase_map(y_pos, y_neg, x_pos, x_neg){
  101.         // Pad existing rows with additional width and height
  102.         for(var row = 0; row < map.length; row++){
  103.             map[row] = Array(x_neg+1).join(icon.unknown) + map[row] + Array(x_pos+1).join(icon.unknown);
  104.         }
  105.         // Add new rows to the top
  106.         for(var higher = 0; higher < y_pos; higher++){ map.unshift(new_row()); }
  107.         // Add new rows to the bottom
  108.         for(var lower = 0; lower < y_neg; lower++){ map.push(new_row()); }
  109.     }
  110.     function ray_trace(o_up, o_down, o_right, o_left){
  111.         x = tank.coords[0];
  112.         y = tank.coords[1];
  113.    
  114.         // Redraw our horizontal row
  115.         splice(y, x - o_left, icon_for(x-o_left,y) + empty(o_left) + avatars[tank.rotation] + empty(o_right) + icon_for(x+o_right,y), x+o_right+1);
  116.        
  117.         // Redraw our verticals
  118.         for(var row_up = y-1; row_up > y-o_up; row_up--){ map[row_up] = map[row_up].substring(0,x) + icon.empty + map[row_up].substring(x+1); }
  119.         splice(y-o_up, x, icon_for(x,y-o_up), x+1);
  120.         for(var row_down = y+1; row_down < y+o_down; row_down++){ map[row_down] = map[row_down].substring(0,x) + icon.empty + map[row_down].substring(x+1); }
  121.         splice(y+o_down, x, icon_for(x,y+o_down), x+1);
  122.        
  123.         // Identify ahead
  124.         ends = [[x,y-o_up],[x-o_left,y],[x,y+o_down],[x+o_right,y]][tank.rotation];
  125.         splice(ends[1], ends[0], api.identifyTarget() ? icon.target : icon.obstacle_wall, ends[0]+1);
  126.     }
  127.  
  128.  
  129. /* Utility functions */
  130.     function icon_for(x,y){
  131.         v = map[y].substr(x,1);
  132.         if(v == icon.obstacle_wall) return v;
  133.         if(v == icon.target) return v;
  134.         return icon.obstacle_unknown;
  135.     }
  136.     function empty(length){
  137.         return Array(length).join(icon.empty);
  138.     }
  139.     function splice(row, x1, new_text, x2){
  140.         map[row] = map[row].substring(0,x1) + new_text + map[row].substring(x2);
  141.     }
  142.     function new_row(){
  143.         return Array(map_mins[0]+1).join(icon.unknown);
  144.     }
  145.     function warn(msg){ console.log("╞ " + msg); }
  146.     function notice(msg){ if(verbose) console.log("├ " + msg); }
  147.     function subnotice(msg){ if(verbose) console.log("│\t└────\t" + msg); }
  148.     function subsubnotice(msg){ if(verbose) console.log("│\t\t└────\t" + msg); }
  149.     function act(msg){ console.log("▌ " + msg); }
  150.     function alt_subnotice(msg){ if(verbose) console.log("│\t\t"+ msg); }
  151.     function tank_stats(){
  152.         notice("Tank Stats:\tFuel: "+api.currentFuel()+", Target ahead? "+(api.identifyTarget()?"Yes":"No"));
  153.         alt_subnotice("Rotation: "+avatars[tank.rotation]+" ("+tank.rotation+")");
  154.         alt_subnotice("Lidar:    ^:"+tank.lidar.front+"  v:"+tank.lidar.back+"  <:"+tank.lidar.left+"  >:"+tank.lidar.right);
  155.         alt_subnotice("Aligned*: "+avatars[0]+":"+o_up+"  "+avatars[1]+":" + o_down + "  "+avatars[2]+":" + o_left + "  "+avatars[3]+":" + o_right);
  156.         alt_subnotice("Expected: ^:"+tank.expected_lidar.front+"  v:"+tank.expected_lidar.back+"  <:"+tank.expected_lidar.left+"  >:"+tank.expected_lidar.right);
  157.         alt_subnotice("Travled:  "+avatars[0]+":"+tank.traveled.o_up+"  "+avatars[1]+":"+tank.traveled.o_down+"  "+avatars[2]+":"+tank.traveled.o_left+"  "+avatars[3]+":"+tank.traveled.o_right);
  158.     }
  159.     function map_stats(){
  160.         notice("Map Stats:\tTank "+avatars[tank.rotation]+" @["+tank.coords[0]+", "+
  161.             tank.coords[1]+"], Map size ["+map[0].length+", "+map.length+"]   (top left is 0,0)");
  162.         map.forEach(function(row){ alt_subnotice(row); });
  163.     }
  164.  
  165.  
  166. /* Tank functions */
  167. // Simple Actions
  168.     tank.sense = function(){
  169.         tank.scan();
  170.         if(api.identifyTarget()){
  171.             subnotice("Scanning target: Enemy!")
  172.             tank.status.combat.active = true;
  173.         } else {
  174.             subnotice("Scanning target: Clear.")
  175.         }
  176.         build_map();
  177.         tank.update_coords();
  178.     }
  179.     tank.scan = function(){
  180.         notice("Running lidar scans.");
  181.         tank.lidar.front = api.lidarFront();
  182.         tank.lidar.back  = api.lidarBack();
  183.         tank.lidar.left  = api.lidarLeft();
  184.         tank.lidar.right = api.lidarRight();
  185.     }
  186.     tank.forward = function(){
  187.         if(api.lidarFront() <= 1 || tank.status.tick.action_done) return;
  188.         act("DRIVING FORWARD");
  189.         if( tank.rotation===0)     { tank.coords[1]--; tank.traveled.o_up++; }
  190.         else if(tank.rotation==1) { tank.coords[0]--; tank.traveled.o_left++; }
  191.         else if(tank.rotation==2) { tank.coords[1]++; tank.traveled.o_down++; }
  192.         else if(tank.rotation==3) { tank.coords[0]++; tank.traveled.o_right++; }
  193.         tank.expected_lidar.back = tank.lidar.back + 1;
  194.         tank.expected_lidar.left = tank.expected_lidar_to_front_left();
  195.         tank.expected_lidar.right = tank.expected_lidar_to_front_right();
  196.         api.moveForward();
  197.         tank.status.tick.action_done = true;
  198.         tank.status.shots_fired_in_a_row = 0;
  199.     }
  200.     tank.backward = function(){
  201.         if(api.lidarBack() <= 1 || tank.status.tick.action_done) return;
  202.         act("DRIVING BACKWARD");
  203.         if( tank.rotation===0)     { tank.coords[1]++; tank.traveled.o_down++; }
  204.         else if(tank.rotation==1) { tank.coords[0]++; tank.traveled.o_right++; }
  205.         else if(tank.rotation==2) { tank.coords[1]--; tank.traveled.o_up++; }
  206.         else if(tank.rotation==3) { tank.coords[0]--; tank.traveled.o_left++; }
  207.         tank.expected_lidar.back = tank.lidar.back - 1;
  208.         tank.expected_lidar.left = tank.expected_lidar_to_back_left();
  209.         tank.expected_lidar.right = tank.expected_lidar_to_back_right();
  210.         api.moveBackward();
  211.         tank.status.tick.action_done = true;
  212.         tank.status.shots_fired_in_a_row = 0;
  213.     }
  214.     tank.turn_left= function(){
  215.         if(tank.status.tick.action_done) return;
  216.         act("TURNING LEFT");
  217.         tank.rotation++;
  218.         if(tank.rotation > 3) tank.rotation = 0;
  219.         tank.expected_lidar.back = tank.lidar.right;
  220.         tank.expected_lidar.right = tank.lidar.front;
  221.         tank.expected_lidar.left = tank.lidar.back;
  222.         api.turnLeft();
  223.         tank.status.tick.action_done = true;
  224.         tank.status.shots_fired_in_a_row = 0;
  225.     }
  226.     tank.turn_right= function(){
  227.         if(tank.status.tick.action_done) return;
  228.         act("TURNING RIGHT");
  229.         tank.rotation--;
  230.         if(tank.rotation < 0) tank.rotation = 3;
  231.         tank.expected_lidar.back = tank.lidar.left;
  232.         tank.expected_lidar.left = tank.lidar.front;
  233.         tank.expected_lidar.right = tank.lidar.back;
  234.         api.turnRight();
  235.         tank.status.tick.action_done = true;
  236.         tank.status.shots_fired_in_a_row = 0;
  237.     }
  238.     tank.shoot = function(){
  239.         if(tank.status.tick.action_done) return;
  240.         act("FIRING CANON");
  241.         api.fireCannon();
  242.         tank.status.tick.action_done = true;
  243.         tank.status.combat.time_since_last_shot = 0;
  244.         tank.status.shots_fired_in_a_row++;
  245.         tank.status.combat.last_shot_range = tank.lidar.front;
  246.     }
  247. // Special Actions
  248.     tank.start_turning_around = function(){
  249.         subnotice("Turning around (1/2)");
  250.         tank.status.turning_around = true;
  251.         tank.turn_right();
  252.     };
  253.     tank.finish_turning_around = function(){
  254.         if(!tank.status.turning_around){ warn("Warning! Trying to finish a turn we never started!"); return; }
  255.         subnotice("Still turning around (2/2)");
  256.         tank.status.turning_around = false;
  257.         tank.turn_right();
  258.     };
  259.     tank.turn_towards = function(rotation){
  260.         if(tank.rotation == rotation) return;
  261.         if(rotation !== 0 && rotation != 1 && rotation != 2 && rotation != 3) return;
  262.         subnotice("Turning to from " + avatars[tank.rotation] + " to face " + avatars[rotation]);
  263.         if(tank.rotation === 0){
  264.             if(rotation == 1){ tank.turn_left(); }
  265.             else if(rotation == 2){ tank.start_turning_around(); }
  266.             else{ tank.turn_right(); }
  267.         } else if(tank.rotation == 1){
  268.             if(rotation === 0){ tank.turn_right(); }
  269.             else if(rotation == 2){ tank.turn_left(); }
  270.             else{ tank.start_turning_around(); }
  271.         } else if(tank.rotation == 2){
  272.             if(rotation === 0){ tank.start_turning_around(); }
  273.             else if(rotation == 1){ tank.turn_right(); }
  274.             else{ tank.turn_left(); }
  275.         } else {
  276.             if(rotation === 0){ tank.turn_left(); }
  277.             else if(rotation == 1){ tank.start_turning_around(); }
  278.             else{ tank.turn_right(); }
  279.         }
  280.     };
  281.     tank.turn_towards_closest_unknown_ping = function(){
  282.         r_dist = tank.lidar_object.right == icon.obstacle_wall ? false : tank.lidar.right;
  283.         l_dist = tank.lidar_object.left == icon.obstacle_wall ? false : tank.lidar.left;
  284.         b_dist = tank.lidar_object.back == icon.obstacle_wall ? false : tank.lidar.back;
  285.         if(r_dist == l_dist && l_dist == b_dist && b_dist === false){ subnotice("All pings are known walls."); return; }
  286.         subnotice("Turning towards the closest unidentified ping.");
  287.        
  288.         opts = [[function(){tank.turn_right()},r_dist], [function(){tank.turn_left()},l_dist],[function(){tank.start_turning_around()},b_dist]];
  289.         opts.sort(function(a,b){
  290.             return (a[1] === false ?
  291.                         (b[1] === false ? 0 : 1) :
  292.                         (b[1] === false ? -1 : (a[1] > b[1] ? 1 : (a[1] == b[1] ? 0 : -1)))
  293.                     );
  294.         });
  295.         return opts[0][0]();
  296.     }
  297.     tank.turn_towards_unexpected_pings = function(){
  298.         dir = tank.unexpected_ping_direction();
  299.         r_dir = tank.relative_to_rotation(dir);
  300.         if(dir===false) return;
  301.         tank.reset();
  302.         tank.status.directive.active = true;
  303.         tank.status.directive.name = "investigate";
  304.         tank.status.directive.distance = tank.rotation_to_lidar(r_dir)
  305.         tank.status.directive.direction =r_dir;
  306.         return tank.turn_towards(r_dir);
  307.     }
  308. // Response Actions
  309.     tank.unexpected_ping_direction = function(){
  310.         subnotice("Calculating direction of closest unexpected ping.");
  311.        
  312.         alerts = [];
  313.         if(tank.expected_lidar.right && tank.expected_lidar.right > tank.lidar.right){
  314.             alerts.push([3, tank.expected_lidar.right, tank.lidar.right]);
  315.         }
  316.         if(tank.expected_lidar.left && tank.expected_lidar.left > tank.lidar.left){
  317.             alerts.push([1, tank.expected_lidar.left, tank.lidar.left]);
  318.         }
  319.         if(tank.expected_lidar.back && tank.expected_lidar.back > tank.lidar.back){
  320.             alerts.push([2, tank.expected_lidar.back, tank.lidar.back]);
  321.         }
  322.         if(alerts.length == 0){
  323.             subnotice("No unexpected pings.");
  324.             return false;
  325.         }
  326.         alerts = alerts.sort(function(a,b){return a[2] == b[2] ? (a[2] < b[2] ? -1 : 1) : 0});
  327.         subnotice("Unexpected object to the " + avatars[tank.relative_to_rotation(alerts[0][0])] + " (expected: " + alerts[0][1] + ", was: " + alerts[0][2] + ")");
  328.         return alerts[0][0];
  329.     }
  330.     tank.turn_towards_biggest_open_direction = function(){
  331.         subnotice("Turning towards the largest open direction.");
  332.         return tank.turn_towards(tank.biggest_open_direction());
  333.     }
  334. // Values
  335.     tank.expected_lidar_to_front_left = function(){
  336.         if(tank.rotation == 0) return tank.expected_lidar_from_row(tank.y-1, 0, tank.x);
  337.         if(tank.rotation == 1) return tank.expected_lidar_from_col(tank.x-1, tank.y, map.length);
  338.         if(tank.rotation == 2) return tank.expected_lidar_from_row(tank.y+1, map[0].length, tank.x+1);
  339.         if(tank.rotation == 3) return tank.expected_lidar_from_col(tank.x+1, tank.y, 0);
  340.     }
  341.     tank.expected_lidar_to_front_right = function(){
  342.         if(tank.rotation == 0) return tank.expected_lidar_from_row(tank.y-1, map[0].length, tank.x+1);
  343.         if(tank.rotation == 1) return tank.expected_lidar_from_col(tank.x-1, 0, tank.y);
  344.         if(tank.rotation == 2) return tank.expected_lidar_from_row(tank.y+1, 0, tank.x);
  345.         if(tank.rotation == 3) return tank.expected_lidar_from_col(tank.x+1, map.length, tank.y);
  346.     }
  347.     tank.expected_lidar_to_back_left = function(){
  348.         if(tank.rotation == 0) return tank.expected_lidar_from_row(tank.y+1, 0, tank.x);
  349.         if(tank.rotation == 1) return tank.expected_lidar_from_col(tank.x+1, tank.y, map.length);
  350.         if(tank.rotation == 2) return tank.expected_lidar_from_row(tank.y-1, map[0].length, tank.x+1);
  351.         if(tank.rotation == 3) return tank.expected_lidar_from_col(tank.x-1, tank.y, 0);
  352.     }
  353.     tank.expected_lidar_to_back_right = function(){
  354.         if(tank.rotation == 0) return tank.expected_lidar_from_row(tank.y+1, map[0].length, tank.x+1);
  355.         if(tank.rotation == 1) return tank.expected_lidar_from_col(tank.x+1, 0, tank.y);
  356.         if(tank.rotation == 2) return tank.expected_lidar_from_row(tank.y-1, 0, tank.x);
  357.         if(tank.rotation == 3) return tank.expected_lidar_from_col(tank.x-1, map.length, tank.y);
  358.     }
  359.     tank.expected_lidar_from_row = function(row, left, right){
  360.         chunk = map[row].substring(right, left);
  361.         if(left < right) chunk = chunk.split('').reverse().join('');
  362.         unknown_pings = chunk.indexOf(icon.obstacle_unknown)+1;
  363.         walls = chunk.indexOf(icon.obstacle_wall)+1;
  364.         unknowns = chunk.indexOf(icon.unknown)+1;
  365.         if(unknowns > 0){
  366.             if(unknowns < unknown_pings && unknowns < walls) return false;
  367.         }
  368.         if(unknown_pings > 0){
  369.             return unknown_pings < walls ? unknown_pings : (walls > 0 ? walls : unknown_pings);
  370.         }
  371.         return false;
  372.     }
  373.     tank.expected_lidar_from_col = function(col, top, bottom){
  374.         return false;
  375.     }
  376.     tank.icon_at_rotation = function(rotation){
  377.         return [tank.lidar_object.front, tank.lidar_object.left, tank.lidar_object.back, tank.lidar_object.right][tank.rotation_to_relative(rotation)];
  378.     }
  379.     tank.icon_at = function(rotation){
  380.         return [tank.lidar_object.front, tank.lidar_object.left, tank.lidar_object.back, tank.lidar_object.right][rotation];
  381.     }
  382.     tank.biggest_open_direction = function(){
  383.         subsubnotice("Finding biggest open direction");
  384.         if(tank.lidar.right > tank.lidar.left){
  385.             if(tank.lidar.right > tank.lidar.back) return tank.relative_to_rotation(3);
  386.             else if(tank.lidar.back > tank.lidar.front) return tank.relative_to_rotation(2);
  387.         } else {
  388.             if(tank.lidar.left > tank.lidar.back) return tank.relative_to_rotation(1);
  389.             else if(tank.lidar.back > tank.lidar.front) return tank.relative_to_rotation(2);
  390.         }
  391.         return false;
  392.     }
  393.     function direction_of_most_unknowns(){
  394.         return direction_of_most(icon.unknown, false);
  395.     }
  396.     function direction_of_most_unknown_pings(){
  397.         return direction_of_most(icon.obstacle_unknown, true);
  398.     }
  399.     function direction_of_most(icon,include_walls){
  400.         include_walls = (include_walls == undefined || include_walls === false) ? false : include_walls;
  401.         leftmost = include_walls ? 0 : 1;
  402.         topmost = include_walls ? 0 : 1;
  403.         bottommost = include_walls ? map.length : map.length - 1;
  404.         rightmost = include_walls ? map[0].length : map[0].length - 1;
  405.         unknowns_above = unknowns_below = unknowns_left = unknowns_right = 0;
  406.         r = new RegExp(icon, "g");
  407.         for(row_above = topmost; row_above <= tank.y; row_above++){
  408.             if(row_above != tank.y) unknowns_above += (map[row_above].match(r) || []).length;
  409.             unknowns_left += (map[row_above].substring(leftmost,tank.x).match(r) || []).length;
  410.             unknowns_right += (map[row_above].substring(tank.x+1, rightmost).match(r) || []).length;
  411.         }
  412.         for(row_below = tank.y+1; row_below < bottommost; row_below++){
  413.             unknowns_below += (map[row_below].match(r) || []).length;
  414.             unknowns_left += (map[row_below].substring(leftmost,tank.x).match(r) || []).length;
  415.             unknowns_right += (map[row_below].substring(tank.x+1, rightmost).match(r) || []).length;
  416.         }
  417.         subsubnotice("There are " + unknowns_above + " '"+icon+"'s to the north, " + unknowns_below + " south, " + unknowns_left + " east, and " + unknowns_right + " west.");
  418.         if(unknowns_above + unknowns_below + unknowns_left + unknowns_right === 0) return false;
  419.         if(unknowns_above >= unknowns_below){
  420.             if(unknowns_above >= unknowns_left && unknowns_above >= unknowns_right) return 0;
  421.             if(unknowns_above >= unknowns_left) return 3;
  422.             return 1;
  423.         }
  424.         if(unknowns_below >= unknowns_left && unknowns_below >= unknowns_right) return 2;
  425.         if(unknowns_below >= unknowns_left) return 3;
  426.         return unknowns_right >= unknowns_left ? 3 : 1;
  427.     }
  428.     tank.distance_traveled = function(){
  429.     return tank.traveled.o_up + tank.traveled.o_down + tank.traveled.o_right + tank.traveled.o_left;
  430. }
  431.     tank.is_new = function(){
  432.         return tank.distance_traveled() < 5 && tank.status.shots_fired < 1 && tank.status.ticks < 3;
  433.     }
  434. // Modifiers
  435.     tank.update_coords = function(){
  436.         subnotice("Updating coordinate information");
  437.         tank.x = tank.coords[0];
  438.         tank.y = tank.coords[1];
  439.         ends = [[x,y-tank.o_lidar.up],[x-tank.o_lidar.left,y],[x,y+tank.o_lidar.down],[x+tank.o_lidar.right,y]];
  440.         tank.lidar_object.right = icon_for(ends[(tank.rotation+3)%4][0],ends[(tank.rotation+3)%4][1]);
  441.         tank.lidar_object.back = icon_for(ends[(tank.rotation+2)%4][0],ends[(tank.rotation+2)%4][1]);
  442.         tank.lidar_object.left = icon_for(ends[(tank.rotation+1)%4][0],ends[(tank.rotation+1)%4][1]);
  443.         tank.lidar_object.front = icon_for(ends[(tank.rotation)%4][0],ends[(tank.rotation)%4][1]);
  444.     }
  445.     tank.tick_reset = function(){
  446.         tank.status.ticks++;
  447.         tank.status.tick.action_done = false;
  448.     }
  449. // Translations
  450.     tank.rotation_to_relative = function(rotation){ return ((4-tank.rotation) - rotation) % 4; }
  451.     tank.relative_to_rotation = function(relative){ return (relative+tank.rotation) % 4; }
  452.     tank.rotation_to_lidar = function(rotation){
  453.         return [tank.lidar.front, tank.lidar.left, tank.lidar.back, tank.lidar.right][tank.rotation_to_relative(rotation)];
  454.     }
  455.  
  456. /** END FRAMEWORK **/
  457.  
  458. /* DRIVE THE TANK! */
  459. // Directives # FEEL FREE TO REWRITE THESE
  460.     tank.investigate = function(){
  461.         notice("Investigating. Need to walk " + (tank.status.directive.distance - tank.status.directive.steps) + " more step(s).");
  462.         if(tank.status.directive.distance - tank.status.directive.steps < 1){
  463.             subnotice("It was around here! Anything uknown nearby?");
  464.             tank.turn_towards_closest_unknown_ping();
  465.             if(tank.status.tick.action_done){
  466.                 tank.reset();
  467.                 return;
  468.             }
  469.             subnotice("No? Explore I guess?");
  470.             return tank.explore();
  471.         }
  472.         tank.status.directive.steps++;
  473.         tank.forward();
  474.     }
  475.     tank.explore_half = function(){
  476.         subnotice("Exploring up to half way?");
  477.         if(tank.lidar.front < tank.lidar.back){
  478.             subnotice("We're over halfway");
  479.             open_direction = tank.biggest_open_direction();
  480.             if(tank.icon_at(open_direction) != icon.obstacle_wall){
  481.                 subsubnotice("Lets check it out");
  482.                 tank.turn_towards(open_direction);
  483.                 if(tank.status.tick.action_done){
  484.                     tank.status.directive.name = "explore";
  485.                     tank.status.directive.direction = tank.rotation;
  486.                     return;
  487.                 }
  488.             } else {
  489.                 subsubnotice("Biggest open area is towards a known wall. Is anything unkown?");
  490.                 tank.turn_towards_closest_unknown_ping();
  491.                 if(!tank.status.tick.action_done){
  492.                     if(tank.lidar.front > 0){
  493.                         subsubnotice("Wow. Okay. Go further?");
  494.                         return tank.explore();
  495.                     }
  496.                     subsubnotice("OMG. Fuck it.");
  497.                     tank.turn_towards_biggest_open_direction();
  498.                     if(tank.status.tick.action_done) return;
  499.                 }
  500.             }
  501.         }
  502.         subsubnotice("Keep going");
  503.         return tank.explore();
  504.     }
  505.     tank.explore = function(){
  506.         if(!tank.status.directive.active){
  507.             notice("Start exploring");
  508.             tank.status.directive.active = true;
  509.             tank.status.directive.name = "explore";
  510.             subnotice("Drive towards the most unknown stuff.");
  511.             stuff_dir = direction_of_most_unknowns();
  512.             if(stuff_dir !== false){
  513.                 tank.status.directive.direction = stuff_dir;
  514.                 tank.turn_towards(tank.status.directive.direction);
  515.                 if(tank.status.tick.action_done) return;
  516.                 subnotice("That would be forward");
  517.                 tank.forward();
  518.                 if(tank.status.tick.action_done) return;
  519.                 subnotice("We can't go forward.");
  520.                 tank.status.lost = true;
  521.             } else {
  522.                 subsubnotice("There is no unknown stuff");
  523.                 tank.status.lost = true;
  524.             }
  525.         } else notice("Continue exploring");
  526.        
  527.         if(tank.status.lost){
  528.             subnotice("We are lost!?");
  529.             tank.turn_towards_biggest_open_direction();
  530.             if(tank.status.tick.action_done) return;
  531.             subnotice("We're already facing that way?");
  532.             tank.forward();
  533.             if(tank.status.tick.action_done){
  534.                 tank.status.lost = false;
  535.                 return;
  536.             }
  537.         } else {
  538.             subnotice("Drive forward");
  539.             tank.forward();
  540.             if(tank.status.tick.action_done) return;
  541.         }
  542.        
  543.         subnotice("We can't go forward any more?");
  544.         if(tank.is_new()){
  545.             subnotice("We're young, go big");
  546.             tank.turn_towards_biggest_open_direction();
  547.             if(tank.status.tick.action_done) return;
  548.         } else {
  549.             most_unknowns = direction_of_most_unknowns();
  550.             if(most_unknowns === false){
  551.                 subnotice("No unknowns? What about unknown pings?");
  552.                 most_unknowns = direction_of_most_unknown_pings();
  553.                 tank.status.directive.name = "explore_half";
  554.                 tank.status.directive.direction = most_unknowns;
  555.                 tank.turn_towards(tank.status.directive.direction);
  556.                 if(tank.status.tick.action_done) return;
  557.             }
  558.             if(tank.rotation == most_unknowns){
  559.                 subsubnotice("Oh. That way is forward. And we can't go forward.");
  560.                 tank.status.directive.name = "explore_half";
  561.                 tank.status.directive.direction = most_unknowns;
  562.                 tank.turn_towards_biggest_open_direction();
  563.                 if(tank.status.tick.action_done) return;
  564.             } else if(tank.icon_at_rotation(most_unknowns) != icon.obstacle_wall){
  565.                 subsubnotice("This looks like a good bet, lets go (rotation: " + most_unknowns + ").");
  566.                 tank.status.directive.direction = most_unknowns;
  567.                 tank.turn_towards(tank.status.directive.direction);
  568.                 if(tank.status.tick.action_done) return;
  569.             } else {
  570.                 subsubnotice("But we already know there's a wall that way (" + tank.icon_at_rotation(most_unknowns) + ").");
  571.                 tank.turn_towards_closest_unknown_ping();
  572.                 if(tank.status.tick.action_done) return;
  573.                 subsubnotice("There's a wall every way...");
  574.                 tank.turn_towards_biggest_open_direction();
  575.                 if(tank.status.tick.action_done) return;
  576.             }
  577.         }
  578.         if(tank.status.tick.action_done) return;
  579.        
  580.         warn("Oh no!");
  581.     }
  582.     tank.next_directive_action = function(action){
  583.         if(tank.directives.indexOf(action)<0){ warn("Warning! Cannot do '"+action+"'!"); return; }
  584.         return tank[action]();
  585.     }
  586.     tank.next_combat_action = function(){
  587.         if(!tank.status.combat.active) return false;
  588.         notice("Battle planner");
  589.        
  590.         if(api.identifyTarget()){
  591.             subnotice("Target directly ahead.");
  592.             if(tank.status.shots_fired_in_a_row > 1 && tank.lidar.front <= tank.status.combat.last_shot_range + 1){
  593.                 subsubnotice("There are a lot of enemies. Try to avoid being flanked.");
  594.                 tank.backward();
  595.                 if(tank.status.tick.action_done) return;
  596.             }
  597.             if(tank.lidar.front <= tank.max_range){
  598.                 subsubnotice("Clear to Fire!")
  599.                 tank.shoot();
  600.                 if(tank.status.tick.action_done) return;
  601.             } else {
  602.                 subnotice("Too far to shoot. Range: " + tank.lidar.front + ", max: " + tank.max_range + ".");
  603.                 if(tank.status.combat.chase_target_seen_count > 0){
  604.                     subsubnotice("But the target hasn't moved. Go ahead and take the shot");
  605.                     tank.shoot();
  606.                     if(tank.status.tick.action_done){
  607.                         subsubnotice("Target gone, probably. End chase.");
  608.                         tank.status.combat.chasing = false;
  609.                         tank.status.combat.chase_remaining = 0;
  610.                         return;
  611.                     }
  612.                 } else {
  613.                     subsubnotice("Get closer to the target. (Chase mode active)")
  614.                     tank.status.combat.chasing = true;
  615.                     tank.status.combat.chase_remaining = tank.lidar.front;
  616.                     tank.status.combat.chase_target_seen_count++;
  617.                 }
  618.             }
  619.         } else {
  620.             tank.status.combat.time_since_last_shot++;
  621.             subnotice("No target ahead. Time since last shot: " + tank.status.combat.time_since_last_shot);
  622.         }
  623.        
  624.        
  625.         if(tank.status.combat.chasing && tank.status.combat.chase_remaining > 0){
  626.             subnotice("We are in persuit. Trying to travel " + tank.status.combat.chase_remaining + " more blocks");
  627.             subnotice("Anything unexpected around?");
  628.             unexpected_ping_direction = tank.unexpected_ping_direction();
  629.             if(unexpected_ping_direction !== false){
  630.                 subsubnotice("Unexpected ping!");
  631.                 if(tank.status.combat.chase_remaining > tank.rotation_to_lidar(unexpected_ping_direction)){
  632.                     subsubnotice("And it's closer than our chase target!");
  633.                     tank.turn_towards(unexpected_ping_direction);
  634.                     if(tank.status.tick.action_done) return;
  635.                 }
  636.             }
  637.             subsubnotice("Nope.");
  638.             tank.status.combat.chase_remaining--;
  639.             tank.forward();
  640.             if(tank.status.tick.action_done) return;
  641.         }else if(tank.status.combat.chasing && tank.status.combat.chase_remaining == 0){
  642.             subnotice("This is where we expect to see thing thing we chased. Anything unexpected?");
  643.             tank.turn_towards_unexpected_pings();
  644.             if(tank.status.tick.action_done) return;
  645.             subnotice("No? Anything Unknown?");
  646.             tank.turn_towards_closest_unknown_ping();
  647.             if(tank.status.tick.action_done) return;
  648.         }
  649.        
  650.         if(tank.status.combat.time_since_last_shot < 3){
  651.             subnotice("Cannon is still warm. Can we possibly shoot any of our pings?");
  652.             tank.turn_towards_unexpected_pings();
  653.             if(tank.status.tick.action_done) return;
  654.             tank.turn_towards_closest_unknown_ping();
  655.             if(tank.status.tick.action_done) return;
  656.         }
  657.         if(tank.status.combat.time_since_last_shot == 3 && tank.status.turning_around){
  658.             subnotice("Cannon is almost cooled. Finish this turn.");
  659.             return;
  660.         }
  661.        
  662.         subnotice("No more enemies detected");
  663.         tank.reset();
  664.         subnotice("Tank reset. Combat mode disabled");
  665.     }
  666.  
  667. // Run the thing! # FEEL FREE TO REWRITE THIS
  668.     exports.update = function() {
  669.    
  670.     // Here we go...
  671.     if(verbose) console.log("┌─ tick " + tank.status.ticks + "\t───────────────────────────────────────────────────────────────┐");
  672.     tank.tick_reset();
  673.    
  674.     // What do things look like since our last action
  675.     tank.sense();
  676.     if(verbose) tank_stats();
  677.     if(verbose) map_stats();
  678.  
  679.     // Respond to possible threats
  680.     if(tank.status.combat.active){
  681.         notice("Combat mode is active.");
  682.         tank.next_combat_action();
  683.         if(tank.status.tick.action_done) return;
  684.     }
  685.    
  686.     notice("Checking scan data for unexpected movement");
  687.     tank.turn_towards_unexpected_pings();
  688.     if(tank.status.tick.action_done) return;
  689.    
  690.     if(tank.status.turning_around){
  691.         notice("We were turning around.");
  692.         return tank.finish_turning_around();
  693.     }
  694.    
  695.     if(tank.status.directive.active){
  696.         notice("Current directive: " + tank.status.directive.name);
  697.         tank.next_directive_action(tank.status.directive.name);
  698.         if(tank.status.tick.action_done) return;
  699.     }
  700.    
  701.     if(tank.is_new()){
  702.         notice("I'm pretty new to this level.");
  703.         tank.reset();
  704.         tank.explore();
  705.         if(tank.status.tick.action_done) return;
  706.     }
  707.    
  708.     tank.explore();
  709. };
Advertisement
Add Comment
Please, Sign In to add comment