# Fastest gun of the west, king of the hill challenge

This is a King of the Hill challenge in a round robin. It's a battle to find the best gunman of the west!

To be able to compete in this contest you need to make two functions. The first one sets the attributes of your gunman and the second is the main logic function for the gunman.

# Attribute Function

function () {

var bot = {
name: "testBot",
numbOfBullets: 7,
shotsPerTurn: 1,
moveSpeed: 2
}
return bot
}


The attribute function includes 5 variables that you will need to set according to some rules (with the exception of name that can be any string). You must spend a total of exactly 15 points on your gunman -- gunmen that do not spend all 15 points are not eligible. Here is how the attributes work:

• numbOfBullets - defines how many bullets your gun holds.

The initial and minimum value of numbOfBullets is 1. Each additional bullet costs 1 point with the maximum being 16 bullets with 15 points spent.

• reloadSpeed - defines how many turns your gunman needs to reload his gun after he ran out of bullets.

The base and maximum value is 4 with the minimum being 1. Decreasing this attribute by 1 costs 2 points.

• shotsPerTurn - defines how many times your gunman can shoot in one turn.

The base and minimum value is 1. Each increase by 1 costs 3 points so you can have a maximum of 6 shots per round with 15 points spent. Raising this attribute above numbOfBullets is counter productive since you can't shoot more bullets then your gun can hold.

• moveSpeed - defines how many spaces your gunman can run in one turn.

The base and minimum value is 1. Each increase by 1 costs 3 points with a maximum of 6 speed with 15 points spent. The gunman can run either left or right every turn up to a maximum of his move speed. He can also stand still which gives him a bonus (more on this later).

The example function above has 6 points spend on bullets, 6 points spend on reload speed and 3 points spend on movement.

# Main function

function main(bulletsLeft, yourShots, enemyShots, yourMovement, enemyMovement) {

var shots = [];
shots.push(Math.floor((Math.random() * 24) + 1));
var move = yourMovement[yourMovement.length - 1] + 2
var play = [];
play.shots = shots;
play.move = move;
return play;
}


Parameters:

• bulletsLeft, number of bullets left in your gun
• yourShots, this is a array of arrays of all the past positions your gunman has fired at.

Example for a gunman who can shoot 1 bullet per round:

[[12],[4],[22],...]


Example for a gunman who can shoot 3 bullets per round:

[[12,13,14],[11,15,16],[9,14],...]

• enemyShots - same as above but for your enemy

• yourMovement - an array of all your past movement positions
• enemyMovement, same as above but for your enemy

What you need to return:

You are required to return a variable which has 3 attributes:

• shots - an array of numbers which determine at which space/s your gunman will shoot
• move - a single number that determines to what space your gunman will try to move to
• reload - a true/false value with which you can make your gunman reload

# The Duel

The contest follows a round robin 1 versus 1 system. Each gunman has 50 rounds against every other gunman. A round lasts until someone is hit by a bullet or until 66 turns have passed (a turn is when both players have shot).

The gunman can earn 2 points by killing their opponent, 1 point if they both die in the same turn or 0 points if they reach the 66 turns limit. The shooting field is 24 spaces width (1-24 inclusive). To hit a player and win a round you need to shoot at the same space as he is currently standing on.

Here is a step by step guide on how a duel works. This also covers all invalid commands and special rules:

• At the start of each duel both players are put on space 12 and their revolvers are fully loaded
• The main function is called and the gunman make their first move command and choose where they want to shoot
• First the gunmen move to their new location. If any invalid input is made at the move command (positions lower then 1 or higher then 24 or they moved more spaces then they are allowed too) they stay at the same position.
• Next reloading is checked, if you ran out of bullets the previous turn or you called reloading yourself your gunman goes into the reload cycle. He is reloading for as many turns as you set your reloadSpeed value. If you decided to stand still (returning the same space integer as you where standing on before or just returning a invalid value) you reload counter goes down for 2 turns instead of one.
• Now comes checking your shooting values, every turn you can enter as many shooting location as you like they will always be cut off to the actual valid amount which is determined by: The number of shots per turn and the number of bullets in your revolver (whichever is lower). Your shotsPerTurn value is increased by 1 if you decide to stand still this turn, so you can make a extra shot if you decide to stand still. If you are in the reload cycle you have 0 shots.
• Now comes the actual shooting, there are 2 ways this can go down. If both gunman have the same movespeed stat then they both shoot at the same time and can both kill each other at the same time. In the case that they have different movespeed stats the bot with the higher movespeed stat starts shooting first and if he kills his opponent he wins this round. If the gunman can shoot one or more bullets in one round then it follows the same rules as above except in more cycles as a example: Lets say that bot1 has 3 bullets and is faster and bot 2 has 2 bullets then it would go like this:

Bot1 shoots, Bot2 shoots cycle 1
Bot1 shoots, Bot2 shoots cycle 2
Bot1 shoots              cycle 3


This would look the same if they had the same movespeed only that if now Bot1 hit Bot2 in the same cycle Bot2 could also hit Bot1 and it would be a tie.

# RULES

First I am copying some rules from Calvin's Hobbies' entry that also apply here.

When declaring a new JavaScript variable, you must use the var keyword. This is because a variable declared without var becomes global rather than local, so it would be easy to accidentally (or intentionally) mess with the controller or communicate freely with other players. It has to be clear that you aren't trying to cheat.

When declaring functions it is best to use the var keyword as well, i.e. use var f = function(...) {...} instead of function f(...) {...}. I'm not entirely sure why, but sometimes it appears to make a difference.

In your code you may not...

• attempt to access or modify the controller or other player's code.
• attempt to modify anything built into JavaScript.
• make web queries.
• do otherwise malicious things.

• The users can create as many gunman as they want and change their functions for any period of time
• I will remove any entry from the game that either takes a excessive amount of time or tries to cheat in any way that I see fit
• The names of the attributes that your function need to return has to be the same as in the examples with the same structure!

Your answer should be in this format, the first function being the attribute function and the second being the logic function. Notice that I used an exclamation mark because if you just make new lines between code blocks the parser wont see two different code blocks so you have to use any symbol(just use a exclamation mark) to seperate them:

var bot = {
name: "testBot",
numbOfBullets: 7,
shotsPerTurn: 1,
moveSpeed: 2
}
return bot

var shots = []
var testBot_moveUp = true
if(Math.random() * 2 > 1)
testBot_moveUp = false
shots.push(Math.floor((Math.random() * 24) + 1))
var move = 0
if (testBot_moveUp)
move = yourMovement[yourMovement.length - 1] + 2
else
move = yourMovement[yourMovement.length - 1] - 2
move = 12
var play = []
play.shots = shots
play.move = move
return play


And here is the controller: GAME CONTROLLER. Just open the link and wait for the bots to load, then select which one you want in the fight (probably all) and press the start button.

I also put in a testbot as my answer which will compete, it also serves as a example on how the structure of the answer should look like. As a note, if you make a small mistake and edit your answer stackexchanges algorithm might not pick it up right away and the site that the controller uses which is generated by stackexchange isnt updated(but will later or if you make bigger changes which i suggest doing, just add some text at the end). Here is the site: codelink

• I don't seem to be able to get the two bots fighting each other at the moment- if I have them both selected, pressing start doesn't seem to do anything and I'm not sure whether that's my bot being wrong or the controller taking a long time Jun 14, 2015 at 13:54
• Yea as i explained at the end of my question when you edited your answer it didnt edit it yet in the stackexchange code generator because it didnt notice that there was a change, if you add some text at the end of your answer it should work Jun 14, 2015 at 14:07
• I think (fingers crossed) I've corrected those errors- it's just hard to find the errors if the controller doesn't tell me that I didn't provide the correct output and just silently does nothing Jun 14, 2015 at 14:23
• You can use <!----> to separate codeblocks "invisibly" (without the !). Jun 14, 2015 at 17:03
• Found the error. Change "play1 = maskedEval(players[a].code, params)" to "play1 = maskedEval(playingPlayers[a].code, params)" - same for play2 Jun 16, 2015 at 8:14

# Pandarus

var bot = {
name:"Pandarus",
numbOfBullets: 2,
shotsPerTurn: 1,
moveSpeed: 5
}
return bot

var myPos;
if(yourMovement.length > 0)
{
myPos = yourMovement[yourMovement.length - 1];
}
else
{
myPos = 12;

}
var EnemyPos;
if(enemyMovement.length>0) {
EnemyPos = enemyMovement[enemyMovement.length - 1];
}
else
{
EnemyPos = 12;
}

var play = {
shots: [
],
move: 12
};
if (bulletsLeft < 1)
{
play.shots = [
];
}
else
{
//FIRE!!!
var enemyMoveSum = 0;
for (var i = 0; i < enemyMovement.length; i++)
{
var MoveSinceLast;
if (i == 0)
{
MoveSinceLast = enemyMovement[i] - 12;
}
else
{
MoveSinceLast =enemyMovement[i] - enemyMovement[i-1];
}

enemyMoveSum += Math.abs(MoveSinceLast);
}

var enemyAvgMove;
if (enemyMovement.length > 0)
{
enemyAvgMove = Math.round(enemyMoveSum / enemyMovement.length);
}
else
{
enemyAvgMove = 0;
}

var LeftShot = EnemyPos - enemyAvgMove;
var RightShot = EnemyPos + enemyAvgMove;

if (RightShot > 24 ||( (LeftShot>0) && (Math.random()*2 < 1)))
{
play.shots.push(
LeftShot
);
}
else
{
play.shots.push(
RightShot
);
}
}

var MyMove = myPos;
do
{
var move = Math.floor(Math.random() * 10) - 5;
if(move == 0)
{
move = 5;
}
MyMove = myPos + move;
}
while (MyMove<1 || MyMove > 23)

play.move = MyMove;

return play;


Pandarus relies on his speed to get out the way of the bullets, and uses the enemies previous movements to guess where they are going to go.

• Have to apoligize, there was a bug in the scoring now everything works correctly. It was very weird to me that my bot was winning lol Jun 14, 2015 at 17:39
• Oh and your submission had another weird thing, the numbers for your move command where decimals so i added rounding into the controller Jun 14, 2015 at 17:47
• I really don't know why it was outputting decimals :-) I'll try and improve it tomorrow Jun 14, 2015 at 19:08
• i removed the console.log since it was breaking the controller Jun 14, 2015 at 20:42
• Yeah sorry, anyway I've (finally) got it working (and beating your test bot) now :) Jun 15, 2015 at 12:15

## A Simple Man

Not perfect at anything, but quite good at everything through the power of less is more.

return {
name: "A Simple Man",
numbOfBullets: 7,   /* 9 points */
shotsPerTurn: 2,    /* 3 points */
reloadSpeed: 4,     /* 0 points */
moveSpeed: 3        /* 3 points */
}

var lastPos = yourMovement[ yourMovement.length - 1 ],
lastEnemyPos = enemyMovement[ enemyMovement.length - 1 ],
lastEnemyMove = enemyMovement.length > 1 ?
( function () {
var i = 0,
currentMove,
minMove = Infinity;
while ( i < enemyMovement.length ) {
currentMove = Math.abs( enemyMovement[ enemyMovement.length - 1 ] - enemyMovement[ enemyMovement.length - 2 ] );
if ( currentMove < minMove ) { minMove = currentMove; }
return minMove;
}
} )()
: 1,

return {
shots: [ yourMovement.length === 1 ? 12 : lastEnemyPos + lastEnemyMove, lastEnemyPos - lastEnemyMove ],
move: needsToReload ? lastPos : lastPos + Math.floor( Math.random() * 3 + 1 ) * ( ( Math.random() > 0.5 ) ? -1 : 1 ),
};

• Thank @ProgramFOX for adding the syntax highlighting, but this broke the programm. Jun 28, 2015 at 11:23
• That's weird. Adding syntax highlighting is only a HTML comment and shouldn't break the program. Jun 28, 2015 at 11:23
• Don’t know, but the programm didn’t load my code anymore, now its fine again. Jun 28, 2015 at 11:24
• Ahh, I see, probably the parser didn't understand the format with the HTML comment, so it did break the program indeed. My bad! Jun 28, 2015 at 11:44
var bot = {
name: "testBot",
numbOfBullets: 7,
shotsPerTurn: 1,
moveSpeed: 2
}
return bot

var shots = []
var testBot_moveUp = true
if(Math.random() * 3 > 1)
testBot_moveUp = false
shots.push(Math.floor((Math.random() * 24) + 1))
var move = 0
if (testBot_moveUp)
move = yourMovement[yourMovement.length - 1] + 2
else
move = yourMovement[yourMovement.length - 1] - 2
var play = []
play.shots = shots
play.move = move
return play


Test bot, this added as a control test. If anybody loses to this you should be ashamed :). Fixed bot behaviour, copy pasted the wrong test bot(it always stayed on field 12)

var bot = {
name: "Sniper",
numbOfBullets: 4,   /* 3 points */
reloadSpeed: 4,     /* 0 points */
shotsPerTurn: 1,    /* 0 points */
moveSpeed: 5        /* 12 points */
};
return bot;

var play = {};
var my_speed = 5;

var gatherStatistics = function(moves) {
var enemyMoves = [];

for (var m = 1; m < moves.length; ++m) {
var diff = moves[m]-moves[m-1];

var found = false;
for (var i = 0; i < enemyMoves.length; ++i) {
if (enemyMoves[i][0] === diff) {
++enemyMoves[i][1];
found = true;
break;
}
}
if (!found) enemyMoves.push([diff,1]);
}

return enemyMoves;
};
var calcOptimalTarget = function(moves, histogram) {
var enemy_pos = moves[moves.length-1];
var optimalDiffs = [];
var optimalScore = 0;

for (var i = 0; i < histogram.length; ++i) {
var diff = histogram[i][0];
var score = histogram[i][1];

if (score > optimalScore) {
optimalScore = score;
optimalDiffs = [diff];
} else if (score === optimalScore) {
optimalDiffs.push(diff);
}
}

var chosenDiff = optimalDiffs[Math.floor(Math.random() * optimalDiffs.length)];
return enemy_pos + chosenDiff;
};

/* Run around like a mad man */
var my_pos = yourMovement[yourMovement.length-1];
var rand_sign = 2*Math.floor(2*Math.random())-1;

/* Never run into walls */
if (my_pos <= my_speed+1) {
rand_sign = 1;
} else if (my_pos >= 24 - my_speed - 1) {
rand_sign = -1;
}

if (yourMovement.length === 1) { /* Leap out of the way on first move */
play.move = yourMovement[yourMovement.length-1] + rand_sign*my_speed;
} else {
play.move = yourMovement[yourMovement.length-1] + rand_sign*((my_speed-1)*Math.floor(2*Math.random()) + 1);
}

/* Shoot all bullets by the end of the game */
var random_shot = (Math.random() > 0.15) ? true : false;

if (enemyMovement[enemyMovement.length-1] === enemyMovement[enemyMovement.length-2]) {
/* Enemy is standing still; now is our time to STRIKE! */
play.shots = [ enemyMovement[enemyMovement.length-1] ];
} else if (enemyMovement.length >= 2 && random_shot) {
/* We take a random shot; best guess by enemies movement */
var histogram = gatherStatistics(enemyMovement);
play.shots = [ calcOptimalTarget(enemyMovement, histogram) ];
} else {
/* No default shooting */
play.shots = [];
}

return play;

• so if the enemy never stands still the sniper never shoots? :D Jun 16, 2015 at 10:07

## The Weaver

More concerned with staying alive than killing, he weaves back and forth, increasing his distance every time. Picks a random spot within the enemies proven range to shoot at.

var bot = {
name: "TheWeaver",
numbOfBullets: 4, // 3 points
shotsPerTurn: 1, // 0 points
moveSpeed: 5 // 12 points
}
return bot;


var play = {};
var moveSpeed = 2;

//Guess the enemies speed
var enSpeed = 1;
var prev = 12;
for(var move in enemyMovement){
if(Math.abs(move - prev) > enSpeed){
enSpeed = Math.abs(move - prev);
}
prev = move;
}

//Randomly shoot in his range
var enemyPos = 12;
if(enemyMovement.length > 0){
enemyPos = enemyMovement[enemyMovement.length - 1];
}
var shots = [];

//Shoot somewhere in his range
var distance = Math.random()*enSpeed;
var direction = 1;
if(Math.random() < 0.5){ direction = -1;}
if(enemyPos + enSpeed > 24){ direction = -1;}
if(enemyPos - enSpeed <= 0){ direction = 1;}
shots.push(enemyPos + distance*direction);

var move = 12;

if(yourMovement.length == 0){
move = 12 + moveSpeed - 1;
}
//Quick switch
else if(yourMovement.length == 1){
move = 11
}
//Wave baby, weave
else{
var lastPos = yourMovement[yourMovement.length - 1];
var lastMove = yourMovement[yourMovement.length - 1] - yourMovement[yourMovement.length - 2];
var distance = Math.abs(lastMove + 1);
if(distance > moveSpeed) { distance = 0;}
var direction = lastMove/Math.abs(lastMove)*(-1);
move = lastPos + distance*direction;
}

//Correct move
if(move > 24){
move = 24;
}
if(move < 1){
move = 1;
}

play.move = move;
play.shots = shots;

return play;

• move = 12 + moveSpeed - 1; is equivalent to move = 11 + moveSpeed;, no? Otherwise this looks like a good bot ;) Jul 21, 2015 at 17:25
• @ConfusedMr_C Haha yes, its the same, I guess I just chose the first one for readability, makes it more clear that it moves one less than the maximum moveSpeed from the start point. Also makes it easier to replace all 12 with 15 if the size of the map changes or anything
– Cain
Jul 21, 2015 at 17:52
• Oh, okay. We're all programmers here so I was surprised that nobody else had mentioned it :P Jul 22, 2015 at 8:40

# Alexander Hamilton

If he doesn't win in the first round, will probably die

var bot = {
name: "Hamilton",
numbOfBullets: 7, // 6 pts
shotsPerTurn: 4, // 9 pts
moveSpeed: 1 // 0pts
}
return bot


!

var shots = []
var move = yourMovement[yourMovement.length - 1] + 1
var play = []
play.shots = [12,11,10,13,14,9,15,8,16,7,17,6,18]
play.move = move
return play


# Aaron Burr

var bot = {
name: "Burr",
numbOfBullets: 7, // 6 pts
shotsPerTurn: 3, // 6 pts
moveSpeed: 2 // 3pts
}
return bot


!

var shots = []
var move = yourMovement[yourMovement.length - 1]
// Dodging dance
switch (yourMovement.length % 4) {
case 1:
move += 2
break;
case 2:
move -= 1
break;
case 3:
move -= 2
break;
case 0:
move += 1
break;
}
var play = []
var elast = enemyMovement[enemyMovement.length - 1]
play.shots = [elast + 1, elast -1, elast]
play.move = move
return play

var bot = {
name: "Winger",
numbOfBullets: 7, // 6 points
shotsPerTurn: 3, // 6 points
moveSpeed: 2 // 3 points
}
return bot;

var play = {};
var moveSpeed = 2;

//Guess the enemies speed
var enSpeed = 5; // Assume they are fast on the first turn
var prev = 12;
for(var move in enemyMovement){
if(Math.abs(move - prev) > enSpeed){
enSpeed = Math.abs(move - prev);
}
prev = move;
}

var move = 12;
if(Math.random() < 0.5){ moveSpeed = 1; }
//Move against the enemies shots
if(yourMovement.length == 0 || enemyShots.length == 0){
move = 12 + moveSpeed;
}
else if(enemyShots.length == 1){
if(enemyShots[0] <= 12){
move = yourMovement[yourMovement.length - 1] - moveSpeed;
}
else{
move = yourMovement[yourMovement.length - 1] + moveSpeed;
}
}
else{
var dir = enemyShots[enemyShots.length - 1][0] - yourMovement[yourMovement.length - 1];
if(dir > 0){
move = yourMovement[yourMovement.length - 1] + moveSpeed;
}
else{
move = yourMovement[yourMovement.length - 1] - moveSpeed;
}
}

if(bulletsLeft < 3){
}

var enemyPos = 12;
if(enemyMovement.length > 0){
enemyPos = enemyMovement[enemyMovement.length - 1];
}
var shots = [];
//Shoot a spread around the opponent
shots.push(enemyPos);
if(enemyPos + enSpeed <= 24){ shots.push(enemyPos + enSpeed);}
if(enemyPos - enSpeed > 0){ shots.push(enemyPos - enSpeed);}

}

//Correct move
if(move > 24){
move = 24;
}
if(move < 1){
move = 1;
}
if(reload && (yourMovement[yourMovement.length - 1] - yourMovement[yourMovement.length - 2]) != 0){
move = yourMovement[yourMovement.length - 1];
}

play.move = move;
play.shots = shots;

return play;


Winger fires a spread that bounds the enemies range. He also kind of runs towards the enemies shots.

Just gonna leave this here to push the reset.

# SMG

His gun is his cover. Unfortunately, it seems to block his view. He is also good at taking advantage of standing still to reload faster and get extra shots.

var bot = {
name: "SMG",
numbOfBullets: 12, //11pt
shotsPerTurn: 1,   //0pt
moveSpeed: 1       //0pt
}
return bot

var shots = [];
shots.push(Math.floor((Math.random() * 24) + 1));
shots.push(Math.floor((Math.random() * 24) + 1));
var play = [];
if (bulletsLeft < 1) {
play.shots = [];
}
play.shots = shots;
play.move = Math.floor((Math.random() * 24) + 1);
return play;

var bot = {
numbOfBullets: 7,
shotsPerTurn: 1,
moveSpeed: 4
}
return bot

var getSpeed=function(Moves){
var m = 0;
for(var i=1;i<Moves.length;i++){
var d = Math.abs(Moves[i]-Moves[i-1]);
m = m>d?m:d;
}
return m;
}
var validMove=function(moves,speed){
speed = speed||getSpeed(moves);
var m;
do{
m=moves[moves.length-1]+Math.floor(Math.random()*(speed*2+1)-speed);
}while(m>25 && m<0);
return m;
}
var shots = [];
shots.push(validMove(enemyMovement));
var move = validMove(yourMovement,4);
return {
shots:shots,
move:move,
};

• Since this is never reloading, it would be better if you didn't waste any points on reload speed and instead buy more bullets. Jun 16, 2015 at 12:45
• @QuadrExAtt: Reload is automatic when you run out of shots. Jun 16, 2015 at 21:27
var bot = {
name: "Gun and run",
numbOfBullets: 4,   /* 3 points */
reloadSpeed: 4,     /* 0 points */
shotsPerTurn: 3,    /* 6 points */
moveSpeed: 3        /* 6 points */
};
return bot;

var play = {};
if (yourShots.length === 1) { /* Opening move */
if (Math.random() < 0.5) {
play.shots = [13,14,15,16];
} else {
play.shots = [8,9,10,11];
}
play.move = 12;
} else { /* YOLO */
play.shots = [];
switch (yourMovement[yourMovement.length - 1]) {
case 12:
play.move = 15;
break;
case 15:
play.move = 18;
break;
case 18:
play.move = 15;
break;
}
}
return play;

• Hey its "yourShots" not my myShots, now that i think about it "myShots" would have been better lol, oh and move isnt a array its just a single number Jun 16, 2015 at 7:05

# Diephobus

var bot = {
name: 'Deiphobus',
numbOfBullets: 5,
shotsPerTurn: 4,
moveSpeed: 1
};
return bot

var getSorted = function(list)
{
var modifiedList = [0,0,0,0,0,0,0,0,0,0,0,0,0];
modifiedList[0] = list[6];
modifiedList[1] = list[7];
modifiedList[2] = list[5];
modifiedList[3] = list[8];
modifiedList[4] = list[4];
modifiedList[5] = list[9];
modifiedList[6] = list[3];
modifiedList[7] = list[10];
modifiedList[8] = list[2];
modifiedList[9] = list[11];
modifiedList[10] = list[1];
modifiedList[11] = list[12];
modifiedList[12] = list[0];

var messedUpOrder = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1];
for(var order = 0; order < 13; order++) {
var currBest = -2;

for (var i = 0; i < 13; i++) {
if ((messedUpOrder.indexOf(i) < 0) && (modifiedList[i] > modifiedList[currBest] || currBest<0)) {

currBest = i;
}
}

messedUpOrder[order] = currBest;
}

var toRet = [0,0,0,0,0,0,0,0,0,0,0,0,0];
toRet[6] = messedUpOrder[0];
toRet[7] = messedUpOrder[1];
toRet[5] = messedUpOrder[2];
toRet[8] = messedUpOrder[3];
toRet[4] = messedUpOrder[4];
toRet[9] = messedUpOrder[5];
toRet[3] = messedUpOrder[6];
toRet[10] = messedUpOrder[7];
toRet[2] = messedUpOrder[8];
toRet[11] = messedUpOrder[9];
toRet[1] = messedUpOrder[10];
toRet[12] = messedUpOrder[11];
toRet[0] = messedUpOrder[12];

};
var myPos;
if(yourMovement.length>0) {
myPos  = yourMovement[yourMovement.length - 1];
}
else{
myPos = 12;
}
var EnemyPos;
var play = {
shots: [
],
move: 12
};
if(enemyMovement.length>0) {
EnemyPos = enemyMovement[enemyMovement.length - 1];
}
else
{
EnemyPos = 12;
}
if(bulletsLeft<4)
{
}
else
{
var enemyChanges = [0,0,0,0,0,0,0,0,0,0,0,0,0];
for(var i = 0; i<enemyMovement.length; i++)
{
var enemyChange;
if(i == 0)
{
enemyChange = enemyMovement[i] - 12;
}
else
{
enemyChange = enemyMovement[i] - enemyMovement[i-1];
}

enemyChanges[enemyChange+6] = enemyChanges[enemyChange+6]+1;
}

var orderedEnemyChanges = getSorted(enemyChanges);
var CurrentShot = 0;
play.shots = [12,12,12,12];
for(var i = 0; i<orderedEnemyChanges.length && CurrentShot<4; i++)
{
var pos = orderedEnemyChanges[i] + EnemyPos - 6;
if(pos<24 && pos>0)
{
play.shots[CurrentShot] = pos;
CurrentShot ++;
}
}
}
if(myPos == 1)
{
play.move = 2;
}
else if (myPos == 23)
{
play.move = 22;
}
else
{
play.move = myPos + (Math.floor((Math.random() * 3)) %3) - 1;
}
return play;


Diephobus beleives in mercilessly firing bullets everywhere he thinks his enemy might be, but he's a bit slow.

# ASCIIGunInTheWest

Fires 2 shots a turn, and guesses where the enemy can go based on how fast he moves. Forgive me if there's any errors, I haven't coded much in JavaScript.

var bot = {
name: "ASCIIGunInTheWest",
numbOfBullets: 4,
shotsPerTurn: 2,
moveSpeed: 2
}
return bot


!

function main(bulletsLeft, yourShots, enemyShots, yourMovement, enemyMovement) {
var randnum = function (min, max) { return Math.floor( Math.random() * (max - min + 1) ) + min }
var getDiff = function (num1, num2) { return Math.abs( (num1 > num2) ? num1-num2 : num2-num1 ) }
var shots = []
var enemyMaxMovement = 0
for (index = 0 index < enemyMovement.length ++index) {
var moveDiff = getDiff(enemyMovement[index], enemyMovement[index - 1])
if (index != 0 && moveDiff > enemyMaxMovement) {
enemyMaxMovement = moveDiff
}
}
var enemyCurrentPosition = enemyMovement[enemyMovement.length - 1]
var enemyMinMoveRange = enemyCurrentPosition - enemyMaxMovement
var enemyMaxMoveRange = enemyCurrentPosition + enemyMaxMovement
shots.push( randnum(enemyMinMoveRange, enemyMaxMoveRange) )
shots.push( randnum(enemyMinMoveRange, enemyMaxMoveRange) )
var move = yourMovement[yourMovement.length - 1] + randnum(-2, 2)
var play = []
play.shots = shots
play.move = move