언덕의 왕-Spacewar!


64

Spacewar 를 해본 적이 있다면 ! 재미있는 게임이라는 것을 알고 있습니다. 당신이 모르는 경우, 이것은 가장 중요하고 가장 중요한 컴퓨터 게임 중 하나였습니다. 그리고 여전히 재미 있습니다! 내가 자란 복제본은 이것 입니다. 분명히 불행히도 Windows 만입니다. 그래서 나는 그것을 다시 만들었습니다!

KotH는 여기에서 호스팅됩니다 : PPCG-Spacewar! 언덕의 왕 . 게임이 어떻게 작동하는지 느끼기 위해 적어도 하나의 다른 봇과 대결하여 인간으로 플레이하는 것이 좋습니다.

게임

  • 한 프레임은 30 밀리 초 (즉, 초당 약 33 프레임)입니다.
  • 필드의 너비는 800 픽셀, 높이는 600 픽셀입니다.
  • 이 필드는 토 로이드 형으로, 필드 밖으로 이동하는 우주선과 미사일이 반대편에 다시 나타납니다.
  • 빨간색과 파란색의 두 우주선이 있습니다.
    • 빨간색은 x = 50에, 임의의 y는 50 (필드 높이-50) 픽셀 사이에 위치합니다.
    • 파란색은 x = (필드 너비-50) 및 임의의 y에서 50, (필드 높이-50) 픽셀 사이에 위치합니다.
    • 양면 x = (필드 너비) / 2.
  • 사용 가능한 컨트롤은 다음과 같습니다.
    • 프레임 당 시계 반대 방향으로 5도 왼쪽으로 돌립니다.
    • 오른쪽으로-프레임 당 5도 시계 방향으로 돌립니다.
    • 파이어 미사일-선박이 가리키는 방향으로 선박의 속도와 함께 프레임 당 추가 10 픽셀로 이동합니다.
    • 소방차-우주선이 가리키는 방향으로 프레임 당 0.30 픽셀의 우주선을 가속화합니다.
    • 초 공간 점프-25 %의 확률로 현장에서 임의의 좌표로 순간 이동합니다. 이 임의의 좌표는 태양 위에있을 수 있습니다.
  • 선박의 최대 속도는 엔진 출력에서 ​​프레임 당 15 픽셀, 중력 증폭시 프레임 당 40 픽셀입니다.
    • 프레임 당 15 픽셀보다 빠르게 이동할 경우 엔진 스러스트는 방향 만 변경하거나 속도를 늦출 수 있습니다.
  • 미사일에 관하여 :
    • 미사일은 직선으로 이동합니다.
    • 미사일은 0.1 초당 최대 1의 속도로 발사 될 수 있습니다.
    • 미사일의 수명은 2.25 초입니다.
    • 선박은 각각 최대 20 개의 미사일을 보유하고 있습니다.
    • 미사일은 내부적으로 점 입자입니다.
  • 중앙에 태양이있어 배에 매우 위험합니다. 가장 작은 접촉은 치명적입니다. 이 태양은 또한 미사일을 파괴합니다.
  • 태양에는 중력이 있습니다. 결과 가속은 5000 / (거리 ^ 2) 픽셀 / 프레임 ^ 2이며, 여기서 거리는 픽셀 단위입니다. 우주선과 미사일이 영향을받습니다.
  • 두 선박 모두 코, 왼쪽 날개 및 오른쪽 날개의 세 가지 타격 구역이 있습니다.
    • 코에 부딪 치면 즉시 사망합니다.
    • 어느 한 쪽 날개를 치면 우주선의 회전 속도와 엔진 가속이 절반으로 줄어 듭니다.
    • 두 날개가 모두 파괴되면 우주선을 조종 할 수 없으며 미사일 만 발사 할 수 있습니다.
  • 선박이 서로 충돌 할 수 있습니다.
    • 코 코의 충격은 두 선박 모두에게 치명적입니다.
    • 코 날개 충격은 날개를 파괴합니다.
    • 날개 날개 충격은 두 날개를 모두 파괴합니다.
  • 죽은 배는 1 초 후에 폭발 할 때까지 견고하고 동결됩니다.
  • 적어도 한 척의 선박이 사망 한 후 3 초 후에 필드가 재설정됩니다. 그때까지 태양과 남은 미사일은 여전히 ​​위험합니다.

원래 게임에는 치명적이고 파괴 할 수없는 소행성이 있지만 포함하지는 않습니다.

규칙

  • 봇은 JavaScript로 작성해야합니다.
  • 봇은 약 10 밀리 초로 결정을 제한해야합니다. 귀하의 봇으로 인해 일관된 지연이 발견되면 실격 처리하여 문제를 해결할 수 있도록 알려 드리겠습니다.
  • 봇은 다음에 액세스 할 수 있습니다.
    • 필드 너비 및 필드 높이
    • 태양의 위치와 반경
    • 두 선박의 위치, 회전, 속도, 모양, 미사일 재고 및 우주 공간 상태
    • 모든 미사일의 위치와 속도
  • 메시지가 표시되면 봇이 문자열 목록을 반환해야합니다.
    • 이러한 문자열은 다음 중 하나이어야한다 : turn left, turn right, fire engine, fire missile, hyperspace. 다른 문자열은 무시됩니다.
    • 중복이 있으면 첫 번째 만 기록됩니다.
    • hyperspace 다른 모든 것보다 우선합니다.
    • turn left그리고 turn right같은 시간에 아무런 영향을주지 않습니다.
    • fire engine 배에 코만 있거나 사망 한 경우에는 효과가 없습니다.
    • fire missile 미사일이 너무 최근에 발사 된 경우 아무런 효과가 없습니다.
  • 평소와 다른 방식으로 변경하면 봇은 다른 봇의 행동을 이용할 수 있습니다. 메타 게임을 장려하고 싶습니다.
    • 다른 봇을 모방 하지 않을 수 있습니다 . (즉, 마음을 읽지 않습니다.)
    • 게임 및 물리 코드에서 사용하는 변수를 설정할 수 없습니다 . (즉, 부정 행위 없음)

봇 구현 세부 사항

봇을 filename과 함께 자동으로 포함 된 자체 JavaScript 파일에 저장합니다 bot_<name>.js. 따라서 이것을 방해하거나 JavaScript의 함수 이름 지정을 방해하는 공백이나 문자를 넣지 마십시오. 즉, 다음과 같은 기능을 정의해야하기 때문이다 : <name>_setup(team)<name>_getActions(gameInfo, botVars). 페이지 아래에는 userbot에 대한 텍스트 영역이 있으며 코드를 테스트하기 위해 편집 할 수 있습니다.

<name>_setup(team)

이 함수는 유지하려는 변수를 정의하기위한 것입니다. team이 될 것입니다 "red"또는 "blue". 이 함수는 객체를 반환해야합니다. 다음과 같이 변수를 정의하십시오.

var vars = {};
vars['example'] = "example";
return vars;

vars객체는 다른 함수로 전달됩니다.

<name>_getActions(gameInfo, botVars)

botVars에서 반환 한 객체 <name>_setup(team)입니다. gameInfo다음 변수를 포함하는 객체입니다.

redScore
blueScore
timeLeft

fieldWidth
fieldHeight

sun_x
sun_y
sun_r //sun's radius

gravityStrength //acceleration in pixels/frame^2 at 1 pixel away from the sun's center
engineThrust    //acceleration in pixels/frame^2

speedLimit //maximum speed under engine power
maxSpeed   //maximum speed from gravity boosts

red_x
red_y
red_rot          //rotation in degrees
red_xv           //x velocity
red_yv           //y velocity
red_shape        //one of "full ship", "left wing", "right wing", "nose only"
red_missileStock //the number of missiles red has left
red_inHyperspace //true if red is in hyperspace
red_exploded     //until red explodes, it is still solid and hazardous
red_alive
// likewise for blue //

numMissiles
missiles //this is a list of objects, each with the following variables
  x
  y
  xv
  yv

봇은 이것들에 대한 모든 권한을 가지고 있습니다. 나는 당신 이 그것들에 쓸 수 있고 원래 변수에 영향을 미치지 않을 것이라고 확신 하지만 어쨌든하지 마십시오. 회전에 참고 사항 : 배송 포인트 는 배와 정렬 할 아래로,의 + y 방향으로, 그래서 아무것도 90 개도에 의해 상쇄 될 필요가있다. 또한 양의 회전은 시계 방향입니다.

이 함수는 봇의 동작을 나타내는 문자열 목록을 반환해야합니다. 예를 들면 다음과 같습니다 ["turn right","thrust"]. 이에 대한 자세한 내용은 규칙 섹션에 있습니다.

추가 세부 사항

다음을 사용할 수도 있습니다.

LineIntersection(L1, L2)

L1 및 L2는 2 요소 배열의 2 요소 배열입니다. 즉, L1 := [[x1,y1],[x2,y2]]하고 L2 := [[u1,v1],[u2,v2]]. 이 함수는 두 줄의 교집합을 계산하여 다음을 반환합니다 [[x,y], [a,b]]. [x,y]는 교점의 좌표이며 교점의 [a,b]각 선을 따라 얼마나 멀리 있는지를 나타내는 한 쌍의 비율입니다. 마찬가지로, a = 0.25교차점 길의 4 분에서 것을 의미 [x1,y1][x2,y2], 마찬가지로위한 b. 교차가 없으면 빈 배열이 반환됩니다.

window["shipShapes"]

var shipShapes = {
    'full ship': [[-8,16],[0,-8],[8,16]],
    'left wing': [[-8,16],[0,-8],[4,4],[0,8],[0,16]],
    'right wing':[[-4,4],[0,-8],[8,16],[0,16],[0,8]],
    'nose only': [[-4,4],[0,-8],[4,4],[0,8]]
};

이것들은 선박의 다각형 좌표입니다. 현재 좌표를 쉽게 얻기 위해 다음을 사용할 수도 있습니다.

getShipCoords(<color>)

getShipCoords("red")Red 's ship 정점의 현재 좌표와 마찬가지로 getShipCoords("blue")Blue 의 좌표를 반환합니다 . 이 좌표는 다음과 같은 목록에 [[x1,y1],[x2,y2],[x3,y3],...]있습니다. 다각형은 암시 적으로 닫혀 있으므로 첫 번째 좌표 쌍과 마지막 좌표 쌍 사이에 선이 있습니다.

게임 / 웹 사이트에서 사용중인 다른 변수 나 기능에 액세스하거나 변경할 수 없습니다. 그리고 함수 이름을 동일하게 지정하지 마십시오. 이것이 문제가 될 것이라고 예상하지는 않지만 봇이 게임 코드를 위반하면 그 가능성이 있습니다. 예외를 기록하거나 포착하지 않습니다.

승리

  • 봇의 모든 페어링은 두 가지 방식으로 최소 10 회 플레이해야합니다. (최소 20 게임 이상)
  • 전반적으로 가장 높은 승 / 패 비율을 가지도록 노력하십시오 . 만약 당신의 봇이 다른 봇에 대해서는 아주 잘 맞지만 다른 봇에 대해서는지는 경우, 두 사람에 대해 이기고 두 사람에 대해지는 것 (일반적으로)입니다.
  • 모든 봇에 대해 비율 (wins + 1) / (losses + 1)이 계산 된 다음 이러한 비율의 평균 및 표준 편차가 계산됩니다. 평균이 높을수록 우선 순위가 높고 평균이 서로 1 단위 이내 인 경우 분산이 낮을수록 우선 순위가 높습니다.
  • 채점은 오늘부터 일주일 이내에 또는 새로 제출하지 않은 3 일 후에 시작됩니다. 따라서 봇 쌍을 반복 할 필요가 없습니다.

무엇보다 재미있게 보내십시오!


리더 보드 (2016-01-08 05:15) :

#   Name                       Mean      StdDev
1.  Helios                     13.625    6.852
2.  EdgeCase                    8.335    8.155
3.  OpponentDodger              8.415    8.186
4.  OrbitBot                    5.110    6.294
5.  SunAvoider                  5.276    6.772
6.  DangitBobby                 3.320    4.423
7.  SprayAndPray                3.118    4.642
8.  Engineer                    3.903    6.315
9.  RighthandedSpasms           1.805    2.477
10. AttackAndComeBack           2.521    2.921
11. PanicAttack                 2.622    3.102
12. FullSpeedAhead              2.058    3.295
13. UhhIDKWhatToCallThisBot     2.555    3.406
14. MissilesPlusScore           0.159    0.228
15. Hyper                       0.236    0.332
16. RandUmmm                    0.988    1.329
17. Kamikaze                    0.781    1.793

참고 : 더 많은 게임을 실행하면 변경 될 수 있습니다. 또한 9-13 등급의 순서가 나를 귀찮게하므로 점수 방법을 조정하여 순위를 매기는 방법에 대한 직관에 더 잘 맞출 수 있습니다.

(평균과 표준 편차는 소수점 이하 세 자리로 반올림되었습니다. 또한 강조 표시를 망쳐 Hyper놓아야합니다 HYPER. : P)


모든 점수? ....
ev3commander

예외가 발생했는지 기록합니까?
TheNumberOne

1
LineIntersection교차하지 않는 세그먼트 를 호출 하면 빈 배열이 반환되도록 지정해야합니다 .
LegionMammal978

1
내가 한 것 같아!
ev3commander

3
@CrazyPython : 기본적으로 게임을 복사한다고 생각하는 첫 번째 두 사람에게 이의를 제기했지만 세 번째는 내가 원하는 것입니다. 감사! : D
El'endia Starman

답변:


12

헬리오스

이 봇은 우주의 중심이거나 적어도 그가 생각한다고 생각합니다. 그가하는 첫 번째 일은 중대 오류를 수정하고 자신을 좌표계의 중심에 두는 것입니다. 그런 다음 그는 자신을 중심으로 무언가를 회전시킵니다.

그는 다른 (가짜) 태양을 좋아하지 않으므로 멀리 떨어지려고합니다. 그는 다른 봇을 좋아하지 않기 때문에 좋은 슈팅 위치에 있다면 쏴 버립니다.

function Helios_setup(team) {
    var botVars = {};
    botVars.myPrefix = team + "_";
    botVars.enemyPrefix = team == "red" ? "blue_" : "red_";
    return botVars;
}

function Helios_getActions(gameInfo, botVars) {
    var actions = [];
    var halfPi = Math.PI / 2;
    var engageAngle = Math.PI / 8;

    var field = {};
    field.width = gameInfo.fieldWidth;
    field.height = gameInfo.fieldHeight;
    field.halfWidth = field.width / 2;
    field.halfHeight = field.height / 2;
    field.posOffsetX = field.width * 3 / 2 - gameInfo[botVars.myPrefix + "x"];
    field.posOffsetY = field.height * 3 / 2 - gameInfo[botVars.myPrefix + "y"];
    field.posAngle = (450 - gameInfo[botVars.myPrefix + "rot"]) % 360 * Math.PI / 180;
    field.posSin = Math.sin(-field.posAngle);
    field.posCos = Math.cos(-field.posAngle);
    field.movOffsetXV = -gameInfo[botVars.myPrefix + "xv"];
    field.movOffsetYV = gameInfo[botVars.myPrefix + "yv"];
    field.movAngle = Math.atan2(-field.movOffsetYV, -field.movOffsetXV);
    field.movSin = Math.sin(-field.movAngle);
    field.movCos = Math.cos(-field.movAngle);

    function zeroIfUndefined(v) {
        return v === undefined ? 0 : v;
    }

    function sqr(x) {
        return x * x
    }

    function getEntity(source, prefix) {
        var tmpX = (field.posOffsetX + zeroIfUndefined(source[prefix + "x"])) % field.width - field.halfWidth;
        var tmpY = field.halfHeight - (field.posOffsetY + zeroIfUndefined(source[prefix + "y"])) % field.height;
        var tmpXV = zeroIfUndefined(source[prefix + "xv"]);
        var tmpYV = -zeroIfUndefined(source[prefix + "yv"]);
        var e = {};
        e.posX = tmpX * field.posCos - tmpY * field.posSin;
        e.posY = tmpX * field.posSin + tmpY * field.posCos;
        e.posR = Math.sqrt(sqr(e.posX) + sqr(e.posY));
        e.posPhi = Math.atan2(e.posY, e.posX);
        e.posXV = tmpXV * field.posCos - tmpYV * field.posSin;
        e.posYV = tmpXV * field.posSin + tmpYV * field.posCos;
        e.posV = Math.sqrt(sqr(e.posXV) + sqr(e.posYV));
        e.movX = tmpX * field.movCos - tmpY * field.movSin;
        e.movY = tmpX * field.movSin + tmpY * field.movCos;
        e.movR = Math.sqrt(sqr(e.movX) + sqr(e.movY));
        e.movPhi = Math.atan2(e.movY, e.movX);
        e.movXV = (tmpXV + field.movOffsetXV) * field.movCos - (tmpYV + field.movOffsetYV) * field.movSin;
        e.movYV = (tmpXV + field.movOffsetXV) * field.movSin + (tmpYV + field.movOffsetYV) * field.movCos;
        return e;
    }

    function getShip(prefix) {
        var ship = getEntity(gameInfo, prefix);
        ship.missileStock = gameInfo[prefix + "missileStock"];
        ship.inHyperspace = gameInfo[prefix + "inHyperspace"];
        ship.exploded = gameInfo[prefix + "exploded"];
        ship.alive = gameInfo[prefix + "alive"];
        return ship;
    }

    var myShip = getShip(botVars.myPrefix);
    myShip.movAngle = (field.posAngle - field.movAngle + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
    var enemyShip = getShip(botVars.enemyPrefix);
    var sun = getEntity(gameInfo, "sun_");

    enemyShip.intersectionLine = [[enemyShip.movX - enemyShip.movXV * 30, enemyShip.movY - enemyShip.movYV * 30],
            [enemyShip.movX + enemyShip.movXV * 30, enemyShip.movY + enemyShip.movYV * 30]];

    var intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle) * 10 * 30, Math.sin(myShip.movAngle) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersection = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }
    intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle - 0.001) * 10 * 30, Math.sin(myShip.movAngle - 0.001) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersectionLeft = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }
    intersection = LineIntersection([[0, 0], [Math.cos(myShip.movAngle + 0.001) * 10 * 30, Math.sin(myShip.movAngle + 0.001) * 10 * 30]],
            enemyShip.intersectionLine);
    if (intersection.length == 2) {
        myShip.intersectionRight = Math.abs(intersection[1][0] / 2 + 0.5 - intersection[1][1]);
    }

    function danger() {
        var tmp1 = sqr(sun.movXV) + sqr(sun.movYV);
        var tmp2 = tmp1 == 0 ? 0 : Math.max(0, Math.min(1, ((-sun.movX) * sun.movXV + (-sun.movY) * sun.movYV) / tmp1));
        var dis = Math.sqrt(sqr(sun.movX + tmp2 * sun.movXV) + sqr(sun.movY + tmp2 * sun.movYV));
        if (dis < 30) {
            return true;
        }
        var shipLine1 = [[-16, 8], [-16, -8]];
        var shipLine2 = [[-16, 8], [8, 0]];
        var shipLine3 = [[-16, -8], [8, 0]];
        if (gameInfo.missiles !== undefined) {
            for (var i = 0; i < gameInfo.missiles.length; i++) {
                var missile = getEntity(gameInfo.missiles[i], "");
                var missileLine = [[missile.movX + missile.movXV * 0.5, missile.movY + missile.movYV * 0.5],
                        [missile.movX + missile.movXV * 3, missile.movY + missile.movYV * 3]];
                if (LineIntersection(shipLine1, missileLine).length == 2 ||
                        LineIntersection(shipLine2, missileLine).length == 2 ||
                        LineIntersection(shipLine3, missileLine).length == 2) {
                  return true;
                }
            }
        }
        return false;
    }

    function fire() {
        return enemyShip.alive && !enemyShip.inHyperspace && myShip.intersection !== undefined &&
            myShip.intersection < 0.1 + myShip.missileStock / 200;
    }

    function evadeSun() {
        if ((sun.movPhi >= 0 && myShip.movAngle < 0) || (sun.movPhi <= 0 && myShip.movAngle > 0)) {
            actions.push("fire engine");
        }
        if (sun.movPhi > 0) {
            if (Math.abs(myShip.movAngle) < halfPi) {
                actions.push("turn right");
            } else {
                actions.push("turn left");
            }
        } else {
            if (Math.abs(myShip.movAngle) < halfPi) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
    }

    function aim() {
        if (myShip.intersection !== undefined && myShip.intersectionLeft !== undefined && myShip.intersectionLeft < myShip.intersection) {
            actions.push("turn left");
        } else if (myShip.intersection !== undefined && myShip.intersectionRight !== undefined && myShip.intersectionRight < myShip.intersection) {
            actions.push("turn right");
        } else {
            if (enemyShip.posPhi > 0) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
        if (myShip.posV < 2 || (enemyShip.alive && (enemyShip.movXV >= 0 || myShip.missileStock == 0))) {
            actions.push("fire engine");
        }
    }

    function brake() {
        if (myShip.movAngle > 0) {
            actions.push("turn left");
        } else {
            actions.push("turn right");
        }
        if (Math.abs(myShip.movAngle) > Math.PI * 3 / 4) {
            actions.push("fire engine");
        }
    }

    function engage() {
        if (enemyShip.missileStock > 0) {
            if ((enemyShip.posPhi > 0 && enemyShip.posPhi < engageAngle) || enemyShip.posPhi < -engageAngle) {
                actions.push("turn right");
            } else {
                actions.push("turn left");
            }
        } else {
            if (enemyShip.posPhi > 0) {
                actions.push("turn left");
            } else {
                actions.push("turn right");
            }
        }
        actions.push("fire engine");
    }

    if (myShip.alive && !myShip.inHyperspace) {
        if (danger()) {
            actions.push("hyperspace");
        }
        if (fire()) {
            actions.push("fire missile");
        }
        if (enemyShip.exploded || enemyShip.inHyperspace || sun.movR < 150 || (sun.movR < 300 && Math.abs(sun.movPhi) < Math.PI)) {
            evadeSun();
        } else if (enemyShip.posR < 300 || myShip.intersection !== undefined) {
            aim();
        } else if (myShip.posV > 10) {
            brake();
        } else {
            engage();
        }
    }

    return actions;
}

1
나는 이것이 지금까지 내가 가장 좋아하는 봇 중 하나라고 생각합니다. 놀랍게도 좋습니다!
El'endia Starman

@ El'endiaStarman 나는 봇을 업데이트했습니다.
Sleafar

업데이트가 시작되었습니다!
El'endia Starman

이것은 OrbitBot에 대해 아주 잘 작동합니다 :)
TheNumberOne

1
@Soaku이 봇과 다른 봇의 주요 차이점은이 봇이 촬영 전에 상대를 겨냥한다는 것입니다.
Sleafar

9

SunAvoider

이것은 단지 태양으로부터 멀리 떨어지려고합니다. 그것은 아주 잘합니다 ... 하나 또는 두 개의 날개가 모두 파괴 될 때까지, 그것은 일반적으로 떨어지기 전에 단지 시간 문제입니다.

function SunAvoider_setup(team) {
    var botVars = {};

    botVars["color"] = team;

    return botVars;
}

function SunAvoider_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        var shipx = gameInfo[botVars["color"]+"_x"];
        var shipy = gameInfo[botVars["color"]+"_y"];
        var sunx = gameInfo["sun_x"];
        var suny = gameInfo["sun_y"];
        var dx = shipx - sunx;
        var dy = shipy - suny;
        var dis = Math.sqrt(dx*dx+dy*dy);
        var fireEngineChance = (dis-100)/(gameInfo["fieldHeight"]/2);

        if (Math.random() > fireEngineChance){ actions.push("fire engine") }

        var ang1 = gameInfo[botVars["color"]+"_rot"]+90;
        var ang2 = Math.degrees( Math.atan2(dy, dx) );
        var angDiff = ang2 - ang1;
        if (angDiff < -180) { //http://stackoverflow.com/a/7869457/1473772
            angDiff += 360;
        } else if (angDiff > 180) {
            angDiff -= 360;
        }

        if (angDiff >= 0) {
            actions.push("turn left");
        } else if (angDiff < 0) {
            actions.push("turn right");
        }
    }

    return actions;
}

9

엣지 케이스

태양에서 멀리 떨어진지도 가장자리까지 전속력으로 비행하십시오! 자신이 태양을 향하고있는 것을 발견하면 가장자리로 돌아 가기 위해 몸을 돌리면서 촬영을 시작합니다. 또한 태양에 닿을 때 초 공간으로 들어갑니다.

function EdgeCase_setup(team) {
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}

function EdgeCase_getActions(gameInfo, botVars) {
  var actions = [];

  // Get our ship's position
  var rotation, x, y, opponentAlive;
  if(botVars.color == "red") {
    rotation = gameInfo.red_rot;
    x = gameInfo.red_x;
    y = gameInfo.red_y;
    opponentAlive = gameInfo.blue_alive;
  }
  else if(botVars.color == "blue") {
    rotation = gameInfo.blue_rot;
    x = gameInfo.blue_x;
    y = gameInfo.blue_y;
    opponentAlive = gameInfo.red_alive;
  }

  // Calculate our rotation compared to the sun in degrees
  var sunX = gameInfo.sun_x,
      sunY = gameInfo.sun_y,
      angle = Math.atan2(sunY - y, sunX - x) * 180 / Math.PI,
      rotationToSun = (rotation - angle + 360) % 360;

  // Check if we need to hyperspace to avoid the sun
  var rX = x - sunX,
      rY = y - sunY,
      distanceFromSun = Math.sqrt(rX * rX + rY * rY) - gameInfo.sun_r;
  if(distanceFromSun < 30) actions.push("hyperspace");
  else {

    // Turn away from the sun
    if(rotationToSun > 90 && rotationToSun < 270) {
      actions.push("turn right");
    }
    else actions.push("turn left");

    // Fire engines if we're pointing away from the sun
    if(rotationToSun > 180) {
      actions.push("fire engine");
    }

    // If we shoot while our opponent's dead we can only kill ourself
    else if(opponentAlive) actions.push("fire missile");
  }

  return actions;
}

이 봇은 이제 생방송입니다! 또한, 이것은 놀라 울 정도로 쉽게 생존 할 수있었습니다. 아마도 다른 곳과 같이 어디에서나 미사일을 스팸하지 않는 방법과 관련이 있습니다. : P
El'endia Starman

7

궤도 봇

현재 타겟팅 또는 충돌 방지 기능 이 없습니다 . 태양을 공전 시키려고한다.

편집 : 이제 임팩트가 임박하면 초 공간으로 이동합니다.

function OrbitBot_setup(team) {
  var botVars = {};

  botVars.color = team;
  return botVars;
}


function OrbitBot_getActions(gameInfo, botVars) {
  var actions = [];

  function getVar(name) {
    return gameInfo[botVars.color + "_" + name];
  }

  function getEnemyVar(name) {
    var eColor;
    if (botVars.color == 'blue') {
        eColor = 'red';
    } else {
        eColor = 'blue';
    }
    return gameInfo[eColor + "_" + name];
  }

  function distance(x1, y1, x2, y2) {
    return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  }

  function toroidDistance(x1, y1, x2, y2) {
    dx = Math.abs(x1 - x2);
        while (dx > gameInfo.fieldWidth) {
        dx -= gameInfo.fieldWidth;
    }
    dx = Math.min(dx, gameInfo.fieldWidth - dx);
    dy = Math.abs(y1 - y2);
        while (dx > gameInfo.fieldHeight) {
        dx -= gameInfo.fieldHeight;
    }
    dy = Math.min(dy, gameInfo.fieldHeight - dy);
    return Math.sqrt(dx*dx+dy*dy);
  }

  function angleDistance(theta1, theta2) {
    var d = theta1 - theta2;
    while (d < 0 || d > Math.PI) {
      if (d < 0) {
        d += Math.PI * 2;
      }
      if (d > Math.PI * 2) {
        d -= Math.PI * 2;
      } else if (d > Math.PI) {
        d = Math.PI * 2 - d;
      }
    }
    return d;
  }

  function toRad(degrees) {
    return degrees / 180 * Math.PI;
  }

  function cap(x, y, limit) {
    var r = x*x+y*y;
    if (r < limit * limit) {
        r = Math.sqrt(r);
        x = x * r / limit;
      y = y * r / limit;
    }
    return [x,y];
  }

  var shape = getVar('shape');

  if (shape != 'nose only') {
    var broken = shape != 'full ship';
    var sunX = gameInfo.sun_x,
      sunY = gameInfo.sun_y,
      sunG = gameInfo.gravityStrength;

    function desirability(x, y, vx, vy) {     //Borrowed from a useless bot.
      var lowest = distance(x, y, sunX, sunY) - 5;
      var missiles = gameInfo.missiles;
      for (var i = 0; i < missiles.length; i++) {
        var mx = missiles[i].x + missiles[i].xv / 2;
        var my = missiles[i].y + missiles[i].yv / 2;
        lowest = Math.min(lowest, toroidDistance(x, y, mx, my) - distance(0, 0, missiles[i].xv, missiles[i].yv));
      }
      return lowest - 16;
    }

    var x = getVar("x"),
      y = getVar("y"),
      vx = getVar("xv"),
      vy = getVar("yv");

    function desirabilityByAcceleration(ax, ay) {//Borrowed from a useless bot.
        var x1 = x,
            y1 = y,
          vx1 = vx,
          vy1 = vy;
      var speed = distance(0,0,vx1,vy1);
      var limit = Math.max(gameInfo.speedLimit, speed);

      vx1 += ax;
      vy1 += ay;
      var temp = cap(vx1, vy1, limit);
      vx1 = temp[0];
      vy1 = temp[1];


      var dx = x1 - sunX;
      var dy = y1 - sunY;
      var dis = Math.sqrt(dx*dx+dy*dy);
      if (dis > 5){
        var force = sunG / (dis * dis);
      } else {
        var force = sunG /5;
      }
      vx1 -= force*dx/dis;
      vy1 -= force*dy/dis;

      var temp = cap(vx1, vy1, 40);
      vx1 = temp[0];
      vy1 = temp[1];

      x1 += vx1;
      y1 += vy1;

      return desirability(x1, y1, vx1, vy1);
    }

    var r = distance(sunX, sunY, x, y);
    var theta = Math.atan((y - sunY) / (x - sunX));

    var sunA = sunG/r/r,
            sunAx = -Math.cos(theta) * sunA,
        sunAy = -Math.sin(theta) * sunA;

    var dv = Math.sqrt(sunG / r);
    var dvx = -dv * Math.sin(theta);
    var dvy = dv * Math.cos(theta);
    if (distance(-dvx, -dvy, vx, vy) < distance(dvx, dvy, vx, vy)) {
      dvx = -dvx;
      dvy = -dvy;
    }

    var dax = dvx - vx;
    var day = dvy - vy;

    var dAngle = Math.atan(day / dax);
    if (dax < 0) {
        dAngle += Math.PI;
    }
    var cAngle = toRad(getVar('rot') - 90);
    var dLeft = angleDistance(cAngle - toRad(broken ? 2.5 : 5), dAngle);
    var dRight = angleDistance(cAngle + toRad(broken ? 2.5 : 5), dAngle);
    var dNeither = angleDistance(cAngle, dAngle);
    if (dLeft < dRight && dLeft < dNeither) {
      actions.push('turn left');
    } else if (dRight < dLeft && dRight < dNeither) {
      actions.push('turn right');
    }

    var cax = Math.cos(cAngle) * (broken ? .15 : .3);
    var cay = Math.sin(cAngle) * (broken ? .15 : .3);

    var ax = 0;
    var ay = 0;

    if (distance(cax, cay, dax, day) < distance(0, 0, dax, day)) {
      actions.push('fire engine');
      ax = cax;
      ay = cay;
    }

    if (desirabilityByAcceleration(ax, ay) <= 16) {
        actions.push('hyperspace');
    }

  }

  return actions;
}

봇이 추가되었습니다.
Conor O'Brien

업데이트가 시작되었습니다!
El'endia Starman

5

오른 손잡이

그 이름은 매우 묘사 적입니다. 선택 turn right0.5 확률 fire engine0.5 확률 및 fire missile0.8 확률. 놀라 울 정도로 어려웠습니다. 주로 예측할 수 없기 때문입니다.

function RighthandedSpasms_setup(team) {
    var botVars = {};

    botVars["color"] = team;

    return botVars;
}

function RighthandedSpasms_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        if (Math.random() > 0.5) { actions.push("turn right") }
        if (Math.random() > 0.5) { actions.push("fire engine") }
        if (Math.random() > 0.8) { actions.push("fire missile") }
    }

    return actions;
}

5

랜드

이 도전에는 무작위 봇이 필요했습니다. 골프에 대한 보너스 포인트?

function RandUmmm_setup(t){
    function P(n,t,r,o,e,f,g){for(o=[e=1<<(f=n.length)];e;)for(t=e.toString(2),r=g=t.length,o[--e]=[];r;)~-t[--r]||o[e].push(n[r+f-g]);return o}var q=P(["fire missile","turn right","fire engine","turn left"]);q.pop();
    return {color:t,m:function(){return q[Math.random()*q.length|0]}};
}

function RandUmmm_getActions(g,b){
    return b.m();
}

시원한! (. 그런데, 내 봇하지 13-7 승리 한번 9-1 손실을 고려, 많은,하지만 그건의 많은 총 점 20 점 90 초.!)
ev3commander

@ BlockCoder1392는 ) 랜덤 봇
코너 오브라이언

4

기사

위험 할 때 초 공간을 사용하는 것을 좋아합니다. 그것이 진정한 힘인지 확인하려면 브라우저의 콘솔을 열고을 입력하십시오 overideHyperspace = 0;. 세미콜론을 잊어 버리면 크리스마스에 ASI를 받게됩니다.

function Engineer_setup(t){
    return{c:t,C:"red0blue".split(0)[+(t=="red")]};
}

function Engineer_getActions(gameInfo,botVars){
    var actions = [];

    function d(x1,y1,x2,y2){return Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))}
    function hS(g){return d(g.sun_x,g.sun_y,g[botVars.c+"_x"],g[botVars.c+"_y"])<50}
    function enemyDist(g){return d(g[botVars.c+"_x"],g[botVars.c+"_y"],g[botVars.C+"_x"],g[botVars.C+"_y"]);}

    function hSm(g){
        // get closest missile
        var r = (g.missiles||[{x:10000,y:10000}]).reduce(function(p,c){return Math.min(d(c.x,c.y,g[botVars.c+"_x"],g[botVars.c+"_y"]),p)},Infinity);
        return r<18;
    }
    function dF(g){
        var a = Math.degrees(Math.atan2(g[botVars.C+"_y"]-g[botVars.c+"_y"],g[botVars.C+"_x"]-g[botVars.c+"_x"]));
        var tP = (g[botVars.c+"_rot"]+360-a)%360;
        return [a,tP];
    }
    function lOr(g){
        var tP = dF(g)[1];
        return 90<tP&&tP<270?"turn left":"turn right";
    }
    function thrust(g){
        return Math.abs(dF(g)-g[botVars.c+"_rot"]);
    }

    // are we too close to the sun or a missile?
    if(hS(gameInfo)||hSm(gameInfo))actions.push("hyperspace");

    // should we fire?
    if(enemyDist(gameInfo)<200)actions.push("fire missile");

    // direction function
    actions.push(lOr(gameInfo,botVars));

    if(Math.random()<.7)actions.push("fire engine");
    return actions;
}

3

스프레이 앤 프레이

function SprayAndPray_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function SprayAndPray_getActions(gameInfo, botVars) {
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push("turn left");
        if (Math.random() > 0.5) { actions.push("fire engine")};
       actions.push("fire missile");
    }

    return actions;
}

모든 방향으로 격렬하게 발사됩니다. 그다지 효과적이지 않습니다!


이 봇은 이제 생방송입니다!
El'endia Starman

3

카미카제

경쟁이 심하지는 않지만 재미있을 것이라고 생각했습니다! 촬영하는 동안 상대방을 향해 똑바로 비행하십시오.

function Kamikaze_setup(team) {
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}

function Kamikaze_getActions(gameInfo, botVars) {
  var actions = [];

  // Get our ship's position
  var us, them, red = {
        rotation: gameInfo.red_rot,
        x: gameInfo.red_x,
        y: gameInfo.red_y,
        alive: gameInfo.blue_alive
      },
      blue = {
        rotation: gameInfo.blue_rot,
        x: gameInfo.blue_x,
        y: gameInfo.blue_y,
        alive: gameInfo.blue_alive
      };
  if(botVars.color == "red") {
    us = red;
    them = blue;
  }
  else if(botVars.color == "blue") {
    us = blue;
    them = red;
  }

  // Turn towards our opponent's position
  var angle = Math.degrees(Math.atan2(them.y - us.y, them.x- us.x)),
      rotationToOpponent = (us.rotation - angle + 360) % 360;
  if(rotationToOpponent > 90 && rotationToOpponent < 270) {
    actions.push("turn left");
  }
  else actions.push("turn right");

  actions.push("fire missile", "fire engine");

  return actions;
}

봇이 추가되었습니다!
Conor O'Brien

OpponentDodger에 대 한 끔찍한 ... PanicAttack와 묶여 ...
noɥʇʎԀʎzɐɹƆ

2

UhhIDKWhatToCallThisBot

임의의 물건.

function UhhIDKWhatToCallThisBot_setup(team) {
var botVars = {};
 botVars['t'] = 0;
botVars["color"] = team;
     return botVars;

}

function UhhIDKWhatToCallThisBot_getActions(gameInfo, botVars) {
    var actions = [];
    //when i need it: "turn left",
    //Use missiles sparingly!
    var WCID = [
    "fire engine",
     "turn right",
    "fire engine",
    "fire missile",
    "turn right",
    "fire engine"]

    if (gameInfo[botVars["color"]+"_alive"]) {
        botVars['t']++;
        actions.push(WCID[botVars[t]%(WCID.length)]);
    }
     return actions;
}

비밀스러운 골프는 어때?
noɥʇʎԀʎzɐɹƆ

2

상대 점

나에게서 멀어 지자 !!!

function OpponentDodger_setup(t){b={};b["c"]=t;b['o']=(t=="red")?"blue":"red";return b;}function OpponentDodger_getActions(g,b){a=[];o=b["c"];j={r:g[o+"_rot"],x:g[o+"_x"],y:g[o+"_y"]};o=b["o"];p={r:g[o+"_rot"],x:g[o+"_x"],y:g[o+"_y"]};l=Math.degrees(Math.atan2(p.y-j.y,p.x-j.x)),x=(j.r-l+360)%360;if(x > 90 && x < 270)a.push("turn right");else a.push("turn left");a.push("fire engine");return a;}  

일부 코드는 user81655에게 감사합니다!


이 봇은 이제 생방송입니다!
El'endia Starman

2

스파이

이야기

이 봇의 프로토 타입은 미친 모드와 일반 모드의 두 가지 모드가있는 봇이었습니다. 미친 모드에 있었을 때 일정한 수의 틱을 유지했습니다. 미친 모드에 들어갈 확률은 일정했습니다. 또한 태양에 가까워 졌을 때 초 공간이되었습니다. 미친 모드에서는 다른 봇을 목표로 끊임없이 발사했습니다. 일반 모드에서는 발사하지 않고 다른 봇에서 날아갔습니다.

적이 충분히 가까이있는 경우에만 미친 모드가되도록 프로토 타입을 조정했습니다. 그런 다음 미친 아이디어가있었습니다. 만약 그것이 미친 모드에 머물러 있다면 어떨까요? 몇 가지 실험 후 (보통 모드에서 봇을 무작위로 불렀습니다) 나는 모든 봇보다 Helios를 치는 것을 발견했습니다. 이것은 이 프로세스가 끝날 때이지만 정리하기 전에 내 코드입니다.

나는 KotH textarea 또는 JS beautifier에 전체 봇을 썼습니다. (정리할 때 Atom 편집기를 짧게 사용했지만 두 줄의 코드처럼)

이 봇에는 다른 봇에서 빌린 많은 코드가 들어 있습니다. Kamikaze의 코드를 다른 봇으로 실행하는 대신 다른 봇에서 도망 치도록 돌리고 태양에 가까워지면 HyperCpacing을 위해 EdgeCase에서 코드를 가져옵니다.

아치 천적은 Helios입니다. 그것은 마티니와 이상하고 오랫동안 대화합니다.

미사일과 초 공간이 태양에 가까워지면 70 %의 확률로 다른 봇과 도망칩니다. 저것과 같이 쉬운. 네.

편집 : 새 코드로 내 봇을 테스트했는데 다른 모든 봇에서는 실패합니다. 나는 그것을 고치기 위해 노력하고 있습니다. 방금 이것이 내 새로운 로봇 전용임을 확인했습니다.

코드

function Spy_setup(team) {
  // Typical setup. Nothing to see here. ;)
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function Spy_getActions(gameInfo, botVars) {
    var actions = [];
    var us, them, red = {
            rotation: gameInfo.red_rot,
            x: gameInfo.red_x,
            y: gameInfo.red_y,
            alive: gameInfo.blue_alive
        },
        blue = {
            rotation: gameInfo.blue_rot,
            x: gameInfo.blue_x,
            y: gameInfo.blue_y,
            alive: gameInfo.blue_alive
        };
    if (botVars.color == "red") {
        us = red;
        them = blue;
    } else if (botVars.color == "blue") {
        us = blue;
        them = red;
    }

    function distance(x1, y1, x2, y2) {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    // Get our ship's position
    var rotation, x, y, opponentAlive;
    if (botVars.color == "red") {
        rotation = gameInfo.red_rot;
        x = gameInfo.red_x;
        y = gameInfo.red_y;
        opponentAlive = gameInfo.blue_alive;
    } else if (botVars.color == "blue") {
        rotation = gameInfo.blue_rot;
        x = gameInfo.blue_x;
        y = gameInfo.blue_y;
        opponentAlive = gameInfo.red_alive;
    }

    // Calculate our rotation compared to the sun in degrees
    var sunX = gameInfo.sun_x,
        sunY = gameInfo.sun_y,
        angle = Math.atan2(sunY - y, sunX - x) * 180 / Math.PI,
        rotationToSun = (rotation - angle + 360) % 360;

    // Check if we need to hyperspace to avoid the sun
    var rX = x - sunX,
        rY = y - sunY,
        distanceFromSun = Math.sqrt(rX * rX + rY * rY) - gameInfo.sun_r;
    if (distanceFromSun < 30) {
        actions.push("hyperspace");
        console.log("Command Module is Hyperspacing.")
    }
    if (gameInfo[botVars["color"] + "_alive"]) {
        var angle = Math.degrees(Math.atan2(them.y - us.y, them.x - us.x)),
            rotationToOpponent = (us.rotation - angle + 360) % 360;
        if (rotationToOpponent > 90 && rotationToOpponent < 270) {
            actions.push("turn right");
        } else {
            actions.push("turn left");
        };
        actions.push("fire engine");
        if (Math.random() > 0.3) {
            actions.push("fire missile")
        }

    }
    return actions;
}

기타

참고 : 코드를 정리 한 후 봇을 테스트하지 않았기 때문에 코드를 정리할 때 문제가 발생했을 수 있습니다.

또한 다른 모든 봇보다 훨씬 낫습니다. 실제로 Helios (edit) , SetCourseFor30Degrees 및 OrbitBot를 제외한 다른 모든 봇 을 이겼습니다! SunAvoider와 연결됩니다.

참고 : 나는 자바 스크립트에 끔찍하다. 왜 그런지 모른다.


@ El'endiaStarman 봇을 일시 정지 상태로 두십시오. 봇을 수정해야합니다. 정리 된 버전은 부정한 버전보다 훨씬 나쁩니다.
noɥʇʎԀʎzɐɹƆ

문제가 해결되면 알려주세요.
El'endia Starman

@ El'endiaStarman 일을 한 다음 다시 작동했습니다. 디버깅, 당신은 알고있다! (아직 완료되지 않음)
noɥʇʎԀʎzɐɹƆ

@ El'endiaStarman ... 그리고 끝났습니다!
noɥʇʎԀʎzɐɹƆ

이 봇은 이제 생방송입니다!
El'endia Starman

1

AttackAndComeBack

소용돌이 치는 대신 상단에서 들어오고 하단에서 나와 상단에서 돌아와서 매우 빠르게 발사됩니다. 일반적으로 태양을 피하십시오.

function AttackAndComeBack_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function AttackAndComeBack_getActions(gameInfo, botVars) {
    var actions = [];
    actions.push("fire missile");
    if (Math.random()>0.4){actions.push("turn right");}
    else {actions.push("turn left");}
    actions.push("fire engine");
    return actions;
}

이 봇은 이제 생방송입니다!
El'endia Starman

1

FullSpeedAhead

엔진과 미사일을 항상 발사하지 않고 발사합니다. 때로는 태양을 치기 전에 놀라 울 정도로 오래 지속됩니다.

function FullSpeedAhead_setup(team){
    return {color: team};
}

function FullSpeedAhead_getActions(gameInfo, botVars){
    var actions = [];

    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push("fire engine");
        actions.push("fire missile");
    }
    return actions;
}

내가 생각했던 것만 큼 나쁘지 않다 ...
noɥʇʎԀʎzɐɹƆ

이 봇은 이제 생방송입니다!
El'endia Starman

1

공황 발작

발사 확률 50 %, 좌회전 확률 80 % 그러나 좌회전하지 않으면 우회전합니다. 미사일이 소진 된 후에는 시간이 결국 태양 때문에 멈추게됩니다.

편집 : 적이 살아있을 때 자체 미사일에 의해 살해 될 수 있기 때문에 발사하지 않는 논리가 추가되었습니다.

function PanicAttack_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    return botVars;
}

function PanicAttack_getActions(gameInfo, botVars) {
    var actions = [];
    actions.push("fire engine");
    if(botVars.color == "red") {
        var opponentAlive = gameInfo.blue_alive;
    }
    else if(botVars.color == "blue") {
        var opponentAlive = gameInfo.red_alive;
    }

    if ((Math.random()>0.5)&&opponentAlive) {
        actions.push("fire missile");
    }

    if (Math.random()>0.2) {
        actions.push("turn left");
    } else {
        actions.push("turn right");
    }

    return actions;
}

이 봇은 이제 생방송입니다!
El'endia Starman

@ El'endiaStarman 다시 업데이트하십시오
noɥʇʎԀʎzɐɹƆ

업데이트가 시작되었습니다!
El'endia Starman

1

DangitBobby

Bobby Hill은 다른 사람들이 자신에 대해 어떻게 생각하는지 상관하지 않습니다. 그는 필드 주위를 느리게 흔들면서 상대가 "허스키"코브라처럼 치기 전에 증기가 다 떨어질 때까지 참을성있게 만족합니다.

function DangitBobby_setup(team) {
    var botVars = {};
    botVars["color"] = team;
    if (team == 'red'){
        botVars['them'] = "blue";
    }
    else{
        botVars['them'] = 'red';
    }
    return botVars;
}

function DangitBobby_getActions(gameInfo, botVars) {
    var actions = [];
    if (gameInfo[botVars["color"]+"_alive"]) {
        actions.push('turn right');
        actions.push('fire engine');
        if (gameInfo[botVars['them']+'_missileStock'] == 0){
                actions.push('fire missile');
        }

    }
}

"그거 내 지갑이야! 난 몰라!"


이 봇은 이제 생방송입니다!
El'endia Starman 5

1

저격병

나는 적을 도청하는 저격병을 만들기 위해 약간의 예측을 가지고 놀고 있습니다. 내 자바 스크립트가 너무 커서 답변에 맞지 않으므로 여기 bot_Sniper 링크가 있습니다 .


마침내이 봇을 시험해 보았지만 불행히도 실제로 게임 속도가 느려졌습니다. 꽤 고르지 않으므로 어떻게 든 코드를 더 빨리 만들어야합니다.
El'endia Starman 2016 년

다음에는 코드 용으로 설계된 [GitHub Gists] (gist.github.com)와 같은 서비스에 게시해야합니다.
noɥʇʎԀʎzɐɹƆ

코드를 최적화하십시오. 나는 그것이 얼마나 오래 걸리는지를 고려하면 정말 좋은 봇이라고 확신합니다. 일부 변수 또는 함수를 인링 할 수 있습니다.
noɥʇʎԀʎzɐɹƆ

또한 중복 코드가 있습니다- 스택 교환에서 봇 게시에서 코드 검토에 이르기까지 많은 것을 얻을 것이라고 생각합니다 .
noɥʇʎԀʎzɐɹƆ

또한 외부 범위에서 Actions ()에 넣은 함수를 정의 할 수 있으므로 인터프리터는 Actions ()를 실행할 때마다 함수를 재분석 할 필요가 없습니다. 또한 속도를 높이기 위해 코드를 프로파일 링해야합니다.
noɥʇʎԀʎzɐɹƆ

1

SmartArrow

화살표처럼, 똑똑

function SmartArrow_setup(team) {
    var botVars = {};
    botVars['mpref'] = team + '_';
    botVars['epref'] = team == 'red' ? 'blue_' : 'red_';
    botVars['ecolor'] = team == 'red' ? 'blue' : 'red';
    return botVars;
}

function SmartArrow_getActions(gameInfo, botVars) {
    var actions = [];
    var x = gameInfo[botVars['mpref'] + 'x'],
        y = gameInfo[botVars['mpref'] + 'y'],
        rot = gameInfo[botVars['mpref'] + 'rot']; // SmartArrow position and rotation
    var ex = gameInfo[botVars['epref'] + 'x'],
        ey = gameInfo[botVars['epref'] + 'y']; // Enemy position
    var sunx = gameInfo.sun_x,
        suny = gameInfo.sun_y; // Sun position
    var Dsunx = Math.abs(x - sunx),
        Dsuny = Math.abs(y - suny); // Sun position delta
    var dex = Math.abs(x - ex),
        dey = Math.abs(y - ey); // Enemy position delta
    var sangle = Math.degrees(Math.atan2(suny - y, sunx - x)),
        snrot = (rot - sangle + 360) % 360;
    if (Dsunx < 40 && Dsuny < 40) // If SmartArrow is too close from sun, hyperspace !
        return ['hyperspace'];
    var missiles = gameInfo.missiles;
    for (var i = 0; i < missiles.length; i++) { // Avoid all these silly missiles
        var dx = Math.abs(x - missiles[i].x),
            dy = Math.abs(y - missiles[i].y);
        if (dx < 10 && dy < 10)
            return ['hyperspace'];
    }
    if (gameInfo[botVars['epref'] + 'alive']) { // If his enemy is alive, SmartArrow try to kill him (logic)
        var angle = Math.degrees(Math.atan2(ey - y, ex - x)),
            nrot = (rot - angle + 360) % 360;
        if (nrot > 90 && nrot < 270)
            actions.push('turn left');
        else
            actions.push('turn right');
        if (nrot > 80 && nrot < 100
         && Math.random() > 0.5) actions.push('fire missile'); // If SmartArrow is in a good spot, shot this silly oponnent
        if (Math.random() > 0.5) actions.push('fire engine');
    }
    else { // Simply (try to) act like SunAvoider if his enemy is dead
        if (snrot > 90 && snrot < 270)
            actions.push('turn right');
        else
            actions.push('turn left');
        if (Dsunx < 300 && Dsuny < 300)
            actions.push('fire engine');
        if (dex < 40 && dey < 40)
            actions.push('hyperspace'); // Dying on the corpse of his opponent is dumb.
    }
    return actions;
}

이 봇은 이제 생방송입니다!
El'endia Starman 2016

1

카미카제

또한 경쟁력을 갖도록 설계되지 않았습니다. 재미로. 태양에 가까워지면 초 공간이되어 총알을 발사하지 않고 플레이어를 쫓습니다. 이 봇이 비무장 버전의 Spy를 쫓는 것을 보는 것은 재미 있지만, 불행히도 둘 이상의 userbot을 가질 수는 없습니다.

El'endia : 둘 이상의 userbot 추가를 고려한 적이 있습니다.)

function KamikazePlus_setup(team) {
  // Typical setup. Nothing to see here. ;)
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function KamikazePlus_getActions(gameInfo, botVars) {
    var actions = [];
    var us, them, red = {
            rotation: gameInfo.red_rot,
            x: gameInfo.red_x,
            y: gameInfo.red_y,
            alive: gameInfo.blue_alive
        },
        blue = {
            rotation: gameInfo.blue_rot,
            x: gameInfo.blue_x,
            y: gameInfo.blue_y,
            alive: gameInfo.blue_alive
        };
    if (botVars.color == "red") {
        us = red;
        them = blue;
    } else if (botVars.color == "blue") {
        us = blue;
        them = red;
    }

    function distance(x1, y1, x2, y2) {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    // Get our ship's position
    var rotation, x, y, opponentAlive;
    if (botVars.color == "red") {
        rotation = gameInfo.red_rot;
        x = gameInfo.red_x;
        y = gameInfo.red_y;
        opponentAlive = gameInfo.blue_alive;
    } else if (botVars.color == "blue") {
        rotation = gameInfo.blue_rot;
        x = gameInfo.blue_x;
        y = gameInfo.blue_y;
        opponentAlive = gameInfo.red_alive;
    }

    // Calculate our rotation compared to the sun in degrees
    var sunX = gameInfo.sun_x,
        sunY = gameInfo.sun_y,
        angle = Math.atan2(sunY - y, sunX - x) * 180 / Math.PI,
        rotationToSun = (rotation - angle + 360) % 360;

    // Check if we need to hyperspace to avoid the sun
    var rX = x - sunX,
        rY = y - sunY,
        distanceFromSun = Math.sqrt(rX * rX + rY * rY) - gameInfo.sun_r;
    if (distanceFromSun < 30) {
        actions.push("hyperspace");
        console.log("Command Module is Hyperspacing.")
    }
    if (gameInfo[botVars["color"] + "_alive"]) {
        var angle = Math.degrees(Math.atan2(them.y - us.y, them.x - us.x)),
            rotationToOpponent = (us.rotation - angle + 360) % 360;
        if (rotationToOpponent > 90 && rotationToOpponent < 270) {
            actions.push("turn left");
        } else {
            actions.push("turn right");
        };
        actions.push("fire engine");
    }
    return actions;
}

Kamikaze +의 코드를 가져 와서 미사일 발사 부분을 제거했습니다.


이미 하나의 Kamikaze 봇 이 있었기 때문에이 봇을 추가하지 않을 것입니다 . 게다가, 이것은 다른 두 개보다 더 사소합니다.
El'endia Starman

@ El'endiaStarman은 여러 사용자 봇을 요청합니다. 두 번째 코드 필드는 기본 숨겨진 확장 가능
noɥʇʎԀʎzɐɹƆ

0

미사일

내가 생각해 낸 이상한 아이디어는 점수 차이의 절대 값을 취하고 게임 방식에 따라 무작위로 움직임 목록을 사용한다는 것입니다. 전략이있는 봇에는 효과적이지만 미사일 폭풍에 대해서는 실패합니다. 또한 나의 첫번째 .

function MissilesPlusScore__setup(team) {
var botVars = {};
botVars["color"] = team;
return botVars;
}
function MissilesPlusScore_getActions(gameInfo, botVars) {
var actions = [];
var moves=["fire missile","hyperspace","turn right","turn left","fire engine","fire missile","turn right","hyperspace","turn left","fire missile","hyperspace","turn right","turn left","hyperspace","fire engine","fire missile","turn right","turn left","hyperspace","fire missile","turn right","turn left","fire engine","hyperspace","fire missile","turn right","turn left","hyperspace"];
if(gameInfo[botVars["color"]+"_alive"]){
var num=gameInfo["redScore"]-gameInfo["blueScore"];
if(num<0){num=num*-1;}
if(num===0){actions.push(moves[Math.round(Math.random()*4)]);}
else{
actions.push(moves[num+gameInfo["numMissiles"]]);
}
}
    return actions;
}

하이퍼

하이퍼 스페이스는 멋지다 !!!!!!!!!!!!!!!!

function HYPER_setup(team){var botVars={};botVars["color"]=team;return botVars}function HYPER_getActions(gameInfo,botVars){var actions=[];if(gameInfo[botVars["color"]+"_alive"]){actions.push(["fire engine","fire missile","hyperspace"][Math.round(Math.random()*2)])};return actions}

좌표 영향

좌표를 기반으로 놀랍도록 효과적입니다.

function CoordinateInfluence_setup(team) {
var botVars = {};
botVars["color"] = team;
return botVars;
}
function CoordinateInfluence_getActions(gameInfo, botVars) {
var actions = [];
if (gameInfo[botVars["color"]+"_alive"]) {
if(gameInfo["blue_x"]>gameInfo["red_x"]){
if(gameInfo["blue_y"]<gameInfo["red_y"]){actions.push("turn right");}
else{actions.push("fire engine");}
}
else if(gameInfo["blue_y"]<gameInfo["red_y"]){
if(gameInfo["blue_x"]>gameInfo["red_x"]){actions.push("turn left");}
else{actions.push("fire missile");}
}
else{actions.push("hyperspace");}
}
return actions;
}

이 봇은 모두 살아 있습니다.
El'endia Starman

대신 여러 답변을 게시해야합니다.
noɥʇʎԀʎzɐɹƆ

다른 봇을 추가 한 경우, 핑을 해주세요. 세번째 봇이 생겼습니다.
El'endia Starman

0

SetCourseFor30Degrees

선장이 왜 30도 코스에 배를 세우는 데 지대한 영향을 줄지 모르지만 저기요 소위로 누구에게 의문을 제기해야합니까? 적어도 당신은 태양을 피할 수있는 허가를 받았습니다! 그리고 당신은 미사일을 발사 할 수 있습니다.

function SetCourseFor30Degrees_setup(team) 
{
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function SetCourseFor30Degrees_getActions(gameInfo, botVars)
{
var actions = [];
var ang1 = gameInfo[botVars["color"]+"_rot"]+0;
var fireChance=0.95;
// sun avoidance
   var x = gameInfo[botVars["color"]+"_x"];
   var y = gameInfo[botVars["color"]+"_y"];
   var sunX = gameInfo["sun_x"]+0;
   var sunY = gameInfo["sun_y"]+0;
  var dx = sunX- x;
   var dy = sunY - y;
var shortRangeAvoidanceDistance = (dx * dx + dy * dy ) ;

 x = gameInfo[botVars["color"]+"_x"]+gameInfo[botVars["color"]+"_xv"]*10;
 y = gameInfo[botVars["color"]+"_y"]+gameInfo[botVars["color"]+"_yv"]*10;
 dx = sunX- x;
 dy = sunY - y;

var longRangeAvoidanceDistance = (dx * dx + dy * dy ) ;


var vel = Math.sqrt(gameInfo[botVars["color"]+"_xv"]*gameInfo[botVars["color"]+"_xv"]+
gameInfo[botVars["color"]+"_yv"]*gameInfo[botVars["color"]+"_yv"]);

var close=vel*1.5;

if (shortRangeAvoidanceDistance <= close* close)
{
  actions.push("hyperspace");
}
else
{
   if (longRangeAvoidanceDistance <= 200*200)
   {

     x = x+Math.cos((ang1-5)*Math.PI/180)*vel ;
     y = y+Math.sin((ang1-5)*Math.PI/180)*vel ;
     dx = sunX- x;
     dy = sunY - y;
     if (( dx * dx + dy * dy ) > longRangeAvoidanceDistance  )
     {
       actions.push("turn right")
     }
     else
     {
        actions.push("turn left")
     }
  }
  else
  {
    var course = botVars["color"]=="red"?30:-30;
    if (ang1>course ) {actions.push("turn left")}
    if (ang1<course ) {actions.push("turn right")}
  }
  if (Math.random() > fireChance){ actions.push("fire missile") }
  actions.push("fire engine")
}
return actions;
}

이 봇은 이제 생방송입니다!
El'endia Starman

0

화살

위험에 처했을 때 적의 초 공간을 쫓고 적이 죽었을 때 유휴 상태입니다.

function Arrow_setup(team) {
    var botVars = {};
    botVars['mpref'] = team + '_';
    botVars['epref'] = team == 'red' ? 'blue_' : 'red_';
    return botVars;
}

function Arrow_getActions(gameInfo, botVars) {
    var actions = [];
    var x = gameInfo[botVars['mpref'] + 'x'],
        y = gameInfo[botVars['mpref'] + 'y'],
        rot = gameInfo[botVars['mpref'] + 'rot']; // My position and rotation
    var ex = gameInfo[botVars['epref'] + 'x'],
        ey = gameInfo[botVars['epref'] + 'y']; // Enemy position
    var Dsunx = Math.abs(x - gameInfo.sun_x);
    var Dsuny = Math.abs(y - gameInfo.sun_y);
    if (Dsunx < 30 && Dsuny < 30) // If Arrow is too close from sun, hyperspace !
        return ['hyperspace'];
    var missiles = gameInfo.missiles;
    for (var i = 0; i < missiles.length; i++) {
        var dx = Math.abs(x - missiles[i].x);
        var dy = Math.abs(y - missiles[i].y);
        if (dx < 10 && dy < 10)
            return ['hyperspace'];
    }
    if (gameInfo[botVars['epref'] + 'alive']) {
        var angle = Math.degrees(Math.atan2(ey - y, ex - x)),
            nrot = (rot - angle + 360) % 360;
        if (nrot > 90 && nrot < 270)
            actions.push('turn left');
        else
            actions.push('turn right');
        if (Math.random() > 0.5) actions.push('fire missile');
    }
    if (Math.random() > 0.5) actions.push('fire engine');
    return actions;
}

이 봇은 이제 생방송입니다!
El'endia Starman 2016

@ El'endiaStarman 봇을 업데이트했습니다
TuxCrafting

업데이트가 시작되었습니다! 그래도 많지 않습니다. : P
El'endia Starman 2016

0

카미카제 +

경쟁력을 갖도록 설계되지 않았습니다. 재미로. 기술적으로, 그것은 스파이의 반대입니다 : 플레이어를 쫓아 라. 태양에 가까워지면 초 공간, 미사일 발사 시간의 70 %. 난 그냥 스파이와 스파이가 미친 사람처럼 도망 쫓는 KamikazePlus를보고 싶어.

function KamikazePlus_setup(team) {
  // Typical setup. Nothing to see here. ;)
  var botVars = {};
  botVars["color"] = team;
  return botVars;
}


function KamikazePlus_getActions(gameInfo, botVars) {
    var actions = [];
    var us, them, red = {
            rotation: gameInfo.red_rot,
            x: gameInfo.red_x,
            y: gameInfo.red_y,
            alive: gameInfo.blue_alive
        },
        blue = {
            rotation: gameInfo.blue_rot,
            x: gameInfo.blue_x,
            y: gameInfo.blue_y,
            alive: gameInfo.blue_alive
        };
    if (botVars.color == "red") {
        us = red;
        them = blue;
    } else if (botVars.color == "blue") {
        us = blue;
        them = red;
    }

    function distance(x1, y1, x2, y2) {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
    }

    // Get our ship's position
    var rotation, x, y, opponentAlive;
    if (botVars.color == "red") {
        rotation = gameInfo.red_rot;
        x = gameInfo.red_x;
        y = gameInfo.red_y;
        opponentAlive = gameInfo.blue_alive;
    } else if (botVars.color == "blue") {
        rotation = gameInfo.blue_rot;
        x = gameInfo.blue_x;
        y = gameInfo.blue_y;
        opponentAlive = gameInfo.red_alive;
    }

    // Calculate our rotation compared to the sun in degrees
    var sunX = gameInfo.sun_x,
        sunY = gameInfo.sun_y,
        angle = Math.atan2(sunY - y, sunX - x) * 180 / Math.PI,
        rotationToSun = (rotation - angle + 360) % 360;

    // Check if we need to hyperspace to avoid the sun
    var rX = x - sunX,
        rY = y - sunY,
        distanceFromSun = Math.sqrt(rX * rX + rY * rY) - gameInfo.sun_r;
    if (distanceFromSun < 30) {
        actions.push("hyperspace");
        console.log("Command Module is Hyperspacing.")
    }
    if (gameInfo[botVars["color"] + "_alive"]) {
        var angle = Math.degrees(Math.atan2(them.y - us.y, them.x - us.x)),
            rotationToOpponent = (us.rotation - angle + 360) % 360;
        if (rotationToOpponent > 90 && rotationToOpponent < 270) {
            actions.push("turn left");
        } else {
            actions.push("turn right");
        };
        actions.push("fire engine");
        if (Math.random() > 0.3) {
            actions.push("fire missile")
        }

    }
    return actions;
}

기본적으로 Spy의 코드를 가져 와서 "왼쪽"과 "오른쪽"을 뒤집 었습니다.


이 봇은 이제 생방송입니다! 네, KamikazePlus가 Spy를 쫓는 것을 보는 것은 재미 있습니다. : P
El'endia Starman

@ El'endiaStarman 나는 KamikazePlus가 총알없이 싸우는 것을 보는 것이 재미 있다는 것을 알았습니다 overideHyperspace = 0;. 그들은 서로를 보려고 할 때 그냥 실종 상태입니다.
noɥʇʎԀʎzɐɹƆ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.