눈싸움 KoTH! 라운드, 4 라운드, 4

결과 (2017 년 5 월 22 일 21:40:37 UTC)

Master18 라운드, 2 라운드 잃고 0 라운드
Save One15 라운드, 3 라운드 잃고 2 라운드
Machine Gun14 라운드, 3 라운드, 3 라운드
Monte Bot14 라운드, 3 라운드, 3 라운드
Amb Bot12 라운드 라운드, 8 라운드, 0 라운드
Coward는 11 라운드, 3 라운드, 6 라운드
Pain in the Nash는 11 라운드, 9 라운드, 0 라운드
Nece Bot는 10 라운드, 7 라운드, 3 라운드
Naming Things is Hard는 10 라운드, 7 라운드, 3 라운드
The Procrastinator10 라운드, 8 라운드, 2 라운드
Yggdrasil10 라운드, 10 라운드, 0 라운드
Simple Bot9 라운드, 4 라운드, 4 라운드 7 라운드
Table Bot9 라운드, 6 라운드 5 라운드
Prioritized Random Bot, 8 라운드, 7 라운드, 5 라운드
Upper Hand Bot7 라운드, 13 라운드, 공동 0 라운드
Aggressor6 라운드, 10 라운드, 4 라운드
Insane5 라운드, 15 라운드, 0 라운드
The Ugly Duckling4 라운드, 16 라운드, 0 라운드
Know Bot3 라운드 라운드, 14 라운드, 3 라운드 묶음
Paranoid Bot은 0 라운드, 19 라운드, 1 라운드
Panic Bot0 라운드, 19 라운드, 1 라운드

불행히도 Linux의 bash에서 실행할 수 없기 때문에 Crazy X-Code Randomess를 테스트 할 수 없습니다. 작동시킬 수 있으면 포함시킬 것입니다.

전체 컨트롤러 출력


게임

이것은 매우 간단한 KoTH 게임입니다. 일대일 눈싸움입니다. k눈덩이를 담을 수있는 초기에 빈 용기가 있습니다 . 당신은 최대 j몇 번 오리 . 매 턴마다 두 선수 모두 움직일 대상을 동시에 선택해야합니다. 세 가지 동작이 있습니다.

  • 다시로드 : 당신에게 또 다른 눈덩이를 제공합니다 (최대 k)
  • 던지기 : 눈덩이를 던져 다른 플레이어가 다시 장전하기로 결정하면 죽습니다. 두 선수가 모두 눈덩이를 던지면 아무도 죽지 않습니다.
  • duck : 다른 플레이어가 눈덩이를 던지면 아무 일도 일어나지 않으며 맞지 않습니다. 더 이상 오리가 없으면 아무 일도 일어나지 않으며 다른 플레이어가 눈덩이를 던지면 죽습니다.

목표

죽지 마

Challlenge 사양

프로그램은 모든 언어로 작성 될 수 있습니다. 각 실행에 대한 인수로 이러한 각 변수를 사용해야합니다.

[turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs]

turn-몇 차례의 턴이 경과했는지 ( 0첫 번째 반복에서)
snowballs-당신이 가진 눈덩이의 수
opponent_snowballs-상대가 가진 눈덩이의
ducks
opponent_ducks– 오리를 몇 번 더
max_snowballs오리고 가게 ( k)

주요 기능의 출력은 0재 장전, 1던지기 및 2오리를 위한 것이어야합니다 . 줄 바꿈이 종료 된 이동을 출력해야합니다. 유효하지 않은 동작은 출력하지 않지만 컨트롤러는 복원력이 뛰어나며 유효하지 않은 동작을 출력하더라도 (이동이 정수가 아닌 경우에도) 중단되지 않습니다. 그것은 있어야 하지만 줄 바꿈 종료합니다. 이동이에없는 경우 [0, 1, 2]기본 이동은 0입니다. 우승자는 전체 라운드 로빈 토너먼트에서 가장 많은 승리를 한 선수로 결정됩니다.

규칙

반복 사이의 메모리 저장을 위해 하나의 파일에서 읽거나 쓸 수 있습니다. 봇은 자체 디렉토리에 위치하므로 파일 이름 충돌이 발생하지 않습니다. 내장 함수 (예 : 임의 생성기)는 변경할 수 없습니다. 처음했을 때는 꽤 재밌었 지만 더 이상은 아닙니다. 당신의 프로그램은 실행을 멈추게하는 일을 할 수 없습니다. 표준 허점이 적용 됩니다.

테스팅

컨트롤러의 소스 코드는 여기 에서 찾을 수 있습니다 . 실행 예 : java Controller "python program1/test1.py" "python program2/test2.py" 10 510 개의 눈덩이와 5 개의 오리.

심사

우승자는 전체 라운드 로빈 후 가장 많은 승리를 한 사람을 선택하여 결정됩니다. 이것은 동점이지만, 가장 많은 승리를 얻지 못한 사람들을 모두 제거하십시오. 그런 다음 한 사람이 이길 때까지 반복하십시오. 심사 기준은 50 개의 눈덩이와 25 마리의 오리입니다.

행복한 KoTHing!

편집 : 1000 라운드가 지나면 게임은 동점으로 선언됩니다. 당신의 봇은 그것을 가정 할 수 있습니다 turn < 1000.



답변

마스터, C #

나는 작은 신경망을 훈련시켰다 ( Sharpneat 사용 ). 눈덩이를 집어 들고 더킹을 좋아하는 것 같습니다 …

이전 버전의 컨트롤러에서는 버그를 발견했습니다. 부정 행위로이기는 방법을 발견했을 때 0 %에서 100 %로 상승했습니다.

편집 : 네트워크 상호 상태를 재설정하고 네트워크를 잘못 훈련하는 것을 잊었습니다. 새로 훈련 된 네트워크는 훨씬 작습니다.

using System;
using System.Collections.Generic;

public class Master
{
    public CyclicNetwork _network;

    public static void Main(string[] args)
    {
        int s = int.Parse(args[1]);
        int os = int.Parse(args[2]);
        int d = int.Parse(args[3]);
        int od = int.Parse(args[4]);
        int ms = int.Parse(args[5]);

        var move = new Master().GetMove(s, os, d, od, ms);
        Console.WriteLine(move);
    }

    public Master()
    {
        var nodes = new List<Neuron>
        {
            new Neuron(0, NodeType.Bias),
            new Neuron(1, NodeType.Input),
            new Neuron(2, NodeType.Input),
            new Neuron(3, NodeType.Input),
            new Neuron(4, NodeType.Input),
            new Neuron(5, NodeType.Input),
            new Neuron(6, NodeType.Output),
            new Neuron(7, NodeType.Output),
            new Neuron(8, NodeType.Output),
            new Neuron(9, NodeType.Hidden)
        };
        var connections = new List<Connection>
        {
            new Connection(nodes[1], nodes[6], -1.3921811701131295),
            new Connection(nodes[6], nodes[6], 0.04683387519679514),
            new Connection(nodes[3], nodes[7], -4.746164930591382),
            new Connection(nodes[8], nodes[8], -0.025484025422054933),
            new Connection(nodes[4], nodes[9], -0.02084856381644095),
            new Connection(nodes[9], nodes[6], 4.9614062853759124),
            new Connection(nodes[9], nodes[9], -0.008672587457112968)
        };
        _network = new CyclicNetwork(nodes, connections, 5, 3, 2);
    }

    public int GetMove(int snowballs, int opponentBalls, int ducks, int opponentDucks, int maxSnowballs)
    {
        _network.InputSignalArray[0] = snowballs;
        _network.InputSignalArray[1] = opponentBalls;
        _network.InputSignalArray[2] = ducks;
        _network.InputSignalArray[3] = opponentDucks;
        _network.InputSignalArray[4] = maxSnowballs;

        _network.Activate();

        double max = double.MinValue;
        int best = 0;
        for (var i = 0; i < _network.OutputCount; i++)
        {
            var current = _network.OutputSignalArray[i];

            if (current > max)
            {
                max = current;
                best = i;
            }
        }

        _network.ResetState();

        return best;
    }
}

public class CyclicNetwork
{
    protected readonly List<Neuron> _neuronList;
    protected readonly List<Connection> _connectionList;
    protected readonly int _inputNeuronCount;
    protected readonly int _outputNeuronCount;
    protected readonly int _inputAndBiasNeuronCount;
    protected readonly int _timestepsPerActivation;
    protected readonly double[] _inputSignalArray;
    protected readonly double[] _outputSignalArray;
    readonly SignalArray _inputSignalArrayWrapper;
    readonly SignalArray _outputSignalArrayWrapper;

    public CyclicNetwork(List<Neuron> neuronList, List<Connection> connectionList, int inputNeuronCount, int outputNeuronCount, int timestepsPerActivation)
    {
        _neuronList = neuronList;
        _connectionList = connectionList;
        _inputNeuronCount = inputNeuronCount;
        _outputNeuronCount = outputNeuronCount;
        _inputAndBiasNeuronCount = inputNeuronCount + 1;
        _timestepsPerActivation = timestepsPerActivation;

        _inputSignalArray = new double[_inputNeuronCount];
        _outputSignalArray = new double[_outputNeuronCount];

        _inputSignalArrayWrapper = new SignalArray(_inputSignalArray, 0, _inputNeuronCount);
        _outputSignalArrayWrapper = new SignalArray(_outputSignalArray, 0, outputNeuronCount);
    }
    public int OutputCount
    {
        get { return _outputNeuronCount; }
    }
    public SignalArray InputSignalArray
    {
        get { return _inputSignalArrayWrapper; }
    }
    public SignalArray OutputSignalArray
    {
        get { return _outputSignalArrayWrapper; }
    }
    public virtual void Activate()
    {
        for (int i = 0; i < _inputNeuronCount; i++)
        {
            _neuronList[i + 1].OutputValue = _inputSignalArray[i];
        }

        int connectionCount = _connectionList.Count;
        int neuronCount = _neuronList.Count;
        for (int i = 0; i < _timestepsPerActivation; i++)
        {
            for (int j = 0; j < connectionCount; j++)
            {
                Connection connection = _connectionList[j];
                connection.OutputValue = connection.SourceNeuron.OutputValue * connection.Weight;
                connection.TargetNeuron.InputValue += connection.OutputValue;
            }
            for (int j = _inputAndBiasNeuronCount; j < neuronCount; j++)
            {
                Neuron neuron = _neuronList[j];
                neuron.OutputValue = neuron.Calculate(neuron.InputValue);
                neuron.InputValue = 0.0;
            }
        }
        for (int i = _inputAndBiasNeuronCount, outputIdx = 0; outputIdx < _outputNeuronCount; i++, outputIdx++)
        {
            _outputSignalArray[outputIdx] = _neuronList[i].OutputValue;
        }
    }
    public virtual void ResetState()
    {
        for (int i = 1; i < _inputAndBiasNeuronCount; i++)
        {
            _neuronList[i].OutputValue = 0.0;
        }
        int count = _neuronList.Count;
        for (int i = _inputAndBiasNeuronCount; i < count; i++)
        {
            _neuronList[i].InputValue = 0.0;
            _neuronList[i].OutputValue = 0.0;
        }
        count = _connectionList.Count;
        for (int i = 0; i < count; i++)
        {
            _connectionList[i].OutputValue = 0.0;
        }
    }
}
public class Connection
{
    readonly Neuron _srcNeuron;
    readonly Neuron _tgtNeuron;
    readonly double _weight;
    double _outputValue;

    public Connection(Neuron srcNeuron, Neuron tgtNeuron, double weight)
    {
        _tgtNeuron = tgtNeuron;
        _srcNeuron = srcNeuron;
        _weight = weight;
    }
    public Neuron SourceNeuron
    {
        get { return _srcNeuron; }
    }
    public Neuron TargetNeuron
    {
        get { return _tgtNeuron; }
    }
    public double Weight
    {
        get { return _weight; }
    }
    public double OutputValue
    {
        get { return _outputValue; }
        set { _outputValue = value; }
    }
}

public class Neuron
{
    readonly uint _id;
    readonly NodeType _neuronType;
    double _inputValue;
    double _outputValue;

    public Neuron(uint id, NodeType neuronType)
    {
        _id = id;
        _neuronType = neuronType;

        // Bias neurons have a fixed output value of 1.0
        _outputValue = (NodeType.Bias == _neuronType) ? 1.0 : 0.0;
    }
    public double InputValue
    {
        get { return _inputValue; }
        set
        {
            if (NodeType.Bias == _neuronType || NodeType.Input == _neuronType)
            {
                throw new Exception("Attempt to set the InputValue of bias or input neuron. Bias neurons have no input, and Input neuron signals should be passed in via their OutputValue property setter.");
            }
            _inputValue = value;
        }
    }
    public double Calculate(double x)
    {
        return 1.0 / (1.0 + Math.Exp(-4.9 * x));
    }
    public double OutputValue
    {
        get { return _outputValue; }
        set
        {
            if (NodeType.Bias == _neuronType)
            {
                throw new Exception("Attempt to set the OutputValue of a bias neuron.");
            }
            _outputValue = value;
        }
    }
}

public class SignalArray
{
    readonly double[] _wrappedArray;
    readonly int _offset;
    readonly int _length;

    public SignalArray(double[] wrappedArray, int offset, int length)
    {
        if (offset + length > wrappedArray.Length)
        {
            throw new Exception("wrappedArray is not long enough to represent the requested SignalArray.");
        }

        _wrappedArray = wrappedArray;
        _offset = offset;
        _length = length;
    }

    public double this[int index]
    {
        get
        {
            return _wrappedArray[_offset + index];
        }
        set
        {
            _wrappedArray[_offset + index] = value;
        }
    }
}

public enum NodeType
{
    /// <summary>
    /// Bias node. Output is fixed to 1.0
    /// </summary>
    Bias,
    /// <summary>
    /// Input node.
    /// </summary>
    Input,
    /// <summary>
    /// Output node.
    /// </summary>
    Output,
    /// <summary>
    /// Hidden node.
    /// </summary>
    Hidden
}

답변

파이썬 하나 저장

대부분의 눈덩이를 즉시 던지지 만 상대방이 탄약이 부족한 것을 지켜보고있을 경우에는 항상 눈덩이를 절약합니다. 그런 다음 보장 된 안전한 재 장전 또는 보장 된 킬이없는 한, 재 장전 전에 가능한 한 오랫동안 (1을 절약하면서) 더킹합니다.

import sys
turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs = map(int, sys.argv[1:])

reload_snowball=0
throw=1
duck=2

if snowballs<=1:
    if opponent_snowballs==0:
        if opponent_ducks==0:
            print throw
        else:
            print reload_snowball
    elif ducks > 1:
        print duck
    else:
        print reload_snowball
else:
    print throw

답변

우선 순위 랜덤 랜트, 자바

import java.util.Random;

public class PrioritizedRandomBot implements SnowballFighter {
    static int RELOAD = 0;
    static int THROW = 1;
    static int DUCK = 2;
    static Random rand = new Random();

    public static void main(String[] args) {
        int t = Integer.parseInt(args[0]);
        int s = Integer.parseInt(args[1]);
        int os = Integer.parseInt(args[2]);
        int d = Integer.parseInt(args[3]);
        int od = Integer.parseInt(args[4]);
        int ms = Integer.parseInt(args[5]);
        if (s > os + od) {
            System.out.println(THROW);
            return;
        }
        if (os == 0) {
            if (s == ms || s > 0 && s == od && rand.nextInt(1001 - t) == 0) {
                System.out.println(THROW);
            } else {
                System.out.println(RELOAD);
            }
            return;
        }
        if (os == ms && d > 0) {
            System.out.println(DUCK);
            return;
        }
        int r = rand.nextInt(os + od);
        if (r < s) {
            System.out.println(THROW);
        } else if (r < s + d) {
            System.out.println(DUCK);
        } else {
            System.out.println(RELOAD);
        }
    }
}

이 봇 선택하는 임의의 범위의 정수 0os + od다음과 눈덩이 오리의 현재 번호에 의해 결정되는 임계 값과, 어느 던져 오리 또는 리로드를 선택한다.

한 가지 봇이 다른 봇보다 눈덩이 + 오리보다 많은 눈덩이가 있으면 승리를 강요 할 수 있다는 사실을 알아야합니다. 이것으로부터 “포인트”라는 개념을 생각 해낼 수 있습니다.

my points = s - os - od
op points = os - s - d

 effects of moves on my points
        OPPONENT
       R    T    D
   R        L   ++
 M T   W
 E D   -    +    +

이 숫자 중 하나가 양수가되면, 그 플레이어는 승리를 강요 할 수 있습니다.

points dif = p - op = 2*(s - os) + d - od

 effects of moves on the difference in points (me - my opponent)
        OPPONENT
       R    T    D
   R        L   +++
 M T   W         -
 E D  ---   +


points sum = p + op = - (d + od)

 effects of moves on the sum of points (me + my opponent)
        OPPONENT
       R    T    D
   R        L    +
 M T   W         +
 E D   +    +   ++

“포인트 차이”표는이 경쟁에 대한 게임 이론의 기초를 형성합니다. 모든 정보를 완전히 포착하지는 못하지만 눈덩이가 오리보다 기본적으로 얼마나 가치가 있는지를 보여줍니다 (눈덩이는 공격과 방어 모두). 상대방이 눈덩이를 던지고 성공적으로 오리를 던지면 상대가 더 귀중한 자원을 사용했기 때문에 강제 승리에 한 걸음 더 다가 서게됩니다. 이 표에는 특정 이동 옵션을 사용할 수없는 경우와 같은 많은 특수한 경우에 수행해야 할 작업도 설명되어 있습니다.

“포인트 합계”테이블은 시간이 지남에 따라 포인트 합계가 0에 도달하는 방법을 보여줍니다 (두 플레이어 모두 오리가 부족할 때).이 시점에서 첫 번째 플레이어가 실수 (필요하지 않은 경우 다시로드)하는 즉시 진다.

이제이 강제 전략을 실제로 강제 할 수없는 경우로 확장 해 봅시다 (우리는 큰 마진으로 이기고 있지만 상대방의 마음 읽기는 우리를 이길 것입니다). 기본적으로, 우리는 s눈덩이 를 가지고 있지만이기려면 상대 s+1(또는 s+2등) 시간을 연속적으로 눈덩이로 만들어야합니다 . 이 경우 시간을 벌기 위해 몇 마리의 오리 또는 몇 가지 재 장전을 수행하려고합니다.

바로 지금,이 봇은 항상 일부 오리에서 몰래 빠져 나가기 때문에 즉각적인 손실이 발생할 위험이 없습니다. 우리는 상대방이 가능한 많은 눈덩이를 찌르는 비슷한 전략을 따르고 있다고 생각합니다. 위험한. 또한 예측 가능성을 방지하기 위해 균일하게 분포 된 분포에 따라이를 몰래 숨기려고합니다. 더킹 확률은 던질 눈덩이의 수와 관련하여 수행해야하는 오리의 수와 관련이 있습니다.

심하게 잃어버린 경우, s + d < os + od모든 오리를 사용하는 것 외에도 일부 재 장전에서 몰래 들어가야합니다.이 경우 무작위로 재 장전하고 싶습니다.

이것이 우리의 봇이 던지기, 오리, 다시로드 순서대로 우선 순위를 매기고 os + od난수를 생성하는 데 사용 됩니다. 왜냐하면 우리가해야 할 임계 값 수이기 때문입니다.

봇이 현재 처리하는 하나의 엣지 케이스와 다른 두 가지 특수 케이스가 있습니다. 에지 케이스는 상대방이 눈덩이 나 오리가 없기 때문에 무작위 화가 작동하지 않으므로 가능한 경우 던지십시오. 그렇지 않으면 다시로드합니다. 또 하나의 특별한 경우는 상대방이 재 장전 할 수없고 던지기에 대한 이점이 없기 때문에 (상대자가 오리를 던지거나 던지기 때문에) 항상 오리입니다 (눈덩이를 절약하는 것이 오리를 저장하는 것보다 더 중요하기 때문에). 마지막 특수한 경우는 상대방에게 눈덩이가없는 경우입니다.이 경우 우리는 안전하게 플레이하고 가능한 경우 다시 장전합니다.


답변

NeceBot-파이썬

게임에 대한 게임 이론 테이블은 다음과 같습니다.

        OPPONENT
       R    T     D
   R   ~    L   +D+S
 M T   W    ~   +D-S
 E D -D-S  -D+S   ~

여기서 ~이점 W이 없고, 이기고, L잃는다 +-S는 것은 눈싸움이 상대방보다지고 나가는 +-D것을 의미하며, 오리가 상대방보다지고 나가는 것을 의미합니다. 이것은 완전히 대칭적인 게임입니다.

내 솔루션은 해당 테이블을 고려하지 않습니다. 나는 수학에 나쁘기 때문에.

import sys

RELOAD = 0
THROW = 1
DUCK = 2

def main(turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs):
    if 2 + ducks <3:
        if 2 + snowballs <3:
            return RELOAD
        if 2 + opponent_ducks <3 or 2 + opponent_snowballs <3:
            return THROW
        return RELOAD
    if 2 + snowballs <3:
        if -opponent_snowballs <3 - 5 or 2 + abs(opponent_snowballs - 1) <3:
            return DUCK
        return RELOAD
    if 2 + opponent_ducks <3 or 2 + abs(snowballs - max_snowballs) <3:
        return THROW
    if -snowballs <3 - 6 or turn % 5 <3:
        return THROW
    return DUCK

print(main(*map(int, sys.argv[1:])))

먼저 필요한 것을 줄이려고하기 때문에 NeceBot이라고합니다. 그 후에는 임의의 전략이 있습니다.


답변

겁쟁이-스칼라

상대방에게 탄약이 없으면 던지기, 그렇지 않으면 (우선 순위에 따라) 오리, 던지거나 다시로드합니다.

object Test extends App {
  val s = args(1).toInt
  val os = args(2).toInt
  val d = args(3).toInt

  val move =
    if(os == 0)
      if(s > 0)
        1
      else
        0
    else if(d > 0)
        2
    else if(s > 0)
      1
    else
      0

  println(move)
}

답변

TheUglyDuckling-Python

상대가 비어 있으면 던질 수 없을 때까지 항상 오리를 던지거나 비어 있으면 다시로드합니다. 최후의 수단으로 다시로드를 사용합니다.

import sys

arguments = sys.argv;

turn = int(arguments[1])
snowballs = int(arguments[2])
opponent_snowballs = int(arguments[3])
ducks = int(arguments[4])
opponent_ducks = int(arguments[5])
max_snowballs = int(arguments[6])

if ducks > 0:
    print 2
elif opponent_snowballs == 0 and snowballs > 0:
    print 1
elif opponent_snowballs == 0 and snowballs <= 0:
    print 0
elif snowballs > 0:
    print 1
elif snowballs <= 0:
    print 0

답변

SimpleBot-파이썬 2

import sys
turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs = map(int, sys.argv[1:])

if opponent_snowballs > 0 and ducks > 0: print 2
elif snowballs: print 1
else: print 0

간단한 것들.

  • 상대방에게 눈덩이가 있고 오리가 있다면 오리입니다.
  • 상대방에게 눈덩이가없고 눈덩이가 있으면 던집니다.
  • 다른 경우에는 다시로드하십시오.