স্নোবল লড়াই কোথ!


35

ফলাফল (মে 22 2017 21:40:37 ইউটিসি)

Master18 রাউন্ড জিতেছে, 2 রাউন্ড হারিয়েছে এবং 0 টি রাউন্ডে
Save One15 রাউন্ড জিতেছে, 3 রাউন্ড হারিয়েছে এবং 2 রাউন্ডে
Machine Gun14 টি রাউন্ড জিতেছে, 3 রাউন্ড হারিয়েছে এবং 3 রাউন্ডে
Monte Bot14 টি রাউন্ড জিতেছে, 3 রাউন্ড হারিয়েছে, এবং 3 রাউন্ডে
Amb Botজিতেছে 12 টি রাউন্ডগুলি, 8 টি রাউন্ড
Cowardহেরেছে এবং 0 টি রাউন্ড 11 টি রাউন্ড জিতেছে, 3 রাউন্ড হারিয়েছে এবং 6 রাউন্ডে
Pain in the Nash11 টি রাউন্ড জিতেছে, 9 রাউন্ড হারিয়েছে এবং 0 টি রাউন্ডটি
Nece Bot10 রাউন্ড জিতেছে, 7 রাউন্ড হারিয়েছে, এবং 3 রাউন্ড
Naming Things is Hard10 রাউন্ড জিতেছে, 7 টি রাউন্ড
The Procrastinatorহেরেছে , এবং তিন রাউন্ডে 10 রাউন্ড জিতেছে, 8 রাউন্ড হারিয়েছে, এবং 2 রাউন্ডে
Yggdrasil10 রাউন্ড জিতেছে, 10 রাউন্ড হারিয়েছে, এবং 0 টি রাউন্ডটি
Simple Bot9 রাউন্ড জিতেছে, 4 রাউন্ড হারিয়েছে, এবং 7 রাউন্ডে
Table Bot9 রাউন্ড জিতেছে, 6 হেরেছে রাউন্ডগুলি এবং 5 টি রাউন্ডটি
Prioritized Random Bot8 রাউন্ড জিতেছে, 7 টি রাউন্ড হারিয়েছে এবং 5 রাউন্ড বেঁধেছে
Upper Hand Bot7 রাউন্ড জিতেছে, 13 টি রাউন্ড হারিয়েছে এবং 0 টি রাউন্ডটি
Aggressor6 রাউন্ড জিতেছে, 10 রাউন্ড হারিয়েছে এবং 4 রাউন্ডে
Insane5 টি রাউন্ড জিতেছে, 15 রাউন্ড হারিয়েছে এবং 0 রাউন্ডে
The Ugly Duckling4 রাউন্ড জিতেছে, 16 রাউন্ড হারিয়েছে এবং 0 টি রাউন্ড
Know Botজিতেছে 3 রাউন্ডগুলি, ১৪ টি রাউন্ড হারিয়েছে এবং 3 রাউন্ডে
Paranoid Bot0 টি রাউন্ড জিতেছে, 19 টি রাউন্ড হারিয়েছে এবং 1 রাউন্ডে
Panic Bot0 রাউন্ড জিতেছে, 19 রাউন্ড হারিয়েছে এবং 1 রাউন্ড টাই করেছে

দুর্ভাগ্যক্রমে আমি ক্রেজি এক্স-কোড র‌্যান্ডোমেস পরীক্ষা করতে পারিনি কারণ লিনাক্সে ব্যাশ থেকে চালানোর জন্য আমি এটি পেতে পারি না। যদি আমি এটি কাজে লাগাতে পারি তবে আমি এটি অন্তর্ভুক্ত করব।

সম্পূর্ণ নিয়ামক আউটপুট


খেলাাটি

এটি একটি খুব সাধারণ কোএটিএইচ গেম। এটি একের পর এক তুষারবল লড়াই। আপনার কাছে প্রাথমিকভাবে খালি ধারক রয়েছে যা kস্নোবোল ধরে রাখতে পারে । আপনি jসময় পর্যন্ত হাঁস করতে পারেন । প্রতিবার, উভয় খেলোয়াড়কে একই সাথে কী পদক্ষেপ নেওয়া উচিত তার জন্য একটি পছন্দ দিতে বলা হয়। তিনটি চাল আছে:

  • পুনরায় লোড করুন: আপনাকে আরও একটি স্নোবল দেয় (অবধি k)
  • নিক্ষেপ: একটি স্নোবল নিক্ষেপ করে, যা অন্য খেলোয়াড়কে পুনরায় লোড করার সিদ্ধান্ত নিলে হত্যা করবে। যদি উভয় খেলোয়াড়ই তুষারবল নিক্ষেপ করে তবে কেউ মারা যায় না (তাদের এত ভালো লক্ষ্য রয়েছে যে তারা একে অপরের স্নোবলগুলিতে আঘাত করবে)
  • হাঁস: কিছুই করে না এবং অন্য খেলোয়াড় যদি তুষারবল ছুড়ে দেয় তবে আঘাত হানা এড়ানো যায়। আপনার কাছে যদি আর কোনও হাঁস না থাকে, তবে কিছুই হয় না এবং অন্য খেলোয়াড় যদি স্নোবল নিক্ষেপ করে তবে আপনি মারা যান।

উদ্দেশ্য

মরবে না।

চ্যালেঞ্জ বিশেষ উল্লেখ

আপনার প্রোগ্রামটি যে কোনও ভাষায় লেখা যেতে পারে। আপনি প্রতিটি প্রয়োগের ক্ষেত্রে এই ভেরিয়েবলকে আর্গুমেন্ট হিসাবে গ্রহণ করবেন:

[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 হাঁস হবে।

শুভ কোথিং!

সম্পাদনা : 1000 রাউন্ড পাস হলে গেমটি টাই ঘোষণা করা হবে। আপনার বট এটা ধরে নিতে পারে turn < 1000


মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
ডেনিস

@ হাইপার নিউট্রিনো আরও প্রশ্ন: আমি ভেবেছিলাম "বিচারের মান" 50 টি স্নোবল এবং 25 টি হাঁস হবে? এবং কেন কখনও কখনও ~ 18 রাউন্ডের পরে ড্র হয়?
কমনগ্যুই

@ মনু এহ ক্র্যাপ আমি আমার ভিএম যুক্তিতে সেটিংস পরিবর্তন করতে ভুলে গেছি। এছাড়াও, কারণ এটি যদি স্নোবল সংঘর্ষগুলির একটি অন্তহীন লুপে যায় তবে এটি পিরিয়ড -১ বা পিরিয়ড -২ লুপটি পুনরাবৃত্তি করার 10 রাউন্ড পরে এটি শেষ করে।
হাইপার নিউট্রিনো

1
তো, আর কোন রাউন্ড হবে? কারণ আমি আমার বট আপলোড করতে চাই এবং কৌতূহল হবে যে সে কীভাবে কাজ করবে।
erbsenhirn

@ বারসেনহিরন যদি আপনি কোনও বট আপলোড করেন এবং আমাকে চ্যাটে বা দ্য উনিশতম বাইটে পিং করেন এবং আমি অন্য রান চালাব।
হাইপারনিউটারিনো

উত্তর:


13

মাস্টার, সি #

আমি একটি ছোট নিউরাল নেটওয়ার্ক প্রশিক্ষণ ( শার্পিন্যাট ব্যবহার করে )। দেখে মনে হচ্ছে স্নোবোল বাছাই করা এবং হাঁস ...

নিয়ামকের পূর্ববর্তী সংস্করণে এটি একটি বাগও খুঁজে পেয়েছিল। প্রতারণার মাধ্যমে কীভাবে জিততে হবে তা আবিষ্কার করে এটি 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
}

দৃশ্যত নেটওয়ার্ক
স্টেটটি

কিসের বিরুদ্ধে আপনি নিউরাল নেটওয়ার্ক প্রশিক্ষণ দিয়েছেন? অন্য পোস্টের বিরুদ্ধে এখানে পোস্ট?
জেএডি

@ জারকো ডাবডেলডাম হ্যাঁ, আমি তাদের বেশ কয়েকটি সি # তে পোর্ট করেছিলাম এবং তাদের বিরুদ্ধে নেটওয়ার্কটি প্রশিক্ষণ দিয়েছি। এ কারণেই এটি সম্ভবত নতুন বটের বিরুদ্ধে looseিলে .ালা হবে।
কমনগ্যু

অথবা কেবল বটগুলির বিরুদ্ধে অন্য একটি নেটওয়ার্ককে প্রশিক্ষণ দিন এবং
এটির জন্য

ওয়াত। নিউরাল নেটওয়ার্কের জন্য ৮ টি ভোট!
ক্রিস্টোফার

6

সেভ ওয়ান, পাইথন

এর বেশিরভাগ স্নোবোল অবিলম্বে নিক্ষেপ করে, তবে প্রতিপক্ষ বিরোধী গোলাবারুদ অভাবের জন্য দেখছে এমন ক্ষেত্রে সবসময় একটি সংরক্ষণ করে। তারপরে, কোনও গ্যারান্টিযুক্ত নিরাপদ পুনরায় লোড বা গ্যারান্টিযুক্ত কিল না থাকলে পুনরায় লোড করার আগে এটি যথাসম্ভব দীর্ঘ (আবার, 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

2
আপনার যদি 0 টি স্নোবোল থাকে, তবে এটি 1
কার্ল বোশ

@ কার্লবোশ যা পৌঁছনো অসম্ভব অবস্থা হওয়া উচিত (0 দিয়ে শুরু করা বাদে) তবে আমি যেভাবেই হোক
কেসটি

2
নিয়মগুলি পরিষ্কার করতে @ স্নোরিংফ্রোগ, আপনি 0 টি
স্নোবোল

@ ফিলনটপি: আমি অবশ্যই এটি সম্পূর্ণরূপে উপেক্ষা করেছি। স্পষ্টকরণের জন্য ধন্যবাদ
স্নোরিংফ্রাগ

6

অগ্রাধিকারপ্রাপ্ত র্যান্ডমবট, জাভা

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);
        }
    }
}

এই বট নির্বাচন সীমার মধ্যে একটি র্যান্ডম পূর্ণসংখ্যা 0থেকে os + od, এবং তারপর পারেন থ্রো হাঁস, অথবা রিলোড চয়ন, snowballs হাঁস তার বর্তমান সংখ্যা দ্বারা নির্ধারিত সীমারেখা সঙ্গে।

একটি জিনিস যা অনুধাবন করা গুরুত্বপূর্ণ, তা হ'ল একবার যদি একটি বটটিতে আরও বেশি স্নোবল থাকে তবে অন্য বোটের তুষারপাত + হাঁস থাকে, তারপরে আপনি জয়ের জন্য বাধ্য করতে পারেন। এ থেকে আমরা "পয়েন্ট" এর ধারণাটি নিয়ে আসতে পারি:

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   +    +   ++

"পয়েন্টের মধ্যে পার্থক্য" সারণি এই প্রতিযোগিতার জন্য গেম তত্ত্বের ভিত্তি তৈরি করে। এটি পুরোপুরি সমস্ত তথ্য ক্যাপচার করে না, তবে এটি দেখায় যে স্নোবলগুলি কীভাবে হাঁসের চেয়ে মৌলিকভাবে মূল্যবান হয় (যেহেতু স্নোবলগুলি অপরাধ এবং প্রতিরক্ষা উভয়ই)। যদি প্রতিপক্ষ কোনও তুষারবল নিক্ষেপ করে এবং আপনি সফলতার সাথে হাঁস খেলেন, তবে আপনি জোর করে জয়ের এক ধাপ কাছাকাছি, যেহেতু আপনার প্রতিপক্ষ আরও মূল্যবান সংস্থান ব্যবহার করেছে। এই টেবিলটি আপনাকে বিশেষ ক্ষেত্রে প্রচুর ক্ষেত্রে কী করা উচিত তাও বর্ণনা করে, যেমন যখন নির্দিষ্ট পদক্ষেপের বিকল্পগুলি উপলব্ধ থাকে না।

"পয়েন্টের সমষ্টি" সারণীটি দেখায় যে কীভাবে সময়ের সাথে সাথে পয়েন্টগুলির যোগফল শূন্যের কাছে পৌঁছায় (উভয় খেলোয়াড় হাঁস ছাড়িয়ে যায়), যেখানে প্রথম খেলোয়াড় তত্ক্ষণাত্ ভুল করে (পুনরায় লোড করুন) যখন ত্রুটি করে হারায়।

এখন, আসুন আমরা জোর করে এমন কৌশলগুলি এমন ক্ষেত্রে প্রসারিত করার চেষ্টা করি যেখানে এটি আসলে জোর করে দেওয়া যায় না (যেমন আমরা বড় ব্যবধানে জয়ী হয়েছি তবে প্রতিপক্ষের পক্ষ থেকে মন-পাঠক আমাদের পরাজিত করবে)। মূলত, আমাদের sস্নোবল রয়েছে তবে জয়ের জন্য টানা পরপর আমাদের প্রতিপক্ষকে s+1(বা s+2ইত্যাদি) স্নোবোল করা দরকার। এই ক্ষেত্রে, আমরা কিছু সময় নিজের কাছে কিনতে কিছু হাঁস বা কয়েকটি পুনরায় লোড করতে চাই।

এই মুহূর্তে, এই বটটি সর্বদা কিছু হাঁসের মধ্যে ঝাঁপিয়ে পড়ার চেষ্টা করে, কেবল তখনই এটি তাত্ক্ষণিক ক্ষতির ঝুঁকি নেয় না: আমরা ধরে নিয়েছি যে প্রতিপক্ষ যতটা তত স্নোবোল তলিয়ে যাওয়ার অনুরূপ কৌশল অনুসরণ করছে, তাই পুনরায় লোড করার চেষ্টা করা সত্যই বিপজ্জনক। এছাড়াও, পূর্বাভাসযোগ্যতা রোধ করার জন্য, আমরা অভিন্ন-এলোমেলো বিতরণ অনুসরণ করে এগুলি ছিনিয়ে নিতে চাই: হাঁসের সম্ভাবনা আমাদের যে পরিমাণ স্নোবোল নিক্ষেপ করতে হবে তার তুলনায় আমাদের কতগুলি হাঁস পালন করতে হবে তার সাথে সম্পর্কিত।

যদি আমরা খারাপভাবে হারাতে পারি, s + d < os + odতবে সেই ক্ষেত্রে আমাদের সমস্ত হাঁস ব্যবহার করার সাথে সাথে আমাদের কিছু পুনরায় লোড করতে হবে, এক্ষেত্রে, আমরা এলোমেলোভাবে লোড করতে চাই, তবে আমাদের যতবার প্রয়োজন ততবার।

এ কারণেই আমাদের বটগুলি নিক্ষেপ, হাঁস এবং পুনরায় লোডের ক্রমে অগ্রাধিকার দেয় এবং os + odএলোমেলো সংখ্যা উত্পন্ন করতে ব্যবহার করে, যেহেতু এটি আমাদের চালানোর প্রান্তিক সংখ্যা।

একটি প্রান্তের কেস এবং অন্য দুটি বিশেষ কেস রয়েছে যা বটটি বর্তমানে পরিচালনা করে। প্রান্তের মামলাটি যখন প্রতিপক্ষের তুষারবল বা না হাঁস থাকে এবং তাই এলোমেলোভাবে কাজ করে না, তাই সম্ভব হলে আমরা ছুঁড়ে ফেলি, অন্যথায় আমরা পুনরায় লোড করি। অন্য একটি বিশেষ ক্ষেত্রে হ'ল প্রতিপক্ষ যখন পুনরায় লোড করতে না পারে এবং তাই ছোঁড়াতে কোনও লাভ হয় না (যেহেতু প্রতিপক্ষ হয় হাঁস বা নিক্ষেপ করবে), তাই আমরা সবসময় হাঁসকে (যেহেতু আমাদের স্নোবলগুলি সংরক্ষণ করা আমাদের হাঁসগুলি সংরক্ষণের চেয়ে মূল্যবান)। চূড়ান্ত বিশেষ কেসটি হ'ল যদি প্রতিপক্ষের কোনও তুষারবল না থাকে, সেক্ষেত্রে আমরা এটি নিরাপদে খেলি এবং সম্ভব হলে পুনরায় লোড করি।


এটি একাধিক সংখ্যা মুদ্রণ শেষ করতে পারে যা সঠিকভাবে কাজ করতে পারে না।
হাইপারনিউটারিনো

@ হাইপারনিট্রিনো আমি যখন এই বটটি মুদ্রণ বিবৃতিতে রিটার্ন ব্যবহার করে পুনরায় লিখি তখন আমি একটি "অন্য" ব্লক যুক্ত করতে ভুলে গিয়েছিলাম।
PhiNotPi

1
@ হাইপার নিউট্রিনো এটি আমার জন্য করেছিল, এবং আমি এটি
বগড হিসাবে

আহ। হ্যাঁ, আপনার কোডটি গণ্ডগোলের জন্য দুঃখিত: পি তবে দুর্দান্ত, প্রথম প্রোগ্রাম যা এলোমেলো ব্যবহার করে!
হাইপার নিউট্রিনো

6

নেসবট - পাইথন

এখানে গেমের জন্য গেম থিওরি টেবিল:

        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 বলা হয় কারণ এটি প্রথমে যা প্রয়োজনীয় তা হ্রাস করার চেষ্টা করে। এর পরে এর কিছু স্বেচ্ছাসেবী কৌশল রয়েছে, যা আমি আশা করি কাজ করে।


4
হুই এত <3লোল। গেম টেবিল থাকার জন্য এবং তারপরে এটি ব্যবহার না করার জন্য +1: পি তবে দুর্দান্ত সমাধান :)
হাইপারনিউটারিনো

3 + opponent_snowballs <3এই ভুল হতে পারে?
PhiNotPi

@ ফিলনটপি ইউপ এখনই ঠিক করা হয়েছে, ধন্যবাদ!
আর্টিয়ার

দুর্ভাগ্যক্রমে, প্রচুর সংখ্যক <3
ক্যালকুলেটরফলাইন

5

কাপুরুষ - স্কালা

নিক্ষেপ, যদি প্রতিপক্ষের কাছে কোনও গোলাবারুদ না থাকে, অন্যথায় (অগ্রাধিকারের ক্রমে) হাঁস, নিক্ষেপ বা পুনরায় লোড।

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)
}

দেখে মনে হচ্ছে এটি আমার বটকে জ্যাম করে ...
এরিক দি আউটগল্ফার

5

দ্য ইউগ্লিডাকলিং - পাইথন

প্রতিপক্ষ খালি থাকলে নিক্ষেপ করার চেষ্টা না করা বা উভয়ই ফাঁকা থাকলে পুনরায় লোড না করা পর্যন্ত সর্বদা হাঁসের কাজ করবে। শেষ রিসোর্ট হিসাবে পুনরায় লোড ব্যবহার করবে।

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

5

সিম্পলবট - পাইথন 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

সাধারণ জিনিস।

  • যদি প্রতিপক্ষের স্নোবোল থাকে এবং আপনার কাছে হাঁস থাকে, তবে আপনি হাঁস খেলেন।
  • যদি প্রতিপক্ষের স্নোবোল না থাকে এবং আপনার কাছে থাকে তবে আপনি ছুঁড়ে ফেলুন।
  • অন্য যে কোনও ক্ষেত্রে, আপনি পুনরায় লোড করুন।

5

নামকরণ-বিষয়গুলি-কঠোর বট - ভিবি.এনইটি ET

জিনিসগুলির নামকরণ শক্ত, এবং আমি নিশ্চিত নই যে এর নামকরণের জন্য আমার একটি সমন্বিত কৌশল আছে।

প্রাথমিক বিজয় পেতে প্রথম কয়েকটি রাউন্ডে জুয়া খেলার চেষ্টা করে। এরপরে, হতাশার দ্বারা জয়ের চেষ্টা করে, বাকি সময়টি নিরাপদে খেলে।

Module SnowballFight

    Private Enum Action
        Reload = 0
        ThrowSnowball = 1
        Duck = 2
    End Enum

    Sub Main(args As String())
        Dim turn As Integer = args(0)
        Dim mySnowballs As Integer = args(1)
        Dim opponentSnowballs As Integer = args(2)
        Dim myDucks As Integer = args(3)
        Dim opponentDucks As Integer = args(4)
        Dim maxSnowballs As Integer = args(5)

        If mySnowballs = 0 AndAlso opponentSnowballs = 0 Then
            ' can't throw, no need to duck
            Console.WriteLine(Action.Reload)
            Exit Sub
        End If

        If turn = 2 AndAlso opponentSnowballs > 0 Then
            ' everyone will probably reload and then throw, so try and duck, and throw turn 3
            Console.WriteLine(Action.Duck)
            Exit Sub
        End If

        If turn = 3 AndAlso opponentSnowballs = 0 Then
            ' they threw on turn 2, get them!
            Console.WriteLine(Action.ThrowSnowball)
            Exit Sub
        End If

        If mySnowballs > 0 AndAlso opponentSnowballs = 0 Then
            ' hope they don't duck
            Console.WriteLine(Action.ThrowSnowball)
            Exit Sub
        End If

        If mySnowballs = 0 AndAlso opponentSnowballs > 0 Then
            If myDucks > 0 Then
                ' watch out!
                Console.WriteLine(Action.Duck)
                Exit Sub
            Else
                ' well, maybe we'll get lucky
                Console.WriteLine(Action.Reload)
                Exit Sub
            End If
        End If

        If opponentSnowballs > 0 AndAlso myDucks > 5 Then
            ' play it safe
            Console.WriteLine(Action.Duck)
            Exit Sub
        End If

        If mySnowballs > 5 OrElse opponentDucks < 5 Then
            ' have a bunch saved up, start throwing them
            Console.WriteLine(Action.ThrowSnowball)
            Exit Sub
        End If

        ' start saving up
        Console.WriteLine(Action.Reload)
    End Sub

End Module

5

মেশিনগান, পাইথন 3

প্রতিপক্ষকে হত্যা করার গ্যারান্টি না দেওয়া পর্যন্ত বা তার হাঁস ছাড়ার আগ পর্যন্ত তুষারবলগুলি সংরক্ষণ করার চেষ্টা করে (কোনও ক্ষেত্রে এটি মেশিনগানের মতো তার সমস্ত স্নোবোলকে অন্ধভাবে গুলি চালানো শুরু করে)

প্রতিপক্ষের যখন কোনও তুষারবল থাকে তখন এটি হাঁস খায়, কারণ এটি মরতে চায় না।

from os import sys
args = sys.argv[1:]
turn = int(args[0])
snowballs = int(args[1])
opponent_snowballs = int(args[2])
ducks = int(args[3])
opponent_ducks = int(args[4])
max_snowballs = int(args[5])
if ducks > 0 and opponent_snowballs > 0:
    print("2")
elif snowballs > 0 and opponent_snowballs == 0 and opponent_ducks == 0:
    print("1")
elif ducks == 0 and snowballs > 0:
    print("1")
elif snowballs < max_snowballs:
    print("0")
elif snowballs == max_snowballs:
    print("1")
else:
    print("0")

5

নোয়বট, পাইথন 3

পূর্ববর্তী পদক্ষেপের ট্র্যাক ফ্রিকোয়েন্সি রাখে, ধরে নেয় প্রতিপক্ষ আবার সবচেয়ে ঘন ঘন একটি তৈরি করবে, তার বিরুদ্ধে রক্ষা করবে।

** প্রতিদ্বন্দ্বী তৈরি করতে পারে না এমন চালগুলি প্রত্যাশা না করে আপডেট করা হয়েছে **

import sys,pickle
TURN,BALLS,OTHROWS,DUCKS,ODUCKS,MAXB,OLOADS = [i for i in range(7)]

def save_state(data,prob):
    with open('snowball.pickle', 'wb') as f:
        pickle.dump((data,prob), f)

def load_state():
    with open('snowball.pickle', 'rb') as f:
        return pickle.load(f)

def reload(data = None):
    if not data or data[BALLS]<data[MAXB]:
        print(0)
        return True
    return False

def throw(data):
    if data[BALLS]>0:
        print(1)
        return True
    return False
def duck(data):
    if data[DUCKS]>0:
        print(2)
        return True
    return False


data = [int(v) for v in sys.argv[1:]]
data.append(0)

if data[TURN] > 0:
    last_data,prob = load_state()
    delta = [l-n for l,n in zip(last_data, data)]
    if delta[OTHROWS]<0:
        delta[OTHROWS]=0
        delta[OLOADS]=1
    prob = [p+d for p,d in zip(prob,delta)]
else:
    prob = [0]*7

expected = sorted(((prob[action],action) for action in [OTHROWS, ODUCKS, OLOADS]),
                      reverse=True)
expect = next( (a for p,a in expected if data[a]>0), OLOADS)

if expect == OTHROWS:
    duck(data) or throw(data) or reload()
elif expect == ODUCKS:
    reload(data) or duck(data) or throw(data) or reload()
else:
    throw(data) or reload(data) or duck(data) or reload()

save_state(data,prob);

এটি ঠিক কীভাবে কাজ করে তা সম্পর্কে আমি নিশ্চিত নই, তবে এটি যদি রাউন্ডগুলির মধ্যে ডেটা সংরক্ষণ করে (পরিবর্তনের বিপরীতে) তবে দুর্ভাগ্যক্রমে সমস্ত ডেটা রাউন্ডের মধ্যে মুছে ফেলা হয়। এটি আপনার সমাধানটিকে অকার্যকর করে না তবে কেবল এটি মনে রাখবেন :)
হাইপারনিউটারিনো

রাউন্ডের মধ্যে ডেটা ধরে রাখার আশা করা হয় না, কেবল বর্তমান প্রতিপক্ষের সাথে সঙ্গতিপূর্ণ আশা করা।
আশেলী

ঠিক আছে। ঠিক আছে. আমি কেবল এটি নিশ্চিত করতে চেয়েছিলাম যে কোনও ভ্রান্ত ধারণা নেই। :)
হাইপারনিউটারিনো

4

ব্রাইংলফ , দ্য এগ্র্রেসর

<<?1:0

আগ্রাসী কোন কাপুরুষ! তার যদি স্নোবল থাকে তবে সে ফেলে দেবে! যদি তার কোনও স্নোবোল না থাকে তবে সে আরও বানাবে!

ব্রেনল্ফ , দ্য পাগল

এটি আসলে কোনও বোট নয়, এটি কেবলমাত্র একজন প্রোগ্রামার যাকে আমি অপহরণ করেছিলাম এবং জোর করে বেনিংফল্ফের করা প্রতিটি প্রকল্প পোর্ট করতে বাধ্য করেছিলাম। তার আর বিচক্ষণতা নেই।

<3r!?:1+|%

3 এর চেয়ে কম এলোমেলো সংখ্যা উত্পন্ন করে এবং আউটপুটগুলি t % rযেখানে টি বর্তমান টার্ন এবং আর এলোমেলো সংখ্যা

এগুলি চালানোর জন্য, আপনাকে braingolf.pyগিথুব থেকে ডাউনলোড করতে হবে , তারপরে হয় ব্রাইংফল্ড কোডটি একটি ফাইলে সংরক্ষণ করুন এবং রান করুন

python3 braingolf.py -f filename <space separated inputs>

অথবা কেবল সরাসরি কোডটি sertোকান

python3 braingolf.py -c '<<?1:0' <space separated inputs>

কোড / ফাইলনামের পরে দ্বিতীয় আর্গুমেন্ট যতক্ষণ না আগ্রাসনকারীর তুষারবলের পরিমাণ হিসাবে ইনপুটগুলি যথেষ্ট অপ্রাসঙ্গিক।

দ্রষ্টব্য: আগ্রাসক আসলে টেস্টবোটের সাথে অভিন্ন আচরণ করে, আমি কেবল ব্রেইনগল্ফে একটি প্রবেশিকা তৈরি করতে চেয়েছিলাম

ব্রেনল্ফ , ব্রেইনি [এখনই ভেঙে গেছে]

VR<<<!?v1:v0|R>!?v1:v0|>R<<!?v1:v0|>R<!?v1:v0|<VR<<.m<.m~v<-?~v0:~v1|>vc
VRv.<.>+1-?2_;|>.M<v?:0_;|1

অবশ্যই কাউকে এটি করতে হয়েছিল: ডি নিস, এবং এমনকি গল্ফড! : ডি
হাইপারনিউটারিনো

ওহ অপেক্ষা করুন এটি গফিয়ার বাদে আমার মতো as lol
হাইপারনিউটারিনো

@ হাইপারনিউট্রিনো হ্যাঁ, আমি এখন একটি বাস্তব ভাষায় একটি বাস্তবের উপর কাজ করছি। আমি একজন সত্যিকারের জন্য ব্রেইনল্ফ ব্যবহার করতাম, তবে এটি নেস্টেড শর্তসাপেক্ষে করতে পারে না, ফলে জিনিসগুলি কঠিন হয়ে যায়
স্কিডেদেব

2
আমি মনে করি আপনার পৃথক উত্তর হিসাবে "দ্য ব্রেইনি" পোস্ট করা উচিত। এছাড়াও, আমি মনে করি এটি ভুল হয়েছে।
এরিক আউটগল্ফার

"দ্য পাগল" কোনও স্থিতিশীল বট নয়, সুতরাং @ হাইপার নিউট্রিনো কীভাবে এটি পরীক্ষা করবেন তা আমি নিশ্চিত নই।
এরিক আউটগলফার

3

টেস্টবট - পাইথন

কোনও বৈধ জমা দেওয়ার মতো দেখতে কেমন তা আপনাকে দেখানোর জন্য এটি একটি পরীক্ষার জমা submission কৌশল: বিকল্প পুনরায় লোডিং এবং নিক্ষেপ। বেশ খারাপ কৌশল কিন্তু এটি আপনাকে আপনার প্রোগ্রামটি কীভাবে কাজ করা উচিত সে সম্পর্কে একটি ধারণা দেয়।

from os import sys
arguments = sys.argv;
turn = int(arguments[1])
print(turn % 2)

চান _, turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs = sys.argvআর্গুমেন্ট হবে?
আর্টিয়ার

@ আর্টিয়ার হ্যাঁ দেখা যাচ্ছে যে প্রথম যুক্তিতে ফাইলের নাম রয়েছে।
হাইপারনিউট্রিনো

আপনি sys.argv[1:]যদি _
এটির

2

আপারহ্যান্ডবট, পাইথন 3

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

if snowballs <= opponent_snowballs:
  if opponent_snowballs > 0 and ducks > 0:
    print(2)
  else:
    if snowballs < max_snowballs:
      print(0)
    else:
      print(1)
else:
  print(1)

এই বটটি তার প্রতিপক্ষের থেকে বেশি স্নোবোল সংগ্রহ করার চেষ্টা করে এবং এই মুহুর্তে নিক্ষেপ শুরু হয়। যদি কোনও মুহুর্তে ইউএইচবি এর প্রতিপক্ষের চেয়ে বেশি স্নোবোল না থাকে, তবে তা হবে:

  • হাঁস, যদি প্রতিপক্ষের স্নোবল থাকে এবং এটি হাঁস ছেড়ে যায়
  • অন্যথায়, পুনরায় লোড করুন (যদি না ইউএইচবি সর্বাধিক হয়, তবে এটি পরিবর্তে ছুড়ে দেয়, যদিও আমি মনে করি না যে এই পরিস্থিতি কখনই সামনে আসবে)

2

ইয়েজিড্রসালি, জাভা

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class Yggdrasil implements SnowballFighter {
    public static boolean debug = false;
    static int RELOAD = 0;
    static int THROW = 1;
    static int DUCK = 2;
    static int INVALID = -3;
    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]);
        System.out.println((new Yggdrasil()).move(t, s, os, d, od, ms));
    }

    public final int move(int t, int s, int os, int d, int od, int ms) {
        State state = State.get(s, os, d, od);
        double val = state.val(4);
        double[] strat = state.strat;
        int move = INVALID;
        if (debug) {
            System.out.println(val + " : " + strat[0] + " " + strat[1] + " " + strat[2]);
        }
        while (move == INVALID) {
            double r = rand.nextDouble();
            if (r < strat[RELOAD] && strat[RELOAD] > 0.0001) {
                move = RELOAD;
            } else if (r < strat[RELOAD] + strat[THROW] && strat[THROW] > 0.0001) {
                move = THROW;
            } else if (r < strat[RELOAD] + strat[THROW] + strat[DUCK] && strat[DUCK] > 0.0001) {
                move = DUCK;
            }
        }
        return move;
    }

    public static class State {

        public static boolean debug = false;
        public static int ms = 50;
        public int s;
        public int os;
        public static int md = 25;
        public int d;
        public int od;

        public State(int s, int os, int d, int od) {
            super();
            this.s = s;
            this.os = os;
            this.d = d;
            this.od = od;
        }

        Double val;
        int valdepth;
        double[] strat = new double[3];

        public Double val(int maxdepth) {
            if (s < 0 || s > ms || d < 0 || d > md || os < 0 || os > ms || od < 0 || od > md) {
                return null;
            } else if (val != null && valdepth >= maxdepth) {
                return val;
            }
            if (s > os + od) {
                val = 1.0; // force win
                strat = new double[] { 0, 1, 0 };
            } else if (os > s + d) {
                val = -1.0; // force loss
                strat = new double[] { 1.0 / (1.0 + s + d), s / (1.0 + s + d), d / (1.0 + s + d) };
            } else if (d == 0 && od == 0) {
                val = 0.0; // perfect tie
                if (s > 0) {
                    strat = new double[] { 0, 1, 0 };
                } else {
                    strat = new double[] { 1, 0, 0 };
                }
            } else if (maxdepth <= 0) {
                double togo = 1 - s + os + od;
                double otogo = 1 - os + s + d;
                double per = otogo * otogo / (togo * togo + otogo * otogo);
                double oper = togo * togo / (togo * togo + otogo * otogo);
                val = per - oper;
            } else {
                Double[][] fullmatrix = new Double[3][3];
                boolean[] vm = new boolean[3];
                boolean[] ovm = new boolean[3];
                for (int i = 0; i < 3; i++) {
                    int dest_s = s;
                    int dest_d = d;
                    if (i == 0) {
                        dest_s++;
                    } else if (i == 1) {
                        dest_s--;
                    } else {
                        dest_d--;
                    }
                    for (int j = 0; j < 3; j++) {
                        int dest_os = os;
                        int dest_od = od;
                        if (j == 0) {
                            dest_os++;
                        } else if (j == 1) {
                            dest_os--;
                        } else {
                            dest_od--;
                        }
                        if (i == 0 && j == 1 && dest_os >= 0 && dest_s <= ms) {
                            fullmatrix[i][j] = -1.0; // kill
                        } else if (i == 1 && j == 0 && dest_s >= 0 && dest_os <= ms) {
                            fullmatrix[i][j] = 1.0; // kill
                        } else {
                            fullmatrix[i][j] = get(dest_s, dest_os, dest_d, dest_od).val(maxdepth - 1);
                        }
                        if (fullmatrix[i][j] != null) {
                            vm[i] = true;
                            ovm[j] = true;
                        }
                    }
                }

                if (debug) {
                    System.out.println();
                    System.out.println(maxdepth);
                    System.out.println(s + " " + os + " " + d + " " + od);
                    for (int i = 0; i < 3; i++) {
                        System.out.print(vm[i]);
                    }
                    System.out.println();
                    for (int i = 0; i < 3; i++) {
                        System.out.print(ovm[i]);
                    }
                    System.out.println();
                    for (int i = 0; i < 3; i++) {
                        for (int j = 0; j < 3; j++) {
                            System.out.printf(" %7.4f", fullmatrix[i][j]);
                        }
                        System.out.println();
                    }
                }
                // really stupid way to find an approximate best strategy
                val = -1.0;
                double[] p = new double[3];
                for (p[0] = 0; p[0] < 0.0001 || vm[0] && p[0] <= 1.0001; p[0] += 0.01) {
                    for (p[1] = 0; p[1] < 0.0001 || vm[1] && p[1] <= 1.0001 - p[0]; p[1] += 0.01) {
                        p[2] = 1.0 - p[0] - p[1];
                        if (p[2] < 0.0001 || vm[2]) {
                            double min = 1;
                            for (int j = 0; j < 3; j++) {
                                if (ovm[j]) {
                                    double sum = 0;
                                    for (int i = 0; i < 3; i++) {
                                        if (vm[i]) {
                                            sum += fullmatrix[i][j] * p[i];
                                        }
                                    }
                                    min = Math.min(min, sum);
                                }
                            }
                            if (min > val) {
                                val = min;
                                strat = p.clone();
                            }
                        }
                    }
                }
                if (debug) {
                    System.out.println("v:" + val);
                    System.out.println("s:" + strat[0] + " " + strat[1] + " " + strat[2]);
                }
            }
            valdepth = maxdepth;
            return val;
        }

        static Map<Integer, State> cache = new HashMap<Integer, State>();

        static State get(int s, int os, int d, int od) {
            int key = (((s) * 100 + os) * 100 + d) * 100 + od;
            if (cache.containsKey(key)) {
                return cache.get(key);
            }
            State res = new State(s, os, d, od);
            cache.put(key, res);
            return res;
        }
    }
}

আমি এই বোটটির নাম রেখেছি "ইয়েজিড্রেসিল" কারণ এটি আসলে গেম ট্রি থেকে সামনের দিকে তাকিয়ে থাকে এবং রাষ্ট্রীয় মূল্যায়ন করে, যা থেকে এটি একটি প্রায় আদর্শ মিশ্র কৌশলটি গণনা করতে পারে। যেহেতু এটি মিশ্র কৌশলগুলির উপর নির্ভর করে, এটি অত্যন্ত অ-সংঘবদ্ধ। বাস্তব প্রতিযোগিতায় এই জিনিসটি কতটা ভাল করবে তা আমি জানি না।

এই বট সম্পর্কে কয়েকটি জিনিস:

  • মূলটি একটি পুনরাবৃত্ত ফাংশন যা কোনও নির্দিষ্ট গেমের জন্য মান এবং নিকট-আদর্শ মিশ্র কৌশলটি গণনা করে। এই মুহুর্তে আমি এটি 4 টি ধাপ এগিয়ে দেখছি।
  • এটি অত্যন্ত আকর্ষণীয় ভূমিকা পালন করে, কারণ অনেক ক্ষেত্রে এই বটটি "রক-পেপার-কাঁচিগুলিতে এলোমেলো পদক্ষেপ গ্রহণের" সমতুল্য। এটি তার ভিত্তি ধরে রেখেছে এবং আশা করছে যে প্রতিপক্ষ এটি একটি পরিসংখ্যানগত সুবিধা দেয়। যদি এই বটটি নিখুঁত হয় (যা এটি নয়) তবে এর বিরুদ্ধে আপনি সবচেয়ে ভাল করতে পারতেন হ'ল 50% জয় এবং 50% লোকসান। ফলস্বরূপ, এমন কোনও প্রতিদ্বন্দ্বী নেই যা এটি ধারাবাহিকভাবে মারধর করে, তবে এটির কোনওটিই ধারাবাহিকভাবে হেরে যায়।

আমি এখনও নামটি বুঝতে পারি না ...: পি
হাইপারনিউটারিনো 18:58

@HyperNeutrino Yggdrasil এর একটি পৌরাণিক গাছ, এবং এই ক্ষেত্রে আমি খেলা গাছ উল্লেখ করছি।
PhiNotPi

ওহহহহ, আমার মনে হচ্ছে আমার এটি মনে রাখা উচিত ছিল। : পি সুন্দর!
হাইপারনিউটারিনো

2

ন্যাশ এ ব্যথা (সি ++)

তাই বলা হয় কারণ আমাকে নিজের ন্যাশ ভারসাম্য সমাধানকারী লিখতে হয়েছিল তা ছিল সত্যিকারের ব্যথা। আমি অবাক হয়েছি যে সহজেই উপলভ্য কোনও ন্যাশ-সমাধানের পাঠাগার নেই!

#include <fstream>
#include <iostream>
#include <vector>
#include <array>
#include <random>
#include <utility>

typedef double NumT;
static const NumT EPSILON = 1e-5;

struct Index {
    int me;
    int them;

    Index(int me, int them) : me(me), them(them) {}
};

struct Value {
    NumT me;
    NumT them;

    Value(void) : me(0), them(0) {}

    Value(NumT me, NumT them) : me(me), them(them) {}
};

template <int subDimMe, int subDimThem>
struct Game {
    const std::array<NumT, 9> *valuesMe;
    const std::array<NumT, 9> *valuesThemT;

    std::array<int, subDimMe> coordsMe;
    std::array<int, subDimThem> coordsThem;

    Game(
        const std::array<NumT, 9> *valuesMe,
        const std::array<NumT, 9> *valuesThemT
    )
        : valuesMe(valuesMe)
        , valuesThemT(valuesThemT)
        , coordsMe{}
        , coordsThem{}
    {}

    Index baseIndex(Index i) const {
        return Index(coordsMe[i.me], coordsThem[i.them]);
    }

    Value at(Index i) const {
        Index i2 = baseIndex(i);
        return Value(
            (*valuesMe)[i2.me * 3 + i2.them],
            (*valuesThemT)[i2.me + i2.them * 3]
        );
    }

    Game<2, 2> subgame22(int me0, int me1, int them0, int them1) const {
        Game<2, 2> b(valuesMe, valuesThemT);
        b.coordsMe[0] = coordsMe[me0];
        b.coordsMe[1] = coordsMe[me1];
        b.coordsThem[0] = coordsThem[them0];
        b.coordsThem[1] = coordsThem[them1];
        return b;
    }
};

struct Strategy {
    std::array<NumT, 3> probMe;
    std::array<NumT, 3> probThem;
    Value expectedValue;
    bool valid;

    Strategy(void)
        : probMe{}
        , probThem{}
        , expectedValue()
        , valid(false)
    {}

    void findBestMe(const Strategy &b) {
        if(b.valid && (!valid || b.expectedValue.me > expectedValue.me)) {
            *this = b;
        }
    }
};

template <int dimMe, int dimThem>
Strategy nash_pure(const Game<dimMe, dimThem> &g) {
    Strategy s;
    int choiceMe = -1;
    int choiceThem = 0;
    for(int me = 0; me < dimMe; ++ me) {
        for(int them = 0; them < dimThem; ++ them) {
            const Value &v = g.at(Index(me, them));
            bool valid = true;
            for(int me2 = 0; me2 < dimMe; ++ me2) {
                if(g.at(Index(me2, them)).me > v.me) {
                    valid = false;
                }
            }
            for(int them2 = 0; them2 < dimThem; ++ them2) {
                if(g.at(Index(me, them2)).them > v.them) {
                    valid = false;
                }
            }
            if(valid) {
                if(choiceMe == -1 || v.me > s.expectedValue.me) {
                    s.expectedValue = v;
                    choiceMe = me;
                    choiceThem = them;
                }
            }
        }
    }
    if(choiceMe != -1) {
        Index iBase = g.baseIndex(Index(choiceMe, choiceThem));
        s.probMe[iBase.me] = 1;
        s.probThem[iBase.them] = 1;
        s.valid = true;
    }
    return s;
}

Strategy nash_mixed(const Game<2, 2> &g) {
    //    P    Q
    // p a A  b B
    // q c C  d D

    Value A = g.at(Index(0, 0));
    Value B = g.at(Index(0, 1));
    Value C = g.at(Index(1, 0));
    Value D = g.at(Index(1, 1));

    // q = 1-p, Q = 1-P
    // Pick p such that choice of P,Q is arbitrary

    // p*A+(1-p)*C = p*B+(1-p)*D
    // p*A+C-p*C = p*B+D-p*D
    // p*(A+D-B-C) = D-C
    // p = (D-C) / (A+D-B-C)

    NumT p = (D.them - C.them) / (A.them + D.them - B.them - C.them);

    // P*a+(1-P)*b = P*c+(1-P)*d
    // P*a+b-P*b = P*c+d-P*d
    // P*(a+d-b-c) = d-b
    // P = (d-b) / (a+d-b-c)

    NumT P = (D.me - B.me) / (A.me + D.me - B.me - C.me);

    Strategy s;
    if(p >= -EPSILON && p <= 1 + EPSILON && P >= -EPSILON && P <= 1 + EPSILON) {
        if(p <= 0) {
            p = 0;
        } else if(p >= 1) {
            p = 1;
        }
        if(P <= 0) {
            P = 0;
        } else if(P >= 1) {
            P = 1;
        }
        Index iBase0 = g.baseIndex(Index(0, 0));
        Index iBase1 = g.baseIndex(Index(1, 1));
        s.probMe[iBase0.me] = p;
        s.probMe[iBase1.me] = 1 - p;
        s.probThem[iBase0.them] = P;
        s.probThem[iBase1.them] = 1 - P;
        s.expectedValue = Value(
            P * A.me + (1 - P) * B.me,
            p * A.them + (1 - p) * C.them
        );
        s.valid = true;
    }
    return s;
}

Strategy nash_mixed(const Game<3, 3> &g) {
    //    P    Q    R
    // p a A  b B  c C
    // q d D  e E  f F
    // r g G  h H  i I

    Value A = g.at(Index(0, 0));
    Value B = g.at(Index(0, 1));
    Value C = g.at(Index(0, 2));
    Value D = g.at(Index(1, 0));
    Value E = g.at(Index(1, 1));
    Value F = g.at(Index(1, 2));
    Value G = g.at(Index(2, 0));
    Value H = g.at(Index(2, 1));
    Value I = g.at(Index(2, 2));

    // r = 1-p-q, R = 1-P-Q
    // Pick p,q such that choice of P,Q,R is arbitrary

    NumT q = ((
        + A.them * (I.them-H.them)
        + G.them * (B.them-C.them)
        - B.them*I.them
        + H.them*C.them
    ) / (
        (G.them+E.them-D.them-H.them) * (B.them+I.them-H.them-C.them) -
        (H.them+F.them-E.them-I.them) * (A.them+H.them-G.them-B.them)
    ));

    NumT p = (
        ((G.them+E.them-D.them-H.them) * q + (H.them-G.them)) /
        (A.them+H.them-G.them-B.them)
    );

    NumT Q = ((
        + A.me * (I.me-F.me)
        + C.me * (D.me-G.me)
        - D.me*I.me
        + F.me*G.me
    ) / (
        (C.me+E.me-B.me-F.me) * (D.me+I.me-F.me-G.me) -
        (F.me+H.me-E.me-I.me) * (A.me+F.me-C.me-D.me)
    ));

    NumT P = (
        ((C.me+E.me-B.me-F.me) * Q + (F.me-C.me)) /
        (A.me+F.me-C.me-D.me)
    );

    Strategy s;
    if(
        p >= -EPSILON && q >= -EPSILON && p + q <= 1 + EPSILON &&
        P >= -EPSILON && Q >= -EPSILON && P + Q <= 1 + EPSILON
    ) {
        if(p <= 0) { p = 0; }
        if(q <= 0) { q = 0; }
        if(P <= 0) { P = 0; }
        if(Q <= 0) { Q = 0; }
        if(p + q >= 1) {
            if(p > q) {
                p = 1 - q;
            } else {
                q = 1 - p;
            }
        }
        if(P + Q >= 1) {
            if(P > Q) {
                P = 1 - Q;
            } else {
                Q = 1 - P;
            }
        }
        Index iBase0 = g.baseIndex(Index(0, 0));
        s.probMe[iBase0.me] = p;
        s.probThem[iBase0.them] = P;
        Index iBase1 = g.baseIndex(Index(1, 1));
        s.probMe[iBase1.me] = q;
        s.probThem[iBase1.them] = Q;
        Index iBase2 = g.baseIndex(Index(2, 2));
        s.probMe[iBase2.me] = 1 - p - q;
        s.probThem[iBase2.them] = 1 - P - Q;
        s.expectedValue = Value(
            A.me * P + B.me * Q + C.me * (1 - P - Q),
            A.them * p + D.them * q + G.them * (1 - p - q)
        );
        s.valid = true;
    }
    return s;
}

template <int dimMe, int dimThem>
Strategy nash_validate(Strategy &&s, const Game<dimMe, dimThem> &g, Index unused) {
    if(!s.valid) {
        return s;
    }

    NumT exp;

    exp = 0;
    for(int them = 0; them < dimThem; ++ them) {
        exp += s.probThem[them] * g.at(Index(unused.me, them)).me;
    }
    if(exp > s.expectedValue.me) {
        s.valid = false;
        return s;
    }

    exp = 0;
    for(int me = 0; me < dimMe; ++ me) {
        exp += s.probMe[me] * g.at(Index(me, unused.them)).them;
    }
    if(exp > s.expectedValue.them) {
        s.valid = false;
        return s;
    }

    return s;
}

Strategy nash(const Game<2, 2> &g, bool verbose) {
    Strategy s = nash_mixed(g);
    s.findBestMe(nash_pure(g));
    if(!s.valid && verbose) {
        std::cerr << "No nash equilibrium found!" << std::endl;
    }
    return s;
}

Strategy nash(const Game<3, 3> &g, bool verbose) {
    Strategy s = nash_mixed(g);
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(1, 2,  1, 2)), g, Index(0, 0)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(1, 2,  0, 2)), g, Index(0, 1)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(1, 2,  0, 1)), g, Index(0, 2)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 2,  1, 2)), g, Index(1, 0)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 2,  0, 2)), g, Index(1, 1)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 2,  0, 1)), g, Index(1, 2)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 1,  1, 2)), g, Index(2, 0)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 1,  0, 2)), g, Index(2, 1)));
    s.findBestMe(nash_validate(nash_mixed(g.subgame22(0, 1,  0, 1)), g, Index(2, 2)));
    s.findBestMe(nash_pure(g));
    if(!s.valid && verbose) {
        // theory says this should never happen, but fp precision makes it possible
        std::cerr << "No nash equilibrium found!" << std::endl;
    }
    return s;
}

struct PlayerState {
    int balls;
    int ducks;

    PlayerState(int balls, int ducks) : balls(balls), ducks(ducks) {}

    PlayerState doReload(int maxBalls) const {
        return PlayerState(std::min(balls + 1, maxBalls), ducks);
    }

    PlayerState doThrow(void) const {
        return PlayerState(std::max(balls - 1, 0), ducks);
    }

    PlayerState doDuck(void) const {
        return PlayerState(balls, std::max(ducks - 1, 0));
    }

    std::array<double,3> flail(int maxBalls) const {
        // opponent has obvious win;
        // try stuff at random and hope the opponent is bad

        (void) ducks;

        int options = 0;
        if(balls > 0) {
            ++ options;
        }
        if(balls < maxBalls) {
            ++ options;
        }
        if(ducks > 0) {
            ++ options;
        }

        std::array<double,3> p{};
        if(balls < balls) {
            p[0] = 1.0f / options;
        }
        if(balls > 0) {
            p[1] = 1.0f / options;
        }
        return p;
    }
};

class GameStore {
protected:
    const int balls;
    const int ducks;
    const std::size_t playerStates;
    const std::size_t gameStates;

public:
    static std::string filename(int turn) {
        return "nashdata_" + std::to_string(turn) + ".dat";
    }

    GameStore(int maxBalls, int maxDucks)
        : balls(maxBalls)
        , ducks(maxDucks)
        , playerStates((balls + 1) * (ducks + 1))
        , gameStates(playerStates * playerStates)
    {}

    std::size_t playerIndex(const PlayerState &p) const {
        return p.balls * (ducks + 1) + p.ducks;
    }

    std::size_t gameIndex(const PlayerState &me, const PlayerState &them) const {
        return playerIndex(me) * playerStates + playerIndex(them);
    }

    std::size_t fileIndex(const PlayerState &me, const PlayerState &them) const {
        return 2 + gameIndex(me, them) * 2;
    }

    PlayerState stateFromPlayerIndex(std::size_t i) const {
        return PlayerState(i / (ducks + 1), i % (ducks + 1));
    }

    std::pair<PlayerState, PlayerState> stateFromGameIndex(std::size_t i) const {
        return std::make_pair(
            stateFromPlayerIndex(i / playerStates),
            stateFromPlayerIndex(i % playerStates)
        );
    }

    std::pair<PlayerState, PlayerState> stateFromFileIndex(std::size_t i) const {
        return stateFromGameIndex((i - 2) / 2);
    }
};

class Generator : public GameStore {
    static char toDat(NumT v) {
        int iv = int(v * 256.0);
        return char(std::max(std::min(iv, 255), 0));
    }

    std::vector<Value> next;

public:
    Generator(int maxBalls, int maxDucks)
        : GameStore(maxBalls, maxDucks)
        , next()
    {}

    const Value &nextGame(const PlayerState &me, const PlayerState &them) const {
        return next[gameIndex(me, them)];
    }

    void make_probabilities(
        std::array<NumT, 9> &g,
        const PlayerState &me,
        const PlayerState &them
    ) const {
        const int RELOAD = 0;
        const int THROW = 1;
        const int DUCK = 2;

        g[RELOAD * 3 + RELOAD] =
            nextGame(me.doReload(balls), them.doReload(balls)).me;

        g[RELOAD * 3 + THROW] =
            (them.balls > 0) ? -1
            : nextGame(me.doReload(balls), them.doThrow()).me;

        g[RELOAD * 3 + DUCK] =
            nextGame(me.doReload(balls), them.doDuck()).me;

        g[THROW * 3 + RELOAD] =
            (me.balls > 0) ? 1
            : nextGame(me.doThrow(), them.doReload(balls)).me;

        g[THROW * 3 + THROW] =
            ((me.balls > 0) == (them.balls > 0))
            ? nextGame(me.doThrow(), them.doThrow()).me
            : (me.balls > 0) ? 1 : -1;

        g[THROW * 3 + DUCK] =
            (me.balls > 0 && them.ducks == 0) ? 1
            : nextGame(me.doThrow(), them.doDuck()).me;

        g[DUCK * 3 + RELOAD] =
            nextGame(me.doDuck(), them.doReload(balls)).me;

        g[DUCK * 3 + THROW] =
            (them.balls > 0 && me.ducks == 0) ? -1
            : nextGame(me.doDuck(), them.doThrow()).me;

        g[DUCK * 3 + DUCK] =
            nextGame(me.doDuck(), them.doDuck()).me;
    }

    Game<3, 3> make_game(const PlayerState &me, const PlayerState &them) const {
        static std::array<NumT, 9> globalValuesMe;
        static std::array<NumT, 9> globalValuesThemT;
        #pragma omp threadprivate(globalValuesMe)
        #pragma omp threadprivate(globalValuesThemT)

        make_probabilities(globalValuesMe, me, them);
        make_probabilities(globalValuesThemT, them, me);
        Game<3, 3> g(&globalValuesMe, &globalValuesThemT);
        for(int i = 0; i < 3; ++ i) {
            g.coordsMe[i] = i;
            g.coordsThem[i] = i;
        }
        return g;
    }

    Strategy solve(const PlayerState &me, const PlayerState &them, bool verbose) const {
        if(me.balls > them.balls + them.ducks) { // obvious answer
            Strategy s;
            s.probMe[1] = 1;
            s.probThem = them.flail(balls);
            s.expectedValue = Value(1, -1);
            return s;
        } else if(them.balls > me.balls + me.ducks) { // uh-oh
            Strategy s;
            s.probThem[1] = 1;
            s.probMe = me.flail(balls);
            s.expectedValue = Value(-1, 1);
            return s;
        } else if(me.balls == 0 && them.balls == 0) { // obvious answer
            Strategy s;
            s.probMe[0] = 1;
            s.probThem[0] = 1;
            s.expectedValue = nextGame(me.doReload(balls), them.doReload(balls));
            return s;
        } else {
            return nash(make_game(me, them), verbose);
        }
    }

    void generate(int turns, bool saveAll, bool verbose) {
        next.clear();
        next.resize(gameStates);
        std::vector<Value> current(gameStates);
        std::vector<char> data(2 + gameStates * 2);

        for(std::size_t turn = turns; (turn --) > 0;) {
            if(verbose) {
                std::cerr << "Generating for turn " << turn << "..." << std::endl;
            }
            NumT maxDiff = 0;
            NumT msd = 0;
            data[0] = balls;
            data[1] = ducks;
            #pragma omp parallel for reduction(+:msd), reduction(max:maxDiff)
            for(std::size_t meBalls = 0; meBalls < balls + 1; ++ meBalls) {
                for(std::size_t meDucks = 0; meDucks < ducks + 1; ++ meDucks) {
                    const PlayerState me(meBalls, meDucks);
                    for(std::size_t themBalls = 0; themBalls < balls + 1; ++ themBalls) {
                        for(std::size_t themDucks = 0; themDucks < ducks + 1; ++ themDucks) {
                            const PlayerState them(themBalls, themDucks);
                            const std::size_t p1 = gameIndex(me, them);

                            Strategy s = solve(me, them, verbose);

                            NumT diff;

                            data[2+p1*2  ] = toDat(s.probMe[0]);
                            data[2+p1*2+1] = toDat(s.probMe[0] + s.probMe[1]);
                            current[p1] = s.expectedValue;
                            diff = current[p1].me - next[p1].me;
                            msd += diff * diff;
                            maxDiff = std::max(maxDiff, std::abs(diff));
                        }
                    }
                }
            }

            if(saveAll) {
                std::ofstream fs(filename(turn).c_str(), std::ios_base::binary);
                fs.write(&data[0], data.size());
                fs.close();
            }

            if(verbose) {
                std::cerr
                    << "Expectations changed by at most " << maxDiff
                    << " (RMSD: " << std::sqrt(msd / gameStates) << ")" << std::endl;
            }
            if(maxDiff < 0.0001f) {
                if(verbose) {
                    std::cerr << "Expectations have converged. Stopping." << std::endl;
                }
                break;
            }
            std::swap(next, current);
        }

        // Always save turn 0 with the final converged expectations
        std::ofstream fs(filename(0).c_str(), std::ios_base::binary);
        fs.write(&data[0], data.size());
        fs.close();
    }
};

void open_file(std::ifstream &target, int turn, int maxDucks, int maxBalls) {
    target.open(GameStore::filename(turn).c_str(), std::ios::binary);
    if(target.is_open()) {
        return;
    }

    target.open(GameStore::filename(0).c_str(), std::ios::binary);
    if(target.is_open()) {
        return;
    }

    Generator(maxBalls, maxDucks).generate(200, false, false);
    target.open(GameStore::filename(0).c_str(), std::ios::binary);
}

int choose(int turn, const PlayerState &me, const PlayerState &them, int maxBalls) {
    std::ifstream fs;
    open_file(fs, turn, std::max(me.ducks, them.ducks), maxBalls);

    unsigned char balls = fs.get();
    unsigned char ducks = fs.get();
    fs.seekg(GameStore(balls, ducks).fileIndex(me, them));
    unsigned char p0 = fs.get();
    unsigned char p1 = fs.get();
    fs.close();

    // only 1 random number per execution; no need to seed a PRNG
    std::random_device rand;
    int v = std::uniform_int_distribution<int>(0, 254)(rand);
    if(v < p0) {
        return 0;
    } else if(v < p1) {
        return 1;
    } else {
        return 2;
    }
}

int main(int argc, const char *const *argv) {
    if(argc == 4) { // maxTurns, maxBalls, maxDucks
        Generator(atoi(argv[2]), atoi(argv[3])).generate(atoi(argv[1]), true, true);
        return 0;
    }

    if(argc == 7) { // turn, meBalls, themBalls, meDucks, themDucks, maxBalls
        std::cout << choose(
            atoi(argv[1]),
            PlayerState(atoi(argv[2]), atoi(argv[4])),
            PlayerState(atoi(argv[3]), atoi(argv[5])),
            atoi(argv[6])
        ) << std::endl;
        return 0;
    }

    return 1;
}

সি ++ 11 বা আরও ভাল হিসাবে সংকলন করুন। পারফরম্যান্সের জন্য, ওপেনএমপি সমর্থন দিয়ে সংকলন করা ভাল (তবে এটি কেবল গতির জন্য; এটির প্রয়োজন নেই)

g++ -std=c++11 -fopenmp pain_in_the_nash.cpp -o pain_in_the_nash

এটি প্রতিটি ঘুরিয়ে কী করা উচিত তা সিদ্ধান্ত নিতে ন্যাশ ভারসাম্য ব্যবহার করে, যার অর্থ হল যে তত্ত্বের ভিত্তিতে প্রতিদ্বন্দ্বী কোনও কৌশলই ব্যবহার করেন না কেন, দীর্ঘমেয়াদে (বহু গেমের উপরে) সর্বদা জিতে বা আঁকবে। এটি বাস্তবে কেস কিনা তা নির্ভর করে আমি বাস্তবায়নে কোনও ত্রুটি করেছি কিনা তার উপর। তবে যেহেতু এই কোএইচটি প্রতিযোগিতা কেবল প্রতিটি প্রতিপক্ষের বিরুদ্ধে একক রাউন্ড রয়েছে, সম্ভবত এটি লিডারবোর্ডে খুব ভাল করবে না।

আমার আসল ধারণাটি ছিল প্রতিটি গেম স্টেটের জন্য একটি সাধারণ মূল্যায়ন ফাংশন (যেমন প্রতিটি বলের মূল্য + বি, প্রতিটি হাঁস ++ ডি) থাকে তবে এই মূল্যায়নগুলি কী হবে তা নির্ধারণ করার ক্ষেত্রে সুস্পষ্ট সমস্যা দেখা দেয় এবং এর অর্থ এটি হতে পারে না আরও বেশি সংখ্যক বল সংগ্রহের আয় কমিয়ে আনার উপর কাজ করুন ইত্যাদি পরিবর্তে এটি পুরো গেম ট্রিটিকে 1000 এর মোড় থেকে পিছনের দিকে কাজ করে বিশ্লেষণ করবে এবং প্রতিটি গেম কীভাবে প্যান করতে পারে তার ভিত্তিতে প্রকৃত মূল্যায়ন পূরণ করবে।

ফলাফলটি হ'ল কয়েকটি কৌশলযুক্ত "সুস্পষ্ট" আচরণ বাদে এই কৌশলটি কীভাবে ব্যবহার করে তা সম্পর্কে আমার কোনও ধারণা নেই (আপনার প্রতিপক্ষের বল + হাঁস রয়েছে তার চেয়ে বেশি বল থাকলে স্নোবল নিক্ষেপ করুন এবং আপনি উভয়ই বাইরে থাকলে পুনরায় লোড করুন) স্নোবলস এর)। কেউ যদি এটি তৈরি করে ডেটাসেট বিশ্লেষণ করতে চায় তবে আমি ভাবতে পারি যে কিছু আকর্ষণীয় আচরণ আবিষ্কার করার আছে!

"সেভ ওয়ান" এর বিরুদ্ধে এটি পরীক্ষা করে দেখা যায় যে এটি সত্যই দীর্ঘমেয়াদে জিততে পারে তবে কেবলমাত্র একটি সামান্য ব্যবধানে (514 জয়, 486 হেরে, 1000 গেমের প্রথম ব্যাচে 0 ড্র, এবং 509 জয়, 491 লোকসান, 0 দ্বিতীয়টি আঁকায়)।


গুরুত্বপূর্ণ!

এটি বাক্সের বাইরে কাজ করবে, তবে এটি দুর্দান্ত ধারণা নয়। পুরো গেম ট্রিটি তৈরি করতে আমার মাঝারি-বিকাশকারী-নির্দিষ্ট ল্যাপটপে প্রায় 9 মিনিট সময় লাগে। তবে এটি চূড়ান্ত সম্ভাব্যতাগুলি একবার উত্পন্ন হওয়ার পরে একটি ফাইলে সংরক্ষণ করবে এবং তার পরে প্রতিটি পালা কেবল একটি এলোমেলো সংখ্যা তৈরি করবে এবং এটি 2 বাইটের সাথে তুলনা করবে, সুতরাং এটি অতি দ্রুত।

এই সমস্ত শর্টকাট করতে, কেবল এই ফাইলটি (3.5MB) ডাউনলোড করুন এবং এক্সিকিউটেবলের সাথে ডিরেক্টরিতে রেখে দিন।

অথবা আপনি এটি চালিয়ে নিজে তৈরি করতে পারেন:

./pain_in_the_nash 1000 50 25

যা রূপান্তরিত না হওয়া অবধি প্রতি এক ফাইলের সংরক্ষণ করবে। মনে রাখবেন যে প্রতিটি ফাইল 3.5MB এবং এটি 720 টি (অর্থাত্ 280 ফাইল, ~ 1 গিগাবাইট) এ রূপান্তর করবে এবং যেহেতু বেশিরভাগ গেমস 720 এর পরিবর্তে কোথাও পায় না, প্রাক-রূপান্তরকারী ফাইলগুলির খুব কম গুরুত্ব থাকে।


প্রোগ্রামটি কেবলমাত্র চূড়ান্ত ফলাফল আউটপুট করা সম্ভব? ধন্যবাদ!
হাইপার নিউট্রিনো

@ হাইপার নিউট্রিনো অন্য সমস্ত আউটপুট স্ট্যাডার করার উচিত, তাই এর কোনও প্রভাব দেখা উচিত নয়, তবে প্রিপ্রসেসিং মোডে চলার সময় কেবল অগ্রগতি দেখানোর জন্য আমি এটি আপডেট করেছি। এটি এখন কেবল স্টাডাউটকে লিখবে যখন স্বাভাবিকভাবে চলমান। আমি যদিও "গুরুত্বপূর্ণ" পরামর্শটি অনুসরণ করার পরামর্শ দিই, যেহেতু নাহলে এটি প্রথম বারে কয়েক মিনিটের জন্য স্থির থাকবে (অন্তত প্রিপ্রোসেসিং দিয়ে আপনি অগ্রগতিটি দেখতে পাবে)।
ডেভ

ওহ ঠিক আছে. আমি সেই পরামর্শটি অনুসরণ করব, ধন্যবাদ!
হাইপারনিউট্রিনো

আপনি যদি ডেটা ফাইলগুলি আপলোড করতে পারেন তবে আমি এটির প্রশংসা করব কারণ সেগুলি উত্পন্ন করার জন্য এটি চিরকালের জন্য নিচ্ছে। আপনি যদি এটি করতে পারতেন তবে তা দুর্দান্ত হত :)
হাইপারনিউটারিনো

@ হাইপারনিউট্রিনো ঠিক আছে, আমার ভয়ঙ্কর ইন্টারনেটে আপলোড করতে চিরতরে সময় লেগেছিল, তবে 3.5MB রূপান্তরিত ফাইলটি এখানে পাওয়া যায়: github.com/davidje13/snowball_koth_pitn/blob/master/… (কেবল এটি একই ডিরেক্টরিতে রেখে দিন)।
ডেভ

1

সুইফ্ট - TheCrazy_XcodeRandomness

দুঃখের বিষয়, এটি কেবলমাত্র স্থানীয়ভাবে চালানো যেতে পারে, এক্সকোডে, কারণ এটিতে Foundationমডিউল এবং এর কার্যকারিতা রয়েছে arc4random_uniform()। তবে অ্যালগরিদম কী তা আপনি বেশ কিছু বলতে পারবেন:

import Foundation

func game(turn: Int, snowballs: Int, opponent_snowballs: Int, ducks: Int, opponent_ducks: Int, max_snowballs: Int) -> Int{
    let RELOAD = 0
    let THROW = 1
    let DUCK = 2
    if turn == 0{
        return arc4random_uniform(2)==0 ? THROW : DUCK
    }
    else if ducks == 0{
        if snowballs != 0{return THROW}
        else {return RELOAD}
    }
    else if snowballs < max_snowballs && snowballs != 0{
        if opponent_ducks == 0 && opponent_snowballs == 0{return THROW}
        else if opponent_snowballs == 0{
            return arc4random_uniform(2)==0 ? THROW : RELOAD
        }
        else if opponent_ducks == 0{return THROW}
        else { return arc4random_uniform(2)==0 ? THROW : RELOAD }
    }
    else if opponent_snowballs == max_snowballs{
        return DUCK
    }
    else if snowballs == max_snowballs || opponent_ducks < 1 || turn < max_snowballs{return THROW}
    return arc4random_uniform(2)==0 ? THROW : RELOAD
}

এটি কি লিনাক্সে বাশ থেকে চালানো যায়?
হাইপারনিউটারিনো

@ হাইপারনিউট্রিনো আমি জানি এটি ম্যাকোস-এ পারে, তবে আমি জানি না এটি লিনাক্সে রয়েছে কিনা। আপনি যদি এটি যাচাই করতে পারেন, এটি দুর্দান্ত। ব্যবহার করে দেখুন swiftকমান্ড এবং তারপর পরীক্ষা যদি এটি কাজ করে
জনাব Xcoder

এটি উপস্থিত নেই বলে মনে হয়; এটির সাথে একটি প্যাকেজ রয়েছে তবে এটি ভাষাটি দ্রুত নয়। সুতরাং আমি কিছু পরীক্ষা না করা পর্যন্ত এটি পরীক্ষা নাও করতে পারি, দুঃখিত।
হাইপারনিউটারিনো

কেবলমাত্র সম্ভাব্য প্রশংসক হলেন এক্সকোড এবং ইন্টেলিজ, তবে এটি অনলাইনে চালানো যায় না Foundation, দুঃখিত: /
মিঃ এক্সকোডার

চেরা। এটির সাথে কন্ট্রোলার চালানোর জন্য আমার এটি কমান্ড লাইন থেকে চালাতে সক্ষম হতে হবে তবে আমার যদি সময় থাকে তবে আমি নিজেই এটি অন্য সমস্ত বটগুলিতে আবার চালাতে পারি।
হাইপারনিউটারিনো

1

টেবিলবট, পাইথন 2

টেবিলবট নামে পরিচিত কারণ এটি এই টেবিলটি প্রয়োগ করে তৈরি করা হয়েছিল:

snow   duck   osnow   oduck   move
0      0      0       0       0
0      0      0       1       0
0      0      1       0       0
0      0      1       1       0
0      1      0       0       0
0      1      0       1       0
0      1      1       0       2
0      1      1       1       2
1      0      0       0       1
1      0      0       1       1
1      0      1       0       1
1      0      1       1       1
1      1      0       0       1
1      1      0       1       1
1      1      1       0       1
1      1      1       1       1

A 1 টি 1 বা তার বেশি থাকার প্রতিনিধিত্ব করে, 0 0 এর কোনওটি না থাকার প্রতিনিধিত্ব করে।

বট:

import sys

reload=0
throw=1
duck=2

t,snowballs,o_snowballs,ducks,o_ducks,m=map(int,sys.argv[1:])

if snowballs > 0:
	print throw
elif ducks==0:
	print reload
elif o_snowballs==0:
	print reload
else:
	print duck

এটি অনলাইন চেষ্টা করুন!


1

অ্যামবোট - র‌্যাকেট স্কিম

আমি বেশিরভাগ ব্যবহার করে চেষ্টা করে দেখতে চেয়েছিলাম amb, কারণ এটি দুর্দান্ত। এই বটটি এলোমেলোভাবে অপশনগুলি (পুনরায় লোড, নিক্ষেপ এবং হাঁস) অর্ডার করে, যেগুলি বোঝায় না সেগুলি ফিল্টার করে এবং প্রথম বিকল্পটি বেছে নেয়। তবে এর সাথে amb, আমরা ধারাবাহিকতা এবং ব্যাকট্র্যাকিং ব্যবহার করতে পারি!

#lang racket
(require racket/cmdline)

; Defining amb.
(define failures null)

(define (fail)
  (if (pair? failures) ((first failures)) (error "no more choices!")))

(define (amb/thunks choices)
  (let/cc k (set! failures (cons k failures)))
  (if (pair? choices)
    (let ([choice (first choices)]) (set! choices (rest choices)) (choice))
    (begin (set! failures (rest failures)) (fail))))

(define-syntax-rule (amb E ...) (amb/thunks (list (lambda () E) ...)))

(define (assert condition) (unless condition (fail)))

(define (!= a b)
  (not (= a b)))

(define (amb-list list)
  (if (null? list)
      (amb)
      (amb (car list)
           (amb-list (cdr list)))))

; The meaningful code!
; Start by defining our options.
(define reload 0)
(define throw 1)
(define duck 2)

; The heart of the program.
(define (make-choice turn snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (let ((can-reload? (reload-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs))
        (can-throw? (throw-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs))
        (can-duck? (duck-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs)))
    (if (not (or can-reload? can-throw? can-duck?))
        (random 3) ; something went wrong, panic
        (let* ((ls (shuffle (list reload throw duck)))
               (action (amb-list ls)))
          (assert (or (!= action reload) can-reload?))
          (assert (or (!= action throw) can-throw?))
          (assert (or (!= action duck) can-duck?))
          action))))

; Define what makes a move possible.
(define (reload-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (not (or
        (= snowballs max_snowballs) ; Don't reload if we're full.
        (and (= opponent_ducks 0) (= opponent_snowballs max_snowballs)) ; Don't reload if opponent will throw.
        )))

(define (throw-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (not (or
        (= snowballs 0) ; Don't throw if we don't have any snowballs.
        (= opponent_snowballs max_snowballs) ; Don't throw if our opponent won't be reloading.
        )))

(define (duck-valid? snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (not (or
        (= ducks 0) ; Don't duck if we can't.
        (= opponent_snowballs 0) ; Don't duck if our opponent can't throw.
        )))

; Parse the command line, make a choice, print it out.
(command-line
 #:args (turn snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
 (writeln (make-choice
           (string->number turn)
           (string->number snowballs)
           (string->number opponent_snowballs)
           (string->number ducks)
           (string->number opponent_ducks)
           (string->number max_snowballs))))

আমি একে অপরের বিরুদ্ধে এই দুটি বট চালানোর জন্য একটি ছোট পরীক্ষার প্রোগ্রামও করেছিলাম। এটি মনে হয় দ্বিতীয় বটটি প্রায়শই জয়ী হয় তাই আমি কোথাও ভুল করে থাকতে পারি।

(define (run)
  (run-helper 0 0 0 5 5 5))                         

(define (run-helper turn snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (printf "~a ~a ~a ~a ~a ~a ~n" turn snowballs opponent_snowballs ducks opponent_ducks max_snowballs)
  (let ((my-action (make-choice turn snowballs opponent_snowballs ducks opponent_ducks max_snowballs))
        (opponent-action (make-choice turn opponent_snowballs snowballs opponent_ducks ducks max_snowballs)))
    (cond ((= my-action reload)
           (cond ((= opponent-action reload)
                  (run-helper (+ turn 1) (+ snowballs 1) (+ opponent_snowballs 1) ducks opponent_ducks max_snowballs))
                 ((= opponent-action throw)
                  (writeln "Opponent wins!"))
                 ((= opponent-action duck)
                  (run-helper (+ turn 1) (+ snowballs 1) opponent_snowballs ducks (- opponent_ducks 1) max_snowballs))))
          ((= my-action throw)
           (cond ((= opponent-action reload)
                  (writeln "I win!"))
                 ((= opponent-action throw)
                  (run-helper (+ turn 1) (- snowballs 1) (- opponent_snowballs 1) ducks opponent_ducks max_snowballs))
                 ((= opponent-action duck)
                  (run-helper (+ turn 1) (- snowballs 1) opponent_snowballs ducks (- opponent_ducks 1) max_snowballs))))
          ((= my-action duck)
           (cond ((= opponent-action reload)
                  (run-helper (+ turn 1) snowballs (+ opponent_snowballs 1) (- ducks 1) opponent_ducks max_snowballs))
                 ((= opponent-action throw)
                  (run-helper (+ turn 1) snowballs (- opponent_snowballs 1) (- ducks 1) opponent_ducks max_snowballs))
                 ((= opponent-action duck)
                  (run-helper (+ turn 1) snowballs opponent_snowballs (- ducks 1) (- opponent_ducks 1) max_snowballs)))))))

1

মন্টিবট, সি ++

আমি এই কোথ থেকে মূলত কোডটি নিয়েছি এবং এই চ্যালেঞ্জের জন্য এটি সংশোধন করেছি। এটি ডিকোপলড ইউসিটি মন্টি কার্লো ট্রি ট্রি অনুসন্ধান অ্যালগরিদম ব্যবহার করে। এটি ন্যাশ ভারসাম্যের খুব কাছাকাছি হওয়া উচিত।

#include <cstdlib>
#include <cmath>
#include <random>
#include <cassert>
#include <iostream>


static const int TOTAL_ACTIONS = 3;
static const int RELOAD = 0;
static const int THROW = 1;
static const int DUCK = 2;

//The number of simulated games we run every time our program is called.
static const int MONTE_ROUNDS = 10000;

struct Game
{
    int turn;
    int snowballs;
    int opponentSnowballs;
    int ducks;
    int opponentDucks;
    int maxSnowballs;
    bool alive;
    bool opponentAlive;

    Game(int turn, int snowballs, int opponentSnowballs, int ducks, int opponentDucks, int maxSnowballs)
        : turn(turn),
          snowballs(snowballs),
          opponentSnowballs(opponentSnowballs),
          ducks(ducks),
          opponentDucks(opponentDucks),
          maxSnowballs(maxSnowballs),
          alive(true),
          opponentAlive(true)
    {
    }

    Game(int turn, int snowballs, int opponentSnowballs, int ducks, int opponentDucks, int maxSnowballs, bool alive, bool opponentAlive)
        : turn(turn),
        snowballs(snowballs),
        opponentSnowballs(opponentSnowballs),
        ducks(ducks),
        opponentDucks(opponentDucks),
        maxSnowballs(maxSnowballs),
        alive(alive),
        opponentAlive(opponentAlive)
    {
    }

    bool atEnd() const
    {
        return !(alive && opponentAlive) || turn >= 1000;
    }

    bool isValidMove(int i, bool me)
    {
        if (atEnd())
        {
            return false;
        }

        switch (i)
        {
        case RELOAD:
            return (me ? snowballs : opponentSnowballs) < maxSnowballs;
        case THROW:
            return (me ? snowballs : opponentSnowballs) > 0;
        case DUCK:
            return (me ? ducks : opponentDucks) > 0 && (me ? opponentSnowballs : snowballs) > 0;
        default:
            throw "This should never be executed.";
        }

    }

    Game doTurn(int my_action, int enemy_action)
    {
        assert(isValidMove(my_action, true));
        assert(isValidMove(enemy_action, false));

        Game result(*this);

        result.turn++;

        switch (my_action)
        {
        case RELOAD:
            result.snowballs++;
            break;
        case THROW:
            result.snowballs--;
            if (enemy_action == RELOAD)
            {
                result.opponentAlive = false;
            }
            break;
        case DUCK:
            result.ducks--;
            break;
        default:
            throw "This should never be executed.";
        }

        switch (enemy_action)
        {
        case RELOAD:
            result.opponentSnowballs++;
            break;
        case THROW:
            result.opponentSnowballs--;
            if (my_action == RELOAD)
            {
                result.alive = false;
            }
            break;
        case DUCK:
            result.opponentDucks--;
            break;
        default:
            throw "This should never be executed.";
        }

        return result;
    }
};

struct Stat
{
    int wins;
    int attempts;

    Stat() : wins(0), attempts(0) {}
};

/**
* A Monte tree data structure.
*/
struct MonteTree
{
    //The state of the game.
    Game game;

    //myStats[i] returns the statistic for doing the i action in this state.
    Stat myStats[TOTAL_ACTIONS];
    //opponentStats[i] returns the statistic for the opponent doing the i action in this state.
    Stat opponentStats[TOTAL_ACTIONS];
    //Total number of times we've created statistics from this tree.
    int totalPlays = 0;

    //The action that led to this tree.
    int myAction;
    //The opponent action that led to this tree.
    int opponentAction;

    //The tree preceding this one.
    MonteTree *parent = nullptr;

    //subtrees[i][j] is the tree that would follow if I did action i and the
    //opponent did action j.
    MonteTree *subtrees[TOTAL_ACTIONS][TOTAL_ACTIONS] = { { nullptr } };

    MonteTree(const Game &game) :
        game(game), myAction(-1), opponentAction(-1) {}


    MonteTree(Game game, MonteTree *parent, int myAction, int opponentAction) :
        game(game), myAction(myAction), opponentAction(opponentAction), parent(parent)
    {
        //Make sure the parent tree keeps track of this tree.
        parent->subtrees[myAction][opponentAction] = this;
    }

    //The destructor so we can avoid slow ptr types and memory leaks.
    ~MonteTree()
    {
        //Delete all subtrees.
        for (int i = 0; i < TOTAL_ACTIONS; i++)
        {
            for (int j = 0; j < TOTAL_ACTIONS; j++)
            {
                auto branch = subtrees[i][j];

                if (branch)
                {
                    branch->parent = nullptr;
                    delete branch;
                }
            }
        }
    }

    double scoreMove(int move, bool me)
    {

        const Stat &stat = me ? myStats[move] : opponentStats[move];
        return stat.attempts == 0 ?
            HUGE_VAL :
            double(stat.wins) / stat.attempts + sqrt(2 * log(totalPlays) / stat.attempts);
    }


    MonteTree * expand(int myAction, int enemyAction)
    {
        return new MonteTree(
            game.doTurn(myAction, enemyAction),
            this,
            myAction,
            enemyAction);
    }

    int bestMove() const
    {
        //Select the move with the highest win rate.
        int best;
        double bestScore = -1;
        for (int i = 0; i < TOTAL_ACTIONS; i++)
        {
            if (myStats[i].attempts == 0)
            {
                continue;
            }

            double score = double(myStats[i].wins) / myStats[i].attempts;
            if (score > bestScore)
            {
                bestScore = score;
                best = i;
            }
        }

        return best;
    }
};

int random(int min, int max)
{
    static std::random_device rd;
    static std::mt19937 rng(rd());

    std::uniform_int_distribution<int> uni(min, max - 1);

    return uni(rng);
}

/**
* Trickle down root until we have to create a new leaf MonteTree or we hit the end of a game.
*/
MonteTree * selection(MonteTree *root)
{
    while (!root->game.atEnd())
    {
        //First pick the move that my bot will do.

        //The action my bot will do.
        int myAction;
        //The number of actions with the same bestScore.
        int same = 0;
        //The bestScore
        double bestScore = -1;

        for (int i = 0; i < TOTAL_ACTIONS; i++)
        {
            //Ignore invalid or idiot moves.
            if (!root->game.isValidMove(i, true))
            {
                continue;
            }

            //Get the score for doing move i. Uses
            double score = root->scoreMove(i, true);

            //Randomly select one score if multiple actions have the same score.
            //Why this works is boring to explain.
            if (score == bestScore)
            {
                same++;
                if (random(0, same) == 0)
                {
                    myAction = i;
                }
            }
            //Yay! We found a better action.
            else if (score > bestScore)
            {
                same = 1;
                myAction = i;
                bestScore = score;
            }
        }

        //The action the enemy will do.
        int enemyAction;

        //Use the same algorithm to pick the enemies move we use for ourselves.
        same = 0;
        bestScore = -1;
        for (int i = 0; i < TOTAL_ACTIONS; i++)
        {
            if (!root->game.isValidMove(i, false))
            {
                continue;
            }

            double score = root->scoreMove(i, false);
            if (score == bestScore)
            {
                same++;
                if (random(0, same) == 0)
                {
                    enemyAction = i;
                }
            }
            else if (score > bestScore)
            {
                same = 1;
                enemyAction = i;
                bestScore = score;
            }
        }

        //If this combination of actions hasn't been explored yet, create a new subtree to explore.
        if (!(*root).subtrees[myAction][enemyAction])
        {
            return root->expand(myAction, enemyAction);
        }

        //Do these actions and explore the next subtree.
        root = (*root).subtrees[myAction][enemyAction];
    }
    return root;
}

/**
* Chooses a random move for me and my opponent and does it.
*/
Game doRandomTurn(Game &game)
{
    //Select my random move.
    int myAction;
    int validMoves = 0;

    for (int i = 0; i < TOTAL_ACTIONS; i++)
    {
        //Don't do idiotic moves.
        //Select one at random.
        if (game.isValidMove(i, true))
        {
            validMoves++;
            if (random(0, validMoves) == 0)
            {
                myAction = i;
            }
        }
    }

    //Choose random opponent action.
    int opponentAction;

    //Whether the enemy has encountered this situation before
    bool enemyEncountered = false;

    validMoves = 0;

    //Weird algorithm that works and I don't want to explain.
    //What it does:
    //If the enemy has encountered this position before,
    //then it chooses a random action weighted by how often it did that action.
    //If they haven't, makes the enemy choose a random not idiot move.
    for (int i = 0; i < TOTAL_ACTIONS; i++)
    {
        if (game.isValidMove(i, false))
        {
            validMoves++;
            if (random(0, validMoves) == 0)
            {
                opponentAction = i;
            }
        }
    }

    return game.doTurn(myAction, opponentAction);
}


/**
* Randomly simulates the given game.
* Has me do random moves that are not stupid.
* Has opponent do random moves.
*
* Returns 1 for win. 0 for loss. -1 for draw.
*/
int simulate(Game game)
{
    while (!game.atEnd())
    {
        game = doRandomTurn(game);
    }

    if (game.alive > game.opponentAlive)
    {
        return 1;
    }
    else if (game.opponentAlive > game.alive)
    {
        return 0;
    }
    else //Draw
    {
        return -1;
    }
}


/**
* Propagates the score up the MonteTree from the leaf.
*/
void update(MonteTree *leaf, int score)
{
    while (true)
    {
        MonteTree *parent = leaf->parent;
        if (parent)
        {
            //-1 = draw, 1 = win for me, 0 = win for opponent
            if (score != -1)
            {
                parent->myStats[leaf->myAction].wins += score;
                parent->opponentStats[leaf->opponentAction].wins += 1 - score;
            }
            parent->myStats[leaf->myAction].attempts++;
            parent->opponentStats[leaf->opponentAction].attempts++;
            parent->totalPlays++;
            leaf = parent;
        }
        else
        {
            break;
        }
    }
}

int main(int argc, char* argv[])
{
    Game game(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6]));

    MonteTree current(game);

    for (int i = 0; i < MONTE_ROUNDS; i++)
    {
        //Go down the tree until we find a leaf we haven't visites yet.
        MonteTree *leaf = selection(&current);

        //Randomly simulate the game at the leaf and get the result.
        int score = simulate(leaf->game);

        //Propagate the scores back up the root.
        update(leaf, score);
    }

    int move = current.bestMove();

    std::cout << move << std::endl;

    return 0;
}

লিনাক্সের জন্য নির্দেশাবলী সংগ্রহ করুন:

সংরক্ষণ করুন MonteBot.cpp
চালান g++ -o -std=c++11 MonteBot MonteBot.cpp

কমান্ড চালানোর জন্য: ./MonteBot <args>


1

Procrastinator - পাইথন 3

প্রথম দম্পতি মোড়কে বাঁচিয়ে দেরি করতে হবে ator হঠাৎ আতঙ্কিত দৈত্যটি বিরোধীদের সর্বাধিক ব্যবহৃত পদক্ষেপের মোকাবিলা করে রিসোর্স ওয়ার হারানো এড়াতে চায়।

import sys

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

max_ducks = 25
times_opponent_ducked = max_ducks - ducks 
times_opponent_thrown = (turn - times_opponent_ducked - opponent_snowballs) / 2
times_opponent_reloaded = times_opponent_thrown + opponent_snowballs


## return a different action, if the disiered one is not possible
def throw():
    if snowballs:
        return 1
    else:
        return duck()

def duck():
    if ducks:
        return 2
    else:
        return reload()

def reload():
    return 0





def instant_gratification_monkey():
    ## throw, if you still have a ball left afterwards
    if snowballs >= 2 or opponent_ducks == 0:
        return throw()
    ## duck, if opponent can throw
    elif opponent_snowballs > 0:
        return duck()
    ## reload, if opponent has no balls and you have only one
    else:
        return reload()

def panic_monster():
    ## throw while possible, else reload
    if times_opponent_reloaded > times_opponent_ducked: 
        if snowballs > 0:
            return throw() 
        else:
            return reload()
    ## alternating reload and duck
    else: 
        if turn % 2 == 1:
            return reload() 
        else:
            return duck()

def procrastinator():     
    if turn < 13 or (snowballs + ducks > opponent_snowballs + opponent_ducks):
        return instant_gratification_monkey()
    else:
        return panic_monster()


print(procrastinator())

"দ্য বিলম্বকারী"। তো, পিপিসি-র প্রত্যেককেই আসলে বাড়ির কাজ করা বোঝানো হয়েছে? (এটি অস্বীকার করবেন না, যারা এটি পড়েছেন এবং আমি)
হাইপারনিউটারিনো

1
"তাত্ক্ষণিক সন্তুষ্টির বানর" আপনি কি টিইডিটালকে দেখেছেন? :)
হাইপারনিউট্রিনো


0

প্যারানয়েডবট এবং প্যানিকবট - অ্যাকশনস্ক্রিপ্ট 3 ( রেডটামারিন )

অযোগ্য, কুলুঙ্গি ভাষা থেকে (কমান্ড-লাইন আর্গুমেন্ট সরবরাহ করার জন্য এক্সটেনশন সহ) স্কিটিশ পারানয়েডবট এবং তার নিস্তেজ মিত্র প্যানিকবটকে বোঝায়।

ParanoidBot

পারানয়েডবট তার মন হারাচ্ছে এবং এর উপর নির্ভর করার জন্য অযথা নির্দিষ্ট কৌশল রয়েছে। প্রথমে কিছুটা রিজার্ভ রেখে একটি থ্রেশহোল্ড না আসা পর্যন্ত এটি স্নোবলগুলি চালু করে। তারপরে, তিনটি সাবধানী হাঁসের পরে, প্যারানোইয়া সেট আপ হয় এবং বট এলোমেলো হাঁসের মাঝে আরও বেশি স্নোবোল জমা করার চেষ্টা করে। এর সরবরাহ পুনরায় পূরণ করার পরে, প্যারানয়েডবট অন্ধভাবে ছুড়ে ফিরতে ফিরে আসে। মাথার ভয়েসগুলির কারণে, প্যারানয়েডবট এটি জিততে বা হারাতে দেওয়ার গ্যারান্টিযুক্ত কিনা তা বলতে পারে এবং সে অনুযায়ী "কৌশল অবলম্বন" করবে।

import shell.Program;
import shell;

var TURN:int = Program.argv[0];
var SB:int = Program.argv[1];
var OPSB:int = Program.argv[2];
var DC:int = Program.argv[3];
var OPDC:int = Program.argv[4];
var MAXSB:int = Program.argv[5];
var usedDucks:int = 0;

if (!FileSystem.exists("data"))
    FileSystem.write("data", 0);
else
    usedDucks = FileSystem.read("data");

if (SB > OPSB + OPDC)
{ trace(1); Program.abort(); }
if (SB + DC < OPSB) {
if (DC > 0)
    trace(2);
else if (SB > 0)
    trace(1);
else
    trace(0);
Program.abort(); }

if (usedDucks >= 3) {
    if (SB > MAXSB / 3) {
        usedDucks = 0;
        FileSystem.write("data", usedDucks);
        trace(1);
        Program.abort();
    }
    else {
        if (Number.random() > 0.5 && DC > 0)
            trace(2);
        else
            trace(0);
    }
}
else {
    if (SB > (MAXSB / 6) && SB >= 3)
    { trace(1); Program.abort(); }
    else {
        usedDucks++;
        FileSystem.write("data", usedDucks);
        if (DC > 0)
            trace(2);
        else if (SB > 0)
            trace(1);
        else
            trace(0);
        Program.abort();
    }
}

ধনুর্বন্ধনী ঘন আকারে সাহায্য করার জন্য কিছুটা দুর্বল

PanicBot

ইতিমধ্যে উন্মাদ হয়ে যাওয়ার পরে, প্যানিকবট সহজাত ভয় থেকে প্রতিক্রিয়া জানায়। ভয়ে কাঁচা থেকে হাঁস ছেড়ে পালিয়ে যাওয়ার পরে, প্যানিকবট তার সমস্ত স্নোবোলকে অন্ধভাবে ছুঁড়ে মারে, তারপরে (সম্ভবত) পরাজিত না হওয়া পর্যন্ত মরিয়া হয়ে আরও বেশি স্নোবোল নিক্ষেপ করে।

import shell.Program;

var SB:int = Program.argv[1];
var DC:int = Program.argv[3];

if (DC > 0)
{ trace(2); Program.abort(); }
if (SB > 0)
{ trace(1); Program.abort(); }
else
{ trace(0); Program.abort(); }



এটি পিপিসিজিতে AS3 ব্যবহার করে অন্য 15 টিরও কম এন্ট্রিগুলির মধ্যে একটি। একদিন, সম্ভবত এই তর্কযুক্ত বিদেশী ভাষা প্রাধান্য পেতে একটি ধাঁধা খুঁজে পাবে।


এটি কি লিনাক্সে বাশ থেকে চালানো যেতে পারে?
হাইপারনিউটারিনো

আমি এটি পরীক্ষা করিনি, তবে হ্যাঁ, এটি করা উচিত। রেডটামারিন এক্সিকিউটেবল (রেডশেল) উইন্ডোজ, ম্যাক এবং লিনাক্সের জন্য নির্মিত: http://redtamarin.com/tools/redshell । উপরের বটগুলির মধ্যে একটি যদি নামের একটি ফাইলে সংরক্ষণ করা হয় snow.asতবে নিম্নলিখিতটি $ ./redshell snow.as -- 0 50 50 25 25

এটি চালানোর চেষ্টা করার সময় এটি আমাকে অনুমতি অস্বীকার করার ত্রুটি দেয়।
হাইপারনিউটারিনো

@ হাইপারনিট্রিনো chmod +x redshellএখানে আপনার বন্ধু ...
এরিক দ্য আউটগোল্ফার

হয়তো chmod 777 সব? রেডটামারিন ওয়েবসাইটেও কিছু সমস্যা সমাধান হতে পারে

0

ডিফেন্ডার, পাইথন

কোনও খেলোয়াড়ের স্নোবোল না থাকলে পুনরায় লোড হয়। যদি এটিতে স্নোবল থাকে তবে তা ছুড়ে দেয়। যদি এটিতে স্নোবোল না থাকে তবে প্রতিপক্ষের কাছে তা হয়, যদি এটি সম্ভব হয় তবে তা হাঁস, অন্যথায় পুনরায় লোড হয়।

def get_move(turn, snowballs, opponent_snowballs, ducks, opponent_ducks, max_snowballs):
    if snowballs == opponent_snowballs == 0:
        return 0 #Reload
    elif snowballs > 0:
        return 1 # Throw
    elif ducks > 0:
        return 2 # Duck
    else:
        return 0 # Reload

if __name__ == "__main__": # if this is the main program
    import sys
    print(main(*[int(arg) for arg in sys.argv[1:]]))

দ্রষ্টব্য: এখনও পরীক্ষিত হয়নি

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.