সেরা যুদ্ধ এআই কি?


315

রণতরী!

2003 সালে ফিরে (যখন আমি 17 বছর), আমি একটি যুদ্ধ এআই কোডিং প্রতিযোগিতায় অংশ নিয়েছিলাম । যদিও আমি সেই টুর্নামেন্টটি হারিয়েছি, আমি অনেক মজা পেয়েছি এবং এটি থেকে অনেক কিছু শিখেছি।

এখন, আমি সেরা প্রতিযোগিতা এআইয়ের সন্ধানে এই প্রতিযোগিতাটি পুনরুত্থিত করতে চাই।

এখানে ফ্রেমওয়ার্কটি এখন বিটবকেটে হোস্ট করা হয়েছে

বিজয়ীকে +450 খ্যাতি দেওয়া হবে! প্রতিযোগিতাটি 17 নভেম্বর, 2009-এ শুরু হবে । 17 তারিখে শূন্য-ঘন্টা চেয়ে কোনও প্রবেশ বা সম্পাদনা গ্রহণ করা হবে না। (সেন্ট্রাল স্ট্যান্ডার্ড সময়) আপনার এন্ট্রিগুলি তাড়াতাড়ি জমা দিন, যাতে আপনি আপনার সুযোগটি মিস করেন না!

এই রাখার জন্য OBJECTIVE , প্রতিযোগিতার আত্মা অনুসরণ করুন।

খেলার নিয়ম:

  1. গেমটি 10x10 গ্রিডে খেলা হয়।
  2. প্রতিটি প্রতিযোগী তাদের গ্রিডে প্রতিটি 5 টি জাহাজ (দৈর্ঘ্যের 2, 3, 3, 4, 5) রাখবে।
  3. কোনও জাহাজ ওভারল্যাপ করতে পারে না, তবে সেগুলি সংলগ্ন হতে পারে।
  4. প্রতিযোগীরা তারপরে প্রতিপক্ষকে লক্ষ্য করে একক শট ফেরা করে।
    • গেমের একটি পার্থক্য প্রতিটি বেঁচে থাকা জাহাজের জন্য একটি করে ভল্লি প্রতি একাধিক শট ফায়ার করতে দেয়।
  5. শট ডুবে, আঘাত করে বা মিস করলে প্রতিপক্ষ প্রতিযোগীকে জানাবে।
  6. যে কোনও একটি খেলোয়াড়ের সমস্ত জাহাজ ডুবে গেলে গেম প্লে শেষ হয়।

প্রতিযোগিতার নিয়ম:

  1. প্রতিযোগিতার স্পিরিট সেরা ব্যাটলশিপ অ্যালগরিদম সন্ধান করা।
  2. প্রতিযোগিতার চেতনার বিরুদ্ধে বিবেচিত যে কোনও কিছুই অযোগ্যতার কারণ হবে be
  3. প্রতিপক্ষের সাথে হস্তক্ষেপ করা প্রতিযোগিতার চেতনার পরিপন্থী।
  4. মাল্টিথ্রেডিং নিম্নলিখিত বিধিনিষেধের অধীনে ব্যবহার করা যেতে পারে:
    • আপনার পালা না আসলে একের বেশি থ্রেড চলতে পারে না। (যদিও, যে কোনও সংখ্যক থ্রেড "স্থগিত" অবস্থায় থাকতে পারে)।
    • "নরমাল" ব্যতীত কোনও থ্রেড অগ্রাধিকারে চলতে পারে না।
    • উপরোক্ত দুটি বিধিনিষেধের ভিত্তিতে, আপনার পালা চলাকালীন আপনাকে কমপক্ষে 3 ডেডিকেটেড সিপিইউ কোরের গ্যারান্টি দেওয়া হবে।
  5. গেম প্রতি সিপিইউ সময়ের এক সেকেন্ডের সীমা প্রাথমিক থ্রেডে প্রতিটি প্রতিযোগীকে বরাদ্দ করা হয়।
  6. সময়ের বাইরে চলে যাওয়ার ফলে বর্তমান গেমটি হারাতে পারে।
  7. যেকোনো আনহ্যান্ডেল ব্যতিক্রমের ফলে বর্তমান গেমটি হারাতে হবে।
  8. নেটওয়ার্ক অ্যাক্সেস এবং ডিস্ক অ্যাক্সেস অনুমোদিত, কিন্তু আপনি সময় সীমাবদ্ধতা মোটামুটি নিষিদ্ধ দেখতে পাবেন। তবে সময়ের চাপ কমাতে কয়েকটি সেট আপ এবং টিয়ার-ডাউন পদ্ধতি যুক্ত করা হয়েছে।
  9. কোডটি উত্তর হিসাবে স্ট্যাকের ওভারফ্লোতে পোস্ট করা উচিত, বা, যদি খুব বড় হয় তবে লিঙ্কযুক্ত।
  10. একটি এন্ট্রি সর্বাধিক মোট আকার (সঙ্কুচিত) 1 এমবি হয়।
  11. আনুষ্ঠানিকভাবে। নেট 2.0 / 3.5 শুধুমাত্র ফ্রেমওয়ার্কের প্রয়োজন।
  12. আপনার প্রবেশের জন্য অবশ্যই আইব্যাটলশিপঅপোনাল্ট ইন্টারফেস প্রয়োগ করা উচিত।

স্কোরিং:

  1. 101 গেমগুলির মধ্যে সেরা 51 গেম একটি ম্যাচের বিজয়ী।
  2. সমস্ত প্রতিযোগী একে অপরের বিরুদ্ধে ম্যাচ খেলবে, রাউন্ড-রবিন স্টাইল।
  3. প্রতিযোগীদের সেরা অর্ধেকটি তারপরে বিজয়ী নির্ধারণের জন্য একটি ডাবল-এলিমিনেশন টুর্নামেন্ট খেলবে। (দু'জনের ক্ষুদ্রতম শক্তি যা অর্ধের চেয়ে বড় বা সমান, আসলে is)
  4. আমি টুর্নামেন্টের জন্য টুর্নামেন্ট এপি কাঠামোটি ব্যবহার করব ।
  5. ফলাফল এখানে পোস্ট করা হবে।
  6. যদি আপনি একাধিক এন্ট্রি জমা দেন তবে কেবলমাত্র আপনার সেরা-স্কোরিং এন্ট্রি ডাবল-এলমের জন্য যোগ্য eligible

শুভকামনা! আনন্দ কর!


সম্পাদনা 1: ফ্রিডকে
ধন্যবাদ , যিনি ফাংশনে একটি ত্রুটি পেয়েছেন । এটা ঠিক করা হয়েছে। ফ্রেমওয়ার্কটির আপডেট সংস্করণটি ডাউনলোড করুন।Ship.IsValid

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

সম্পাদনা 3:
বাগ ফিক্স 1: GameWonএবং GameLostকেবল সময়ের বাইরে যাওয়ার জন্য ফোন করা হয়েছিল।
বাগ ফিক্স 2: কোনও ইঞ্জিন প্রতিটি গেমের সময় নির্ধারণ করে দিলে প্রতিযোগিতাটি কখনও শেষ হবে না।
ফ্রেমওয়ার্কটির আপডেট সংস্করণটি ডাউনলোড করুন।

সম্পাদনা 4:
টুর্নামেন্টের ফলাফল:


যদি এন্ট্রিটির জন্য একটি বৃহত ডাটাবেস প্রয়োজন, এটি কি নেট থেকে এটি সংযোগ করতে পারে? অর্থাৎ। এন্ট্রি কি ওয়েব পরিষেবা কল করতে পারে?
রিমাস রুসানু

এন্ট্রিগুলিতে একটি আকার সীমা আছে?
ঝেরিকো

8
@ স্টিভেন: এছাড়াও, আমি জেফ অ্যাটউডের সাথে পরামর্শ করেছিলাম এটি উপযুক্ত কিনা তা দেখার জন্য। এখানে তার প্রতিক্রিয়া: twitter.com/codinghorror/status/5203185621
জন গীটজেন

1
এছাড়াও আমি তাহাত যোগ করব, এই 50 টি গেমের অনিবার্য র্যান্ডম উপাদান দেওয়া খুব ভাল বাস্তবায়নের মধ্যে সঠিকভাবে পার্থক্য করার পক্ষে যথেষ্ট নয়। আমি ভাবব যে 501 বা তার বেশি এর পক্ষে যুক্তিসঙ্গত দৃষ্টিভঙ্গির জন্য আরও বেশি প্রয়োজন যা আরও ভাল।
ShuggyCoUk

1
একটি "শান্তিপূর্ণ" প্রতিপক্ষ যা জাহাজ স্থাপন করতে অস্বীকার করে প্রতিযোগিতাটি স্তব্ধ করে দেয়। লোকেরা এর মতো নির্বোধ কাজ করার বিষয়ে আপনি কতটা যত্নবান তা নিশ্চিত নন। :)
জো

উত্তর:


56

আমি প্রতি ম্যাচে আরও অনেক গেম করার গতি দ্বিতীয় করে। 50 টি গেম করা কেবল একটি মুদ্রা উল্টানো। পরীক্ষার অ্যালগোরিদমের মধ্যে কোনও যুক্তিসঙ্গত পার্থক্য পেতে আমার 1000 গেমগুলি করা দরকার।

ভয়ঙ্কর 1.2 ডাউনলোড করুন ।

কৌশলের:

  • > ০ টি হিট রয়েছে এমন জাহাজগুলির জন্য সমস্ত সম্ভাব্য অবস্থানের উপর নজর রাখুন। তালিকাটি কখনই ~ 30K এর চেয়ে বড় হয় না তাই এটি সমস্ত জাহাজের জন্য সম্ভাব্য পজিশনের তালিকার বিপরীতে (যা খুব বড়) সঠিকভাবে রাখা যায়।

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

  • এলোমেলো শটগুলির জন্য, লোকেশনকে ওভারল্যাপ করে থাকা যেকোনো অপ্রয়োজনীয় জাহাজের সম্ভাবনার উপর ভিত্তি করে অঙ্কুরের জন্য সেরা অবস্থানের অঙ্কন করুন।

  • অভিযোজিত অ্যালগরিদম যা বিরোধী স্থানে আঘাতের সম্ভাবনা কম এমন স্থানে জাহাজ রাখে।

  • অভিযোজিত অ্যালগরিদম যা প্রতিপক্ষের কাছে তার জাহাজগুলি রাখার সম্ভাবনা বেশি এমন স্থানে গুলি করতে পছন্দ করে।

  • জাহাজগুলি বেশিরভাগ একে অপরের সাথে স্পর্শ করে না place


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

আকর্ষণীয় ... এটি টুর্নামেন্টের মেশিনে দুর্দান্ত চলছে। যাইহোক, একটি "নিখুঁত" ইঞ্জিন এটি ইতিমধ্যে ব্যয় করা অনেক বেশি সময়ের সাথে মানিয়ে নেবে।
জন গীটজেন

35

এখানে আমার প্রবেশ! (সর্বাধিক নিষ্পাপ সমাধান)

"এলোমেলো 1.1"

namespace Battleship
{
    using System;
    using System.Collections.ObjectModel;
    using System.Drawing;

    public class RandomOpponent : IBattleshipOpponent
    {
        public string Name { get { return "Random"; } }
        public Version Version { get { return this.version; } }

        Random rand = new Random();
        Version version = new Version(1, 1);
        Size gameSize;

        public void NewGame(Size size, TimeSpan timeSpan)
        {
            this.gameSize = size;
        }

        public void PlaceShips(ReadOnlyCollection<Ship> ships)
        {
            foreach (Ship s in ships)
            {
                s.Place(
                    new Point(
                        rand.Next(this.gameSize.Width),
                        rand.Next(this.gameSize.Height)),
                    (ShipOrientation)rand.Next(2));
            }
        }

        public Point GetShot()
        {
            return new Point(
                rand.Next(this.gameSize.Width),
                rand.Next(this.gameSize.Height));
        }

        public void NewMatch(string opponent) { }
        public void OpponentShot(Point shot) { }
        public void ShotHit(Point shot, bool sunk) { }
        public void ShotMiss(Point shot) { }
        public void GameWon() { }
        public void GameLost() { }
        public void MatchOver() { }
    }
}

52
আসলে, এই উত্তরটি দুর্দান্ত কারণ এটি
এপিআই'র

1
ফিরে যখন আমি আমার কলেজ অ্যালগরিদম ক্লাসে একটি অনুরূপ প্রকল্প তৈরি করলাম তখন আমি কিছু সিদ্ধান্ত নেওয়ার সাথে এলোমেলো যুক্তি ব্যবহার করতাম। মাঝে মাঝে ভাল লাগতো!
নাথন টেলর

2
এটি কি ওভারল্যাপিং জাহাজগুলি রাখার চেষ্টা করতে পারে?

6
হ্যাঁ, তবে ইঞ্জিন এটিকে অস্বীকার করবে। এটি তখন এআইকে তাদের আবার রাখার জন্য বলবে, তবে এবার আরও কড়া কণ্ঠে with ( pop ax \ cmp ax, 1 \ je stern
দেখেছে

5
গুরুত্বপূর্ণ নোট ফোরানোইন যারা, আমার মতো তারাও দেখেছিল যে তারা সহজেই পূর্ববর্তী স্থানে রাখা শটগুলি স্মরণ করে এবং পুনরাবৃত্তি না করে এটিকে পরাস্ত করতে পারে। ফ্রেমওয়ার্কটি পুনরাবৃত্তিগুলি উপেক্ষা করবে এবং আপনার মোট সময় সীমাটির চেয়ে কম হওয়ায় আপনাকে আর একটি সুযোগ দেবে। এটি আমার মতে দরিদ্র, যদি কেউ তাদের আলগোষ্ঠী ভুল করে তবে তাদের শাস্তি দেওয়া উচিত ...
ShuggyCoUk

22

লোকদের বিরুদ্ধে খেলতে এখানে একটি প্রতিপক্ষ রয়েছে:

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

এই কাজটি করার জন্য, আপনি জাহাজগুলির সমস্ত সম্ভাব্য কনফিগারেশনগুলি সন্ধান করতে চান যা আপনার বর্তমান বিশ্বের দৃষ্টিভঙ্গির সাথে মানিয়ে যায় এবং তারপরে এই কনফিগারেশনের উপর ভিত্তি করে সম্ভাবনার গণনা করুন। আপনি এটি একটি গাছ অন্বেষণ মত ভাবতে পারেন:

সম্ভাব্য যুদ্ধক্ষেত্রের সম্প্রসারণে বলা হয়েছে http://natekohl.net/media/battleship-tree.png

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

এটি তাপের মানচিত্র হিসাবে ভিজ্যুয়ালাইজ করা যেতে পারে, যেখানে গরম দাগগুলি জাহাজগুলি রাখার সম্ভাবনা বেশি:

প্রতিটি অনাবিষ্কৃত অবস্থার জন্য সম্ভাবনার উত্তাপের মানচিত্র http://natekohl.net/media/battleship-probs.png

এই ব্যাটলশিপ প্রতিযোগিতা সম্পর্কে আমি একটি জিনিস পছন্দ করি যে উপরের গাছটি এই ধরণের অ্যালগরিদমকে হিংস্র-জোর করতে যথেষ্ট ছোট small 5 টি জাহাজের প্রতিটির জন্য যদি 150 ডলার সম্ভাব্য অবস্থান থাকে তবে তা 150 5 = 75 বিলিয়ন সম্ভাবনা রয়েছে। এবং এই সংখ্যাটি কেবলমাত্র ছোট হবে, বিশেষত যদি আপনি পুরো জাহাজগুলি মুছে ফেলতে পারেন।

আমি উপরে যে প্রতিপক্ষকে সংযুক্ত করেছি তারা পুরো গাছটি অন্বেষণ করে না; 75 সেকেন্ডের অধীনে যেতে 75 বিলিয়ন এখনও বড়। এটি কয়েকটি হিউরিস্টিকের সাহায্যে এই সম্ভাব্যতাগুলি অনুমান করার চেষ্টা করে।


এখনও অবধি, আপনি আমাদের একমাত্র অন্যান্য সম্পূর্ণ সমাধানটি প্রায় 67.7% থেকে 32.3% :) এর কাছে পরাজিত করছেন
জন গিয়েজেন

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

12

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

বোর্ডভিউ আপনাকে কোনও এনোটোটেড বোর্ডের সাথে সহজেই কাজ করতে দেয়।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;

namespace Battleship.ShuggyCoUk
{
    public enum Compass
    {
        North,East,South,West
    }

    class Cell<T>
    {
        private readonly BoardView<T> view;
        public readonly int X;
        public readonly int Y;
        public T Data;
        public double Bias { get; set; }

        public Cell(BoardView<T> view, int x, int y) 
        { 
            this.view = view; this.X = x; this.Y = y; this.Bias = 1.0;  
        }

        public Point Location
        {
            get { return new Point(X, Y); }
        }

        public IEnumerable<U> FoldAll<U>(U acc, Func<Cell<T>, U, U> trip)
        {
            return new[] { Compass.North, Compass.East, Compass.South, Compass.West }
                .Select(x => FoldLine(x, acc, trip));
        }

        public U FoldLine<U>(Compass direction, U acc, Func<Cell<T>, U, U> trip)
        {
            var cell = this;
            while (true)
            {
                switch (direction)
                {
                    case Compass.North:
                        cell = cell.North; break;
                    case Compass.East:
                        cell = cell.East; break;
                    case Compass.South:
                        cell = cell.South; break;
                    case Compass.West:
                        cell = cell.West; break;
                }
                if (cell == null)
                    return acc;
                acc = trip(cell, acc);
            }
        }

        public Cell<T> North
        {
            get { return view.SafeLookup(X, Y - 1); }
        }

        public Cell<T> South
        {
            get { return view.SafeLookup(X, Y + 1); }
        }

        public Cell<T> East
        {
            get { return view.SafeLookup(X+1, Y); }
        }

        public Cell<T> West
        {
            get { return view.SafeLookup(X-1, Y); }
        }

        public IEnumerable<Cell<T>> Neighbours()
        {
            if (North != null)
                yield return North;
            if (South != null)
                yield return South;
            if (East != null)
                yield return East;
            if (West != null)
                yield return West;
        }
    }

    class BoardView<T>  : IEnumerable<Cell<T>>
    {
        public readonly Size Size;
        private readonly int Columns;
        private readonly int Rows;

        private Cell<T>[] history;

        public BoardView(Size size)
        {
            this.Size = size;
            Columns = size.Width;
            Rows = size.Height;
            this.history = new Cell<T>[Columns * Rows];
            for (int y = 0; y < Rows; y++)
            {
                for (int x = 0; x < Rows; x++)
                    history[x + y * Columns] = new Cell<T>(this, x, y);
            }
        }

        public T this[int x, int y]
        {
            get { return history[x + y * Columns].Data; }
            set { history[x + y * Columns].Data = value; }
        }

        public T this[Point p]
        {
            get { return history[SafeCalc(p.X, p.Y, true)].Data; }
            set { this.history[SafeCalc(p.X, p.Y, true)].Data = value; }
        }

        private int SafeCalc(int x, int y, bool throwIfIllegal)
        {
            if (x < 0 || y < 0 || x >= Columns || y >= Rows)
            {    if (throwIfIllegal)
                    throw new ArgumentOutOfRangeException("["+x+","+y+"]");
                 else
                    return -1;
            }
            return x + y * Columns;
        }

        public void Set(T data)
        {
            foreach (var cell in this.history)
                cell.Data = data;
        }

        public Cell<T> SafeLookup(int x, int y)
        {
            int index = SafeCalc(x, y, false);
            if (index < 0)
                return null;
            return history[index];
        }

        #region IEnumerable<Cell<T>> Members

        public IEnumerator<Cell<T>> GetEnumerator()
        {
            foreach (var cell in this.history)
                yield return cell;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public BoardView<U> Transform<U>(Func<T, U> transform)
        {
            var result = new BoardView<U>(new Size(Columns, Rows));
            for (int y = 0; y < Rows; y++)
            {
                for (int x = 0; x < Columns; x++)
                {
                    result[x,y] = transform(this[x, y]);
                }
            }
            return result;
        }

        public void WriteAsGrid(TextWriter w)
        {
            WriteAsGrid(w, "{0}");
        }

        public void WriteAsGrid(TextWriter w, string format)
        {
            WriteAsGrid(w, x => string.Format(format, x.Data));
        }

        public void WriteAsGrid(TextWriter w, Func<Cell<T>,string> perCell)
        {
            for (int y = 0; y < Rows; y++)
            {
                for (int x = 0; x < Columns; x++)
                {
                    if (x != 0)
                        w.Write(",");
                    w.Write(perCell(this.SafeLookup(x, y)));
                }
                w.WriteLine();
            }
        }

        #endregion
    }
}

কিছু এক্সটেনশান, এর কয়েকটি মূল কাঠামোর কার্যকারিতা ডুপ্লিকেট করে তবে সত্যই আপনার দ্বারা করা উচিত।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections.ObjectModel;

namespace Battleship.ShuggyCoUk
{
    public static class Extensions
    {        
        public static bool IsIn(this Point p, Size size)
        {
            return p.X >= 0 && p.Y >= 0 && p.X < size.Width && p.Y < size.Height;
        }

        public static bool IsLegal(this Ship ship,
            IEnumerable<Ship> ships, 
            Size board,
            Point location, 
            ShipOrientation direction)
        {
            var temp = new Ship(ship.Length);
            temp.Place(location, direction);
            if (!temp.GetAllLocations().All(p => p.IsIn(board)))
                return false;
            return ships.Where(s => s.IsPlaced).All(s => !s.ConflictsWith(temp));
        }

        public static bool IsTouching(this Point a, Point b)
        {
            return (a.X == b.X - 1 || a.X == b.X + 1) &&
                (a.Y == b.Y - 1 || a.Y == b.Y + 1);
        }

        public static bool IsTouching(this Ship ship,
            IEnumerable<Ship> ships,
            Point location,
            ShipOrientation direction)
        {
            var temp = new Ship(ship.Length);
            temp.Place(location, direction);
            var occupied = new HashSet<Point>(ships
                .Where(s => s.IsPlaced)
                .SelectMany(s => s.GetAllLocations()));
            if (temp.GetAllLocations().Any(p => occupied.Any(b => b.IsTouching(p))))
                return true;
            return false;
        }

        public static ReadOnlyCollection<Ship> MakeShips(params int[] lengths)
        {
            return new System.Collections.ObjectModel.ReadOnlyCollection<Ship>(
                lengths.Select(l => new Ship(l)).ToList());       
        }

        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Rand rand)
        {
            T[] elements = source.ToArray();
            // Note i > 0 to avoid final pointless iteration
            for (int i = elements.Length - 1; i > 0; i--)
            {
                // Swap element "i" with a random earlier element it (or itself)
                int swapIndex = rand.Next(i + 1);
                T tmp = elements[i];
                elements[i] = elements[swapIndex];
                elements[swapIndex] = tmp;
            }
            // Lazily yield (avoiding aliasing issues etc)
            foreach (T element in elements)
            {
                yield return element;
            }
        }

        public static T RandomOrDefault<T>(this IEnumerable<T> things, Rand rand)
        {
            int count = things.Count();
            if (count == 0)
                return default(T);
            return things.ElementAt(rand.Next(count));
        }
    }
}

এমন কিছু যা আমি প্রচুর ব্যবহার করে শেষ করি।

enum OpponentsBoardState
{
    Unknown = 0,
    Miss,
    MustBeEmpty,        
    Hit,
}

র্যান্ডোমাইজেশন। সুরক্ষিত তবে পরীক্ষামূলক, পরীক্ষার জন্য কার্যকর।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Battleship.ShuggyCoUk
{
    public class Rand
    {
        Random r;

        public Rand()
        {
            var rand = System.Security.Cryptography.RandomNumberGenerator.Create();
            byte[] b = new byte[4];
            rand.GetBytes(b);
            r = new Random(BitConverter.ToInt32(b, 0));
        }

        public int Next(int maxValue)
        {
            return r.Next(maxValue);
        }

        public double NextDouble(double maxValue)
        {
            return r.NextDouble() * maxValue;
        }

        public T Pick<T>(IEnumerable<T> things)
        {
            return things.ElementAt(Next(things.Count()));
        }

        public T PickBias<T>(Func<T, double> bias, IEnumerable<T> things)
        {
            double d = NextDouble(things.Sum(x => bias(x)));
            foreach (var x in things)
            {
                if (d < bias(x))
                    return x;
                d -= bias(x);                
            }
            throw new InvalidOperationException("fell off the end!");
        }
    }
}

10

একটি পূর্ণাঙ্গ অ্যালগরিদম লেখার জন্য আমার কাছে এখনই সময় নেই, তবে এখানে একটি চিন্তাভাবনা রয়েছে: আপনার প্রতিপক্ষ যদি এলোমেলোভাবে জাহাজ স্থাপন করে, তবে প্লেসমেন্টের সম্ভাবনাগুলি (5.5,5.5) কেন্দ্রে একটি সাধারণ বিতরণ হবে না? উদাহরণস্বরূপ, এক্স ডাইমেনশনে যুদ্ধের জন্য প্লেসমেন্টের সম্ভাবনা (5 ইউনিট দীর্ঘ) এখানে রয়েছে:

x    1 2 3 4 5  6  7 8 9 10
P(x) 2 4 6 8 10 10 8 6 4 2

একই গণনাগুলি y এর জন্য বৈধ হবে। অন্যান্য জাহাজগুলিতে বিতরণ খুব বেশি হবে না তবে আপনার সেরা অনুমানটি এখনও কেন্দ্র। এর পরে, গাণিতিক পদ্ধতিটি আস্তে আস্তে কেন্দ্রের বাইরে তির্যক (সম্ভবত গড় জাহাজের দৈর্ঘ্য সহ, 17/5) বিস্তৃত হবে। উদা:

...........
....x.x....
.....x.....
....x.x....
...........

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


হ্যাঁ, তারা অবশ্যই করত। আমার পুরানো ইঞ্জিন তার জন্য ক্ষতিপূরণ দিয়েছে।
জন গীটজেন

1
আমি যেখান থেকে এসেছি, আস্তে আস্তে কেন্দ্রের বাইরে তির্যকগুলি ছড়িয়ে দেওয়া প্রতারণা বলে মনে করা হয় ।
bzlm

যদি এটি প্রতারণা হিসাবে বিবেচিত হয় তবে খুব সহজ একটি পাল্টা প্রতিস্থাপন রয়েছে। X (y, y) এড়িয়ে চলুন যেখানে x = y। :)
Ine

5
আমি মনে করি তিনি কার্ড গণনা ইঙ্গিত করছিলেন? যা আমার মতে প্রতারণা করছে না।
জন গিয়েজেন 21

10

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

namespace Battleship
{
    using System;
    using System.Collections.ObjectModel;
    using System.Drawing;
    using System.Collections.Generic;
    using System.Linq;
    public class AgentSmith : IBattleshipOpponent
    {        
        public string Name { get { return "Agent Smith"; } }
        public Version Version { get { return this.version; } }
        private Random rand = new Random();
        private Version version = new Version(2, 1);
        private Size gameSize;
        private enum Direction { Up, Down, Left, Right }
        private int MissCount;
        private Point?[] EndPoints = new Point?[2];
        private LinkedList<Point> HitShots = new LinkedList<Point>();
        private LinkedList<Point> Shots = new LinkedList<Point>();
        private List<Point> PatternShots = new List<Point>();
        private Direction ShotDirection = Direction.Up;
        private void NullOutTarget()
        {
            EndPoints = new Point?[2];
            MissCount = 0;
        }
        private void SetupPattern()
        {
            for (int y = 0; y < gameSize.Height; y++)
                for (int x = 0; x < gameSize.Width; x++)
                    if ((x + y) % 2 == 0) PatternShots.Add(new Point(x, y));
        }
        private bool InvalidShot(Point p)
        {
            bool InvalidShot = (Shots.Where(s => s.X == p.X && s.Y == p.Y).Any());
            if (p.X < 0 | p.Y<0) InvalidShot = true;
            if (p.X >= gameSize.Width | p.Y >= gameSize.Height) InvalidShot = true;
            return InvalidShot;
        }
        private Point FireDirectedShot(Direction? direction, Point p)
        {
            ShotDirection = (Direction)direction;
            switch (ShotDirection)
            {
                case Direction.Up: p.Y--; break;
                case Direction.Down: p.Y++; break;
                case Direction.Left: p.X--; break;
                case Direction.Right: p.X++; break;
            }
            return p;
        }
        private Point FireAroundPoint(Point p)
        {
            if (!InvalidShot(FireDirectedShot(ShotDirection,p)))
                return FireDirectedShot(ShotDirection, p);
            Point testShot = FireDirectedShot(Direction.Left, p);
            if (InvalidShot(testShot)) { testShot = FireDirectedShot(Direction.Right, p); }
            if (InvalidShot(testShot)) { testShot = FireDirectedShot(Direction.Up, p); }
            if (InvalidShot(testShot)) { testShot = FireDirectedShot(Direction.Down, p); }
            return testShot;
        }
        private Point FireRandomShot()
        {
            Point p;
            do
            {
                if (PatternShots.Count > 0)
                    PatternShots.Remove(p = PatternShots[rand.Next(PatternShots.Count)]);
                else do
                    {
                        p = FireAroundPoint(HitShots.First());
                        if (InvalidShot(p)) HitShots.RemoveFirst();
                    } while (InvalidShot(p) & HitShots.Count > 0);
            }
            while (InvalidShot(p));
            return p;
        }
        private Point FireTargettedShot()
        {
            Point p;
            do
            {
                p = FireAroundPoint(new Point(EndPoints[1].Value.X, EndPoints[1].Value.Y));
                if (InvalidShot(p) & EndPoints[1] != EndPoints[0])
                    EndPoints[1] = EndPoints[0];
                else if (InvalidShot(p)) NullOutTarget();
            } while (InvalidShot(p) & EndPoints[1] != null);
            if (InvalidShot(p)) p = FireRandomShot();
            return p;
        }
        private void ResetVars()
        {
            Shots.Clear();
            HitShots.Clear();
            PatternShots.Clear();
            MissCount = 0;
        }
        public void NewGame(Size size, TimeSpan timeSpan)
        {
            gameSize = size;
            ResetVars();
            SetupPattern();
        }
        public void PlaceShips(ReadOnlyCollection<Ship> ships)
        {
            foreach (Ship s in ships)
                s.Place(new Point(rand.Next(this.gameSize.Width), rand.Next(this.gameSize.Height)), (ShipOrientation)rand.Next(2));
        }
        public Point GetShot()
        {
            if (EndPoints[1] != null) Shots.AddLast(FireTargettedShot());
            else Shots.AddLast(FireRandomShot());
            return Shots.Last();
        }
        public void ShotHit(Point shot, bool sunk)
        {            
            HitShots.AddLast(shot);
            MissCount = 0;
            EndPoints[1] = shot;
            if (EndPoints[0] == null) EndPoints[0] = shot;
            if (sunk) NullOutTarget();
        }
        public void ShotMiss(Point shot)
        {
            if (++MissCount == 6) NullOutTarget();
        }
        public void GameWon() { }
        public void GameLost() { }
        public void NewMatch(string opponent) { }
        public void OpponentShot(Point shot) { }
        public void MatchOver() { }
    }
}

এখানে নূন্যতম স্থান নিতে সামান্য ঘনীভূত এবং এখনও পঠনযোগ্য।


6

প্রতিযোগিতা ইঞ্জিন সম্পর্কে কিছু মন্তব্য:

নিউগাম পরামিতি:

যদি আইব্যাটলশিপঅপোনেন্ট :: নিউগেমটি প্রি-গেম সেটআপের জন্য তৈরি হয় এবং বোর্ডসাইজ নেয়, তবে এটি শিপস এবং তাদের নিজ নিজ আকারের একটি তালিকাও নেওয়া উচিত। ভেরিয়েবল শিপ কনফিগারেশনের অনুমতি না দিয়ে ভেরিয়েবল বোর্ড-আকারের অনুমতি দেওয়ার কোনও অর্থ নেই।

জাহাজগুলি সিল করা হয়েছে:

ক্লাস শিপ সিল করার কোনও কারণ আমি দেখছি না। অন্যান্য মৌলিক জিনিসের মধ্যে, আমি শিপদের একটি নাম রাখতে চাই, যাতে আমি ("আপনি আমার {0}", শিপ.নাম) এর মতো বার্তা আউটপুট করতে পারি ; । আমার মনেও অন্যান্য এক্সটেনশন রয়েছে, তাই আমি মনে করি শিপটি উত্তরাধিকারসূত্রে হওয়া উচিত।

সময় সীমা:

যদিও 1 সেকেন্ডের সময়সীমা কোনও টুর্নামেন্টের নিয়মের জন্য অর্থবোধ করে, এটি ডিবাগিংয়ের সাথে পুরোপুরি গণ্ডগোল করে। ব্যাটলশিপ প্রতিযোগিতার বিকাশ / ডিবাগিংয়ে সহায়তা করার জন্য সময় লঙ্ঘন উপেক্ষা করার জন্য একটি সহজ সেটিংস থাকা উচিত। সিস্টেমটি.ডায়াগনস্টিকস.প্রসেস :: ইউজারপ্রসেসরটাইম / প্রাইভেলিজড প্রসেসরটাইম / টোটালপ্রসেসরটাইম তদন্ত করার পরামর্শ দিচ্ছি যাতে সময় কত বেশি ব্যবহৃত হচ্ছে তার আরও নিখুঁত দৃশ্যের জন্য।

ডোবা জাহাজ:

আপনি যখন কোনও বিরোধী জাহাজ ডুবিয়েছেন তখন বর্তমান API আপনাকে অবহিত করে:

ShotHit(Point shot, bool sunk);

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

এটি বিশেষত সমালোচনামূলক যখন কোনও এআই একে অপরের বিপরীতে যে জাহাজগুলি চালিত করার চেষ্টা করে। আমি এতে একটি API পরিবর্তনের জন্য অনুরোধ করতে চাই:

ShotHit(Point shot, Ship ship);

যদি জাহাজটি অকার্যকর হয় তবে এর থেকে বোঝা যায় যে শটটি ডুবে যাওয়া শট ছিল এবং আপনি জানেন যে আপনি কোন জাহাজটি ডুবেছিলেন এবং কত দিন ছিল। যদি শটটি একটি ডুবন্ত শট ছিল, তবে শিপটি বাতিল, এবং আপনার আর কোনও তথ্য নেই।


আপনি যদি মনে করেন সময়টি আরও সঠিকভাবে করা যায় তবে দয়া করে কোড নমুনাগুলি পোস্ট করুন। আমি এখনই নিয়মগুলি খুব বেশি পরিবর্তন করতে চাই না।
জন গিয়েজেন

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

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

5
আমি সবসময় এটিকে একটি এল কনফিগারেশনে দুটি জাহাজ রাখার কৌশল হিসাবে বিবেচনা করেছিলাম যাতে আমার প্রতিপক্ষকে মনে হয় যে তারা যুদ্ধক্ষেত্র ডুবেছিল যখন বাস্তবে তারা ছিল না। কোন নৌকাটি ডুবে গেছে তা আপনাকে প্রকাশ করতে হবে এমন ছাপের মধ্যে আমি কখনই ছিলাম না।
জোশ স্মিটন

3
@ ডিজে: আমি মূল কলম এবং কাগজের নিয়ম মেনে চলছি। মনে রাখবেন যে হাসব্রো একটি খেলনা সংস্থা এবং এই গেমটি হাসব্রোর পূর্বে রয়েছে।
জন গীটজেন

5

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Collections.ObjectModel;

namespace Battleship.ShuggyCoUk
{
    public class Simple : IBattleshipOpponent
    {
        BoardView<OpponentsBoardState> opponentsBoard = new BoardView<OpponentsBoardState>(new Size(10,10));
        Rand rand = new Rand();
        int gridOddEven;
        Size size;

        public string Name { get { return "Simple"; } }

        public Version Version { get { return new Version(2, 1); }}

        public void NewMatch(string opponent) {}

        public void NewGame(System.Drawing.Size size, TimeSpan timeSpan)
        {
            this.size = size;
            this.opponentsBoard = new BoardView<OpponentsBoardState>(size);
            this.gridOddEven = rand.Pick(new[] { 0, 1 });
        }

        public void PlaceShips(System.Collections.ObjectModel.ReadOnlyCollection<Ship> ships)
        {
            BoardView<bool> board = new BoardView<bool>(size);
            var AllOrientations = new[] {
                ShipOrientation.Horizontal,
                ShipOrientation.Vertical };

            foreach (var ship in ships)
            {
                int avoidTouching = 3;
                while (!ship.IsPlaced)
                {
                    var l = rand.Pick(board.Select(c => c.Location));
                    var o = rand.Pick(AllOrientations);
                    if (ship.IsLegal(ships, size, l, o))
                    {
                        if (ship.IsTouching(ships, l, o)&& --avoidTouching > 0)
                            continue;
                        ship.Place(l, o);
                    }
                }
            }
        }
        protected virtual Point PickWhenNoTargets()
        {
            return rand.PickBias(x => x.Bias,
                opponentsBoard
                // nothing 1 in size
                .Where(c => (c.Location.X + c.Location.Y) % 2 == gridOddEven)
                .Where(c => c.Data == OpponentsBoardState.Unknown))
                .Location;
        }

        private int SumLine(Cell<OpponentsBoardState> c, int acc)
        {
            if (acc >= 0)
                return acc;
            if (c.Data == OpponentsBoardState.Hit)
                return acc - 1;
            return -acc;
        }

        public System.Drawing.Point GetShot()
        {
            var targets = opponentsBoard
                .Where(c => c.Data == OpponentsBoardState.Hit)
                .SelectMany(c => c.Neighbours())
                .Where(c => c.Data == OpponentsBoardState.Unknown)
                .ToList();
            if (targets.Count > 1)
            {
                var lines = targets.Where(
                    x => x.FoldAll(-1, SumLine).Select(r => Math.Abs(r) - 1).Max() > 1).ToList();
                if (lines.Count > 0)
                    targets = lines;
            }
            var target = targets.RandomOrDefault(rand);
            if (target == null)
                return PickWhenNoTargets();
            return target.Location;
        }

        public void OpponentShot(System.Drawing.Point shot)
        {
        }

        public void ShotHit(Point shot, bool sunk)
        {
            opponentsBoard[shot] = OpponentsBoardState.Hit;
            Debug(shot, sunk);
        }

        public void ShotMiss(Point shot)
        {
            opponentsBoard[shot] = OpponentsBoardState.Miss;
            Debug(shot, false);
        }

        public const bool DebugEnabled = false;

        public void Debug(Point shot, bool sunk)
        {
            if (!DebugEnabled)
                return;
            opponentsBoard.WriteAsGrid(
                Console.Out,
                x =>
                {
                    string t;
                    switch (x.Data)
                    {
                        case OpponentsBoardState.Unknown:
                            return " ";
                        case OpponentsBoardState.Miss:
                            t = "m";
                            break;
                        case OpponentsBoardState.MustBeEmpty:
                            t = "/";
                            break;
                        case OpponentsBoardState.Hit:
                            t = "x";
                            break;
                        default:
                            t = "?";
                            break;
                    }
                    if (x.Location == shot)
                        t = t.ToUpper();
                    return t;
                });
            if (sunk)
                Console.WriteLine("sunk!");
            Console.ReadLine();
        }

        public void GameWon()
        {
        }

        public void GameLost()
        {
        }

        public void MatchOver()
        {
        }

        #region Library code
        enum OpponentsBoardState
        {
            Unknown = 0,
            Miss,
            MustBeEmpty,
            Hit,
        }

        public enum Compass
        {
            North, East, South, West
        }

        class Cell<T>
        {
            private readonly BoardView<T> view;
            public readonly int X;
            public readonly int Y;
            public T Data;
            public double Bias { get; set; }

            public Cell(BoardView<T> view, int x, int y)
            {
                this.view = view; this.X = x; this.Y = y; this.Bias = 1.0;
            }

            public Point Location
            {
                get { return new Point(X, Y); }
            }

            public IEnumerable<U> FoldAll<U>(U acc, Func<Cell<T>, U, U> trip)
            {
                return new[] { Compass.North, Compass.East, Compass.South, Compass.West }
                    .Select(x => FoldLine(x, acc, trip));
            }

            public U FoldLine<U>(Compass direction, U acc, Func<Cell<T>, U, U> trip)
            {
                var cell = this;
                while (true)
                {
                    switch (direction)
                    {
                        case Compass.North:
                            cell = cell.North; break;
                        case Compass.East:
                            cell = cell.East; break;
                        case Compass.South:
                            cell = cell.South; break;
                        case Compass.West:
                            cell = cell.West; break;
                    }
                    if (cell == null)
                        return acc;
                    acc = trip(cell, acc);
                }
            }

            public Cell<T> North
            {
                get { return view.SafeLookup(X, Y - 1); }
            }

            public Cell<T> South
            {
                get { return view.SafeLookup(X, Y + 1); }
            }

            public Cell<T> East
            {
                get { return view.SafeLookup(X + 1, Y); }
            }

            public Cell<T> West
            {
                get { return view.SafeLookup(X - 1, Y); }
            }

            public IEnumerable<Cell<T>> Neighbours()
            {
                if (North != null)
                    yield return North;
                if (South != null)
                    yield return South;
                if (East != null)
                    yield return East;
                if (West != null)
                    yield return West;
            }
        }

        class BoardView<T> : IEnumerable<Cell<T>>
        {
            public readonly Size Size;
            private readonly int Columns;
            private readonly int Rows;

            private Cell<T>[] history;

            public BoardView(Size size)
            {
                this.Size = size;
                Columns = size.Width;
                Rows = size.Height;
                this.history = new Cell<T>[Columns * Rows];
                for (int y = 0; y < Rows; y++)
                {
                    for (int x = 0; x < Rows; x++)
                        history[x + y * Columns] = new Cell<T>(this, x, y);
                }
            }

            public T this[int x, int y]
            {
                get { return history[x + y * Columns].Data; }
                set { history[x + y * Columns].Data = value; }
            }

            public T this[Point p]
            {
                get { return history[SafeCalc(p.X, p.Y, true)].Data; }
                set { this.history[SafeCalc(p.X, p.Y, true)].Data = value; }
            }

            private int SafeCalc(int x, int y, bool throwIfIllegal)
            {
                if (x < 0 || y < 0 || x >= Columns || y >= Rows)
                {
                    if (throwIfIllegal)
                        throw new ArgumentOutOfRangeException("[" + x + "," + y + "]");
                    else
                        return -1;
                }
                return x + y * Columns;
            }

            public void Set(T data)
            {
                foreach (var cell in this.history)
                    cell.Data = data;
            }

            public Cell<T> SafeLookup(int x, int y)
            {
                int index = SafeCalc(x, y, false);
                if (index < 0)
                    return null;
                return history[index];
            }

            #region IEnumerable<Cell<T>> Members

            public IEnumerator<Cell<T>> GetEnumerator()
            {
                foreach (var cell in this.history)
                    yield return cell;
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }

            public BoardView<U> Transform<U>(Func<T, U> transform)
            {
                var result = new BoardView<U>(new Size(Columns, Rows));
                for (int y = 0; y < Rows; y++)
                {
                    for (int x = 0; x < Columns; x++)
                    {
                        result[x, y] = transform(this[x, y]);
                    }
                }
                return result;
            }

            public void WriteAsGrid(TextWriter w)
            {
                WriteAsGrid(w, "{0}");
            }

            public void WriteAsGrid(TextWriter w, string format)
            {
                WriteAsGrid(w, x => string.Format(format, x.Data));
            }

            public void WriteAsGrid(TextWriter w, Func<Cell<T>, string> perCell)
            {
                for (int y = 0; y < Rows; y++)
                {
                    for (int x = 0; x < Columns; x++)
                    {
                        if (x != 0)
                            w.Write(",");
                        w.Write(perCell(this.SafeLookup(x, y)));
                    }
                    w.WriteLine();
                }
            }

            #endregion
        }

        public class Rand
        {
            Random r;

            public Rand()
            {
                var rand = System.Security.Cryptography.RandomNumberGenerator.Create();
                byte[] b = new byte[4];
                rand.GetBytes(b);
                r = new Random(BitConverter.ToInt32(b, 0));
            }

            public int Next(int maxValue)
            {
                return r.Next(maxValue);
            }

            public double NextDouble(double maxValue)
            {
                return r.NextDouble() * maxValue;
            }

            public T Pick<T>(IEnumerable<T> things)
            {
                return things.ElementAt(Next(things.Count()));
            }

            public T PickBias<T>(Func<T, double> bias, IEnumerable<T> things)
            {
                double d = NextDouble(things.Sum(x => bias(x)));
                foreach (var x in things)
                {
                    if (d < bias(x))
                        return x;
                    d -= bias(x);
                }
                throw new InvalidOperationException("fell off the end!");
            }
        }
        #endregion
    }

    public static class Extensions
    {
        public static bool IsIn(this Point p, Size size)
        {
            return p.X >= 0 && p.Y >= 0 && p.X < size.Width && p.Y < size.Height;
        }

        public static bool IsLegal(this Ship ship,
            IEnumerable<Ship> ships,
            Size board,
            Point location,
            ShipOrientation direction)
        {
            var temp = new Ship(ship.Length);
            temp.Place(location, direction);
            if (!temp.GetAllLocations().All(p => p.IsIn(board)))
                return false;
            return ships.Where(s => s.IsPlaced).All(s => !s.ConflictsWith(temp));
        }

        public static bool IsTouching(this Point a, Point b)
        {
            return (a.X == b.X - 1 || a.X == b.X + 1) &&
                (a.Y == b.Y - 1 || a.Y == b.Y + 1);
        }

        public static bool IsTouching(this Ship ship,
            IEnumerable<Ship> ships,
            Point location,
            ShipOrientation direction)
        {
            var temp = new Ship(ship.Length);
            temp.Place(location, direction);
            var occupied = new HashSet<Point>(ships
                .Where(s => s.IsPlaced)
                .SelectMany(s => s.GetAllLocations()));
            if (temp.GetAllLocations().Any(p => occupied.Any(b => b.IsTouching(p))))
                return true;
            return false;
        }

        public static ReadOnlyCollection<Ship> MakeShips(params int[] lengths)
        {
            return new System.Collections.ObjectModel.ReadOnlyCollection<Ship>(
                lengths.Select(l => new Ship(l)).ToList());
        }

        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Battleship.ShuggyCoUk.Simple.Rand rand)
        {
            T[] elements = source.ToArray();
            // Note i > 0 to avoid final pointless iteration
            for (int i = elements.Length - 1; i > 0; i--)
            {
                // Swap element "i" with a random earlier element it (or itself)
                int swapIndex = rand.Next(i + 1);
                T tmp = elements[i];
                elements[i] = elements[swapIndex];
                elements[swapIndex] = tmp;
            }
            // Lazily yield (avoiding aliasing issues etc)
            foreach (T element in elements)
            {
                yield return element;
            }
        }

        public static T RandomOrDefault<T>(this IEnumerable<T> things, Battleship.ShuggyCoUk.Simple.Rand rand)
        {
            int count = things.Count();
            if (count == 0)
                return default(T);
            return things.ElementAt(rand.Next(count));
        }
    }

}


5

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

namespace Battleship
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;

    public class BP7 : IBattleshipOpponent
    {
        public string Name { get { return "BP7"; } }
        public Version Version { get { return this.version; } }

        Random rand = new Random();
        Version version = new Version(0, 7);
        Size gameSize;
        List<Point> scanShots;
        List<NextShot> nextShots;
        int wins, losses;
        int totalWins = 0;
        int totalLosses = 0;
        int maxWins = 0;
        int maxLosses = 0;
        int matchWins = 0;
        int matchLosses = 0;

        public enum Direction { VERTICAL = -1, UNKNOWN = 0, HORIZONTAL = 1 };
        Direction hitDirection, lastShotDirection;

        enum ShotResult { UNKNOWN, MISS, HIT };
        ShotResult[,] board;

        public struct NextShot
        {
            public Point point;
            public Direction direction;
            public NextShot(Point p, Direction d)
            {
                point = p;
                direction = d;
            }
        }

        public struct ScanShot
        {
            public Point point;
            public int openSpaces;
            public ScanShot(Point p, int o)
            {
                point = p;
                openSpaces = o;
            }
        }

        public void NewGame(Size size, TimeSpan timeSpan)
        {
            this.gameSize = size;
            scanShots = new List<Point>();
            nextShots = new List<NextShot>();
            fillScanShots();
            hitDirection = Direction.UNKNOWN;
            board = new ShotResult[size.Width, size.Height];
        }

        private void fillScanShots()
        {
            int x;
            for (x = 0; x < gameSize.Width - 1; x++)
            {
                scanShots.Add(new Point(x, x));
            }

            if (gameSize.Width == 10)
            {
                for (x = 0; x < 3; x++)
                {
                    scanShots.Add(new Point(9 - x, x));
                    scanShots.Add(new Point(x, 9 - x));
                }
            }
        }

        public void PlaceShips(System.Collections.ObjectModel.ReadOnlyCollection<Ship> ships)
        {
            foreach (Ship s in ships)
            {
                s.Place(
                    new Point(
                        rand.Next(this.gameSize.Width),
                        rand.Next(this.gameSize.Height)),
                    (ShipOrientation)rand.Next(2));
            }
        }

        public Point GetShot()
        {
            Point shot;

            if (this.nextShots.Count > 0)
            {
                if (hitDirection != Direction.UNKNOWN)
                {
                    if (hitDirection == Direction.HORIZONTAL)
                    {
                        this.nextShots = this.nextShots.OrderByDescending(x => x.direction).ToList();
                    }
                    else
                    {
                        this.nextShots = this.nextShots.OrderBy(x => x.direction).ToList();
                    }
                }

                shot = this.nextShots.First().point;
                lastShotDirection = this.nextShots.First().direction;
                this.nextShots.RemoveAt(0);
                return shot;
            }

            List<ScanShot> scanShots = new List<ScanShot>();
            for (int x = 0; x < gameSize.Width; x++)
            {
                for (int y = 0; y < gameSize.Height; y++)
                {
                    if (board[x, y] == ShotResult.UNKNOWN)
                    {
                        scanShots.Add(new ScanShot(new Point(x, y), OpenSpaces(x, y)));
                    }
                }
            }
            scanShots = scanShots.OrderByDescending(x => x.openSpaces).ToList();
            int maxOpenSpaces = scanShots.FirstOrDefault().openSpaces;

            List<ScanShot> scanShots2 = new List<ScanShot>();
            scanShots2 = scanShots.Where(x => x.openSpaces == maxOpenSpaces).ToList();
            shot = scanShots2[rand.Next(scanShots2.Count())].point;

            return shot;
        }

        int OpenSpaces(int x, int y)
        {
            int ctr = 0;
            Point p;

            // spaces to the left
            p = new Point(x - 1, y);
            while (p.X >= 0 && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.X--;
            }

            // spaces to the right
            p = new Point(x + 1, y);
            while (p.X < gameSize.Width && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.X++;
            }

            // spaces to the top
            p = new Point(x, y - 1);
            while (p.Y >= 0 && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.Y--;
            }

            // spaces to the bottom
            p = new Point(x, y + 1);
            while (p.Y < gameSize.Height && board[p.X, p.Y] == ShotResult.UNKNOWN)
            {
                ctr++;
                p.Y++;
            }

            return ctr;
        }

        public void NewMatch(string opponenet)
        {
            wins = 0;
            losses = 0;
        }

        public void OpponentShot(Point shot) { }

        public void ShotHit(Point shot, bool sunk)
        {
            board[shot.X, shot.Y] = ShotResult.HIT;

            if (!sunk)
            {
                hitDirection = lastShotDirection;
                if (shot.X != 0)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X - 1, shot.Y), Direction.HORIZONTAL));
                }

                if (shot.Y != 0)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X, shot.Y - 1), Direction.VERTICAL));
                }

                if (shot.X != this.gameSize.Width - 1)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X + 1, shot.Y), Direction.HORIZONTAL));
                }

                if (shot.Y != this.gameSize.Height - 1)
                {
                    this.nextShots.Add(new NextShot(new Point(shot.X, shot.Y + 1), Direction.VERTICAL));
                }
            }
            else
            {
                hitDirection = Direction.UNKNOWN;
                this.nextShots.Clear();     // so now this works like gangbusters ?!?!?!?!?!?!?!?!?
            }
        }

        public void ShotMiss(Point shot)
        {
            board[shot.X, shot.Y] = ShotResult.MISS;
        }

        public void GameWon()
        {
            wins++;
        }

        public void GameLost()
        {
            losses++;
        }

        public void MatchOver()
        {
            if (wins > maxWins)
            {
                maxWins = wins;
            }

            if (losses > maxLosses)
            {
                maxLosses = losses;
            }

            totalWins += wins;
            totalLosses += losses;

            if (wins >= 51)
            {
                matchWins++;
            }
            else
            {
                matchLosses++;
            }
        }

        public void FinalStats()
        {
            Console.WriteLine("Games won: " + totalWins.ToString());
            Console.WriteLine("Games lost: " + totalLosses.ToString());
            Console.WriteLine("Game winning percentage: " + (totalWins * 1.0 / (totalWins + totalLosses)).ToString("P"));
            Console.WriteLine("Game losing percentage: " + (totalLosses * 1.0 / (totalWins + totalLosses)).ToString("P"));
            Console.WriteLine();
            Console.WriteLine("Matches won: " + matchWins.ToString());
            Console.WriteLine("Matches lost: " + matchLosses.ToString());
            Console.WriteLine("Match winning percentage: " + (matchWins * 1.0 / (matchWins + matchLosses)).ToString("P"));
            Console.WriteLine("Match losing percentage: " + (matchLosses * 1.0 / (matchWins + matchLosses)).ToString("P"));
            Console.WriteLine("Match games won high: " + maxWins.ToString());
            Console.WriteLine("Match games lost high: " + maxLosses.ToString());
            Console.WriteLine();
        }
    }
}

এই যুক্তিটি আমার কাছে সবচেয়ে কাছের যে ড্রেডনচটকে পরাজিত করতে হয়েছিল এবং প্রায় ৪১% পৃথক গেম জিতেছিল। (এটি আসলে ৫২ থেকে ৪৯ এর একটি গণনায় একটি ম্যাচ জিততে পেরেছে Od) আশ্চর্যের বিষয়, এই শ্রেণিটি ফার্নসওয়ার্থঅপোনাল্টারের বিপক্ষে আগের সংস্করণ হিসাবে খুব কম উন্নত ছিল না।


5

আমার কম্পিউটারটি এখনই ডেল দ্বারা মেরামত করা হচ্ছে, তবে আমি এখানেই গত সপ্তাহে ছিলাম:

namespace Battleship
{
    using System;
    using System.Collections.ObjectModel;
    using System.Drawing;
    using System.Collections.Generic;
    using System.Linq;

    public class BSKiller4 : OpponentExtended, IBattleshipOpponent
    {
        public string Name { get { return "BSKiller4"; } }
        public Version Version { get { return this.version; } }

        public bool showBoard = false;

        Random rand = new Random();
        Version version = new Version(0, 4);
        Size gameSize;

        List<Point> nextShots;
        Queue<Point> scanShots;

        char[,] board;

        private void printBoard()
        {
            Console.WriteLine();
            for (int y = 0; y < this.gameSize.Height; y++)
            {
                for (int x = 0; x < this.gameSize.Width; x++)
                {
                    Console.Write(this.board[x, y]);
                }
                Console.WriteLine();
            }
            Console.ReadKey();
        }

        public void NewGame(Size size, TimeSpan timeSpan)
        {
            this.gameSize = size;
            board = new char[size.Width, size.Height];
            this.nextShots = new List<Point>();
            this.scanShots = new Queue<Point>();
            fillScanShots();
            initializeBoard();
        }

        private void initializeBoard()
        {
            for (int y = 0; y < this.gameSize.Height; y++)
            {
                for (int x = 0; x < this.gameSize.Width; x++)
                {
                    this.board[x, y] = 'O';
                }
            }
        }

        private void fillScanShots()
        {
            int x, y;
            int num = gameSize.Width * gameSize.Height;
            for (int j = 0; j < 3; j++)
            {
                for (int i = j; i < num; i += 3)
                {
                    x = i % gameSize.Width;
                    y = i / gameSize.Height;
                    scanShots.Enqueue(new Point(x, y));
                }
            }
        }

        public void PlaceShips(ReadOnlyCollection<Ship> ships)
        {
            foreach (Ship s in ships)
            {
                s.Place(new Point(
                        rand.Next(this.gameSize.Width),
                        rand.Next(this.gameSize.Height)),
                        (ShipOrientation)rand.Next(2));
            }
        }

        public Point GetShot()
        {
            if (showBoard) printBoard();
            Point shot;

            shot = findShotRun();
            if (shot.X != -1)
            {
                return shot;
            }

            if (this.nextShots.Count > 0)
            {
                shot = this.nextShots[0];
                this.nextShots.RemoveAt(0);
            }
            else
            {
                shot = this.scanShots.Dequeue();
            }

            return shot;
        }

        public void ShotHit(Point shot, bool sunk)
        {
            this.board[shot.X, shot.Y] = 'H';
            if (!sunk)
            {
                addToNextShots(new Point(shot.X - 1, shot.Y));
                addToNextShots(new Point(shot.X, shot.Y + 1));
                addToNextShots(new Point(shot.X + 1, shot.Y));
                addToNextShots(new Point(shot.X, shot.Y - 1));
            }
            else
            {
                this.nextShots.Clear();
            }
        }



        private Point findShotRun()
        {
            int run_forward_horizontal = 0;
            int run_backward_horizontal = 0;
            int run_forward_vertical = 0;
            int run_backward_vertical = 0;

            List<shotPossibilities> possible = new List<shotPossibilities>(5);

            // this only works if width = height for the board;
            for (int y = 0; y < this.gameSize.Height; y++)
            {
                for (int x = 0; x < this.gameSize.Width; x++)
                {
                    // forward horiz
                    if (this.board[x, y] == 'M')
                    {
                        run_forward_horizontal = 0;
                    }
                    else if (this.board[x, y] == 'O')
                    {
                        if (run_forward_horizontal >= 2)
                        {
                            possible.Add(
                                new shotPossibilities(
                                    run_forward_horizontal,
                                    new Point(x, y),
                                    true));
                        }
                        else
                        {
                            run_forward_horizontal = 0;
                        }
                    }
                    else
                    {
                        run_forward_horizontal++;
                    }

                    // forward vertical
                    if (this.board[y, x] == 'M')
                    {
                        run_forward_vertical = 0;
                    }
                    else if (this.board[y, x] == 'O')
                    {
                        if (run_forward_vertical >= 2)
                        {
                            possible.Add(
                                new shotPossibilities(
                                    run_forward_vertical,
                                    new Point(y, x),
                                    false));
                        }
                        else
                        {
                            run_forward_vertical = 0;
                        }
                    }
                    else
                    {
                        run_forward_vertical++;
                    }


                    // backward horiz
                    if (this.board[this.gameSize.Width - x - 1, y] == 'M')
                    {
                        run_backward_horizontal = 0;
                    }
                    else if (this.board[this.gameSize.Width - x - 1, y] == 'O')
                    {
                        if (run_backward_horizontal >= 2)
                        {
                            possible.Add(
                                new shotPossibilities(
                                    run_backward_horizontal,
                                    new Point(this.gameSize.Width - x - 1, y),
                                    true));
                        }
                        else
                        {
                            run_backward_horizontal = 0;
                        }
                    }
                    else
                    {
                        run_backward_horizontal++;
                    }


                    // backward vertical
                    if (this.board[y, this.gameSize.Height - x - 1] == 'M')
                    {
                        run_backward_vertical = 0;
                    }
                    else if (this.board[y, this.gameSize.Height - x - 1] == 'O')
                    {
                        if (run_backward_vertical >= 2)
                        {
                            possible.Add(
                                new shotPossibilities(
                                    run_backward_vertical,
                                    new Point(y, this.gameSize.Height - x - 1),
                                    false));
                        }
                        else
                        {
                            run_backward_vertical = 0;
                        }
                    }
                    else
                    {
                        run_backward_vertical++;
                    }

                }

                run_forward_horizontal = 0;
                run_backward_horizontal = 0;
                run_forward_vertical = 0;
                run_backward_vertical = 0;
            }
            Point shot;

            if (possible.Count > 0)
            {
                shotPossibilities shotp = possible.OrderByDescending(a => a.run).First();
                //this.nextShots.Clear();
                shot = shotp.shot;
                //if (shotp.isHorizontal)
                //{
                //    this.nextShots.RemoveAll(p => p.X != shot.X);
                //}
                //else
                //{
                //    this.nextShots.RemoveAll(p => p.Y != shot.Y);
                //}
            }
            else
            {
                shot = new Point(-1, -1);
            }

            return shot;
        }

        private void addToNextShots(Point p)
        {
            if (!this.nextShots.Contains(p) &&
                p.X >= 0 &&
                p.X < this.gameSize.Width &&
                p.Y >= 0 &&
                p.Y < this.gameSize.Height)
            {
                if (this.board[p.X, p.Y] == 'O')
                {
                    this.nextShots.Add(p);
                }
            }
        }

        public void GameWon()
        {
            this.GameWins++;
        }

        public void NewMatch(string opponent)
        {
            System.Threading.Thread.Sleep(5);
            this.rand = new Random(System.Environment.TickCount);
        }
        public void OpponentShot(Point shot) { }
        public void ShotMiss(Point shot)
        {
            this.board[shot.X, shot.Y] = 'M';
        }
        public void GameLost()
        {
            if (showBoard) Console.WriteLine("-----Game Over-----");
        }
        public void MatchOver() { }
    }


    public class OpponentExtended
    {
        public int GameWins { get; set; }
        public int MatchWins { get; set; }
        public OpponentExtended() { }
    }

    public class shotPossibilities
    {
        public shotPossibilities(int r, Point s, bool h)
        {
            this.run = r;
            this.shot = s;
            this.isHorizontal = h;
        }
        public int run { get; set; }
        public Point shot { get; set; }
        public bool isHorizontal { get; set; }
    }
}

2
রূপা অভিনন্দন। কথায় কথায় আপনার অ্যালগরিদম বর্ণনা করতে আপত্তি আছে? এটি সম্পর্কে জানতে আগ্রহী হবে।
থমাস আহলে

4

আপনি যদি নিজের বিশ্লেষণের জন্য নিষ্ঠুর হন তবে আপনি সরবরাহ করা র‌্যান্ডমঅপোয়েন্টালটির যান্ত্রিকীগুলিকে অত্যন্ত অযোগ্য বলে মনে করতে পারেন। এটি নিজেই ইতিমধ্যে লক্ষ্যযুক্ত অবস্থানগুলি পুনরায় নির্ধারণ করতে দেয় এবং ফ্রেমওয়ার্কটি এটির পুনরাবৃত্তি করতে বাধ্য করে যতক্ষণ না এটি আঘাত করে এমন একটিকে আঘাত করে বা সরানো প্রতি সময়সীমার মেয়াদ শেষ হয়।

এই প্রতিপক্ষের অনুরূপ আচরণ রয়েছে (কার্যকর প্লেসমেন্ট বিতরণ একই)) এটি কেবল বিচক্ষণতা যাচাই করে এবং কেবলমাত্র কল (একাঙ্কিত) প্রতি একটি এলোমেলো সংখ্যা জেনারেশন গ্রহণ করে।

এটি আমার এক্সটেনশানগুলি / লাইব্রেরির উত্তরের ক্লাসগুলি ব্যবহার করে এবং আমি কেবল মূল পদ্ধতি / রাজ্য সরবরাহ করি।

এলোমেলো থেকে উত্ক্ষিপ্ত হয় এখানে জন স্কিট এর উত্তর

class WellBehavedRandomOpponent : IBattleShipOpponent
{
    Rand rand = new Rand();
    List<Point> guesses;
    int nextGuess = 0;

    public void PlaceShips(IEnumerable<Ship> ships)
    {
        BoardView<bool> board = new BoardView<bool>(BoardSize);
        var AllOrientations = new[] {
            ShipOrientation.Horizontal,
            ShipOrientation.Vertical };

        foreach (var ship in ships)
        {
            while (!ship.IsPlaced)
            {
                var l = rand.Pick(board.Select(c => c.Location));
                var o = rand.Pick(AllOrientations);
                if (ship.IsLegal(ships, BoardSize, l, o))
                    ship.Place(l, o);
            }
        }
    }

    public void NewGame(Size size, TimeSpan timeSpan)
    {
        var board = new BoardView<bool>(size);
        this.guesses = new List<Point>(
            board.Select(x => x.Location).Shuffle(rand));
        nextGuess = 0;
    }

    public System.Drawing.Point GetShot()
    {
        return guesses[nextGuess++];
    }

    // empty methods left out 
}

4

আমি অংশ নিতে সক্ষম হচ্ছি না, তবে এখানে সময় থাকলে আলগরিদমটি আমি প্রয়োগ করতাম:

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

  1. কেন্দ্রে আঘাত করুন (নীচে চূড়ান্ত নোট দেখুন - 'কেন্দ্র' বর্ণনার জন্য কেবল একটি সুবিধা)
  2. কেন্দ্রের ডানদিকে স্পট 4 চাপুন
  3. 1 নীচে এবং কেন্দ্রের ডানদিকে স্পটটি হিট করুন
  4. আগের হিটের ডানদিকে স্পটটি চারটি হিট করুন
  5. সেই ধাঁচে চালিয়ে যান (বোর্ডটি পূরণের জন্য 3 টি স্পেস দিয়ে বিভক্ত রেখাগুলি দিয়ে শেষ হওয়া উচিত) এটি সমস্ত 4 এবং 5 দৈর্ঘ্যের নৌকা এবং 3 এবং 2 নৌকায় একটি পরিসংখ্যানগতভাবে বড় সংখ্যায় আঘাত করতে হবে।

  6. ডায়াগোনগুলির অভ্যন্তরে এলোমেলোভাবে দাগগুলি আঘাত করা শুরু করুন, এটি 2 এবং 3 দৈর্ঘ্যের নৌকাগুলি ধরবে যা ইতিমধ্যে লক্ষ্য করা যায় নি।

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

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

চূড়ান্ত নোট:

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

এটি এমন একটি 'নিখুঁত' অ্যালগরিদম বর্ণনা করে যা এটি (9x9) / 2 + 10 শটের আওতায় সমস্ত জাহাজ পাবে।

তবে, এটি উল্লেখযোগ্যভাবে উন্নত করা যেতে পারে:

একবার কোনও জাহাজ আঘাত হ'ল 'অভ্যন্তরীণ' তির্যক রেখাগুলি করার আগে এর আকারটি চিহ্নিত করুন। আপনি সম্ভবত 2 টি জাহাজটি পেয়েছেন, সেই ক্ষেত্রে 3 আকারের জাহাজটি আরও দ্রুত সন্ধানের জন্য অভ্যন্তরীণ তির্যকগুলি সহজ করা যেতে পারে।

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

প্রতিযোগীর খেলার শৈলীর শনাক্ত করুন - তারা কীভাবে জাহাজের স্থান নির্ধারণের পরিকল্পনা করে তা আপনাকে ক্লু দিতে পারে (যেমন, সম্ভাবনা ভাল যে তাদের নিজস্ব অ্যালগোরিদম খুব দ্রুত তারা কীভাবে তাদের নিজস্ব জাহাজ রাখে তা সনাক্ত করে - যদি আপনার কাছে কেবলমাত্র হাতিয়ারটি একটি হাতুড়ি থাকে, সব কিছুই পেরেকের মতো দেখাচ্ছে)

-Adam


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

4

আমার প্রবেশ

ভয়াবহভাবে বিশেষ কিছুই নয় এবং আমার কাছে থাকা সমস্ত ভাল ধারণা যুক্ত করার জন্য আমি সময় পাইনি।

তবে মনে হয় এটি মোটামুটি ভাল খেলেছে। প্রতিযোগিতায় এটি কীভাবে হয় তা আমরা দেখতে পাব:

(এটি ফাইলের মধ্যে Missouri.csরেখে প্রকল্পে যুক্ত করা হয়েছে))

using System;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

namespace Battleship
{
    // The Empire of Japan surrendered on the deck of the USS Missouri on Sept. 2, 1945
    public class USSMissouri : IBattleshipOpponent
    {
        public String  Name    { get { return name; } }
        public Version Version { get { return ver;  } }

#region IBattleship Interface
        // IBattleship::NewGame
        public void NewGame(Size gameSize, TimeSpan timeSpan)
        {
            size      = gameSize;
            shotBoard = new ShotBoard(size);
            attackVector = new Stack<Attack>();
        }

        // IBattleship::PlaceShips
        public void PlaceShips(ReadOnlyCollection<Ship> ships)
        {
            HunterBoard board;
            targetBoards = new List<HunterBoard>();
            shotBoard    = new ShotBoard(size);
            foreach (Ship s in ships)
            {
                board = new HunterBoard(this, size, s);
                targetBoards.Add(board);

                // REWRITE: to ensure valid board placement.
                s.Place(
                    new Point(
                        rand.Next(size.Width),
                        rand.Next(size.Height)),
                    (ShipOrientation)rand.Next(2));
            }
        }

        // IBattleship::GetShot
        public Point GetShot()
        {
            Point p = new Point();

            if (attackVector.Count() > 0)
            {
                p = ExtendShot();
                return p;
            }

            // Contemplate a shot at every-single point, and measure how effective it would be.
            Board potential = new Board(size);
            for(p.Y=0; p.Y<size.Height; ++p.Y)
            {
                for(p.X=0; p.X<size.Width; ++p.X)
                {
                    if (shotBoard.ShotAt(p))
                    {
                        potential[p] = 0;
                        continue;
                    }

                    foreach(HunterBoard b in targetBoards)
                    {
                        potential[p] += b.GetWeightAt(p);
                    }
                }
            }

            // Okay, we have the shot potential of the board.
            // Lets pick a weighted-random spot.
            Point shot;
            shot = potential.GetWeightedRandom(rand.NextDouble());

            shotBoard[shot] = Shot.Unresolved;

            return shot;
        }

        public Point ExtendShot()
        {
            // Lets consider North, South, East, and West of the current shot.
            // and measure the potential of each
            Attack attack = attackVector.Peek();

            Board potential = new Board(size);

            Point[] points = attack.GetNextTargets();
            foreach(Point p in points)
            {
                if (shotBoard.ShotAt(p))
                {
                    potential[p] = 0;
                    continue;
                }

                foreach(HunterBoard b in targetBoards)
                {
                    potential[p] += b.GetWeightAt(p);
                }
            }

            Point shot = potential.GetBestShot();
            shotBoard[shot] = Shot.Unresolved;
            return shot;
        }

        // IBattleship::NewMatch
        public void NewMatch(string opponent)
        {
        }
        public void OpponentShot(Point shot)
        {
        }
        public void ShotHit(Point shot, bool sunk)
        {
            shotBoard[shot] = Shot.Hit;

            if (!sunk)
            {
                if (attackVector.Count == 0) // This is a first hit, open an attackVector
                {   
                    attackVector.Push(new Attack(this, shot));
                }
                else
                {
                    attackVector.Peek().AddHit(shot);    // Add a hit to our current attack.
                }
            }

            // What if it is sunk?  Close the top attack, which we've been pursuing.
            if (sunk)
            {
                if (attackVector.Count > 0)
                {
                    attackVector.Pop();
                }
            }
        }
        public void ShotMiss(Point shot)
        {
            shotBoard[shot] = Shot.Miss;

            foreach(HunterBoard b in targetBoards)
            {
                b.ShotMiss(shot);  // Update the potential map.
            }
        }
        public void GameWon()
        {
            Trace.WriteLine  ("I won the game!");
        }
        public void GameLost()
        {
            Trace.WriteLine  ("I lost the game!");
        }
        public void MatchOver()
        {
            Trace.WriteLine("This match is over.");
        }

#endregion 

        public ShotBoard theShotBoard
        {
            get { return shotBoard; }
        }
        public Size theBoardSize
        {
            get { return size; }
        }

        private Random rand = new Random();
        private Version ver = new Version(6, 3); // USS Missouri is BB-63, hence version 6.3
        private String name = "USS Missouri (abelenky@alum.mit.edu)";
        private Size size;
        private List<HunterBoard> targetBoards;
        private ShotBoard shotBoard;
        private Stack<Attack> attackVector;
    }

    // An Attack is the data on the ship we are currently working on sinking.
    // It consists of a set of points, horizontal and vertical, from a central point.
    // And can be extended in any direction.
    public class Attack
    {
        public Attack(USSMissouri root, Point p)
        {
            Player = root;
            hit = p;
            horzExtent = new Extent(p.X, p.X);
            vertExtent = new Extent(p.Y, p.Y);
        }

        public Extent HorizontalExtent
        {
            get { return horzExtent; }
        }
        public Extent VerticalExtent
        {
            get { return vertExtent; }
        }
        public Point  FirstHit
        {
            get { return hit; }
        }

        public void AddHit(Point p)
        {
            if (hit.X == p.X) // New hit in the vertical direction
            {
                vertExtent.Min = Math.Min(vertExtent.Min, p.Y);
                vertExtent.Max = Math.Max(vertExtent.Max, p.Y);
            }
            else if (hit.Y == p.Y)
            {
                horzExtent.Min = Math.Min(horzExtent.Min, p.X);
                horzExtent.Max = Math.Max(horzExtent.Max, p.X);
            }
        }
        public Point[] GetNextTargets() 
        {
            List<Point> bors = new List<Point>();

            Point p;

            p = new Point(hit.X, vertExtent.Min-1);
            while (p.Y >= 0 && Player.theShotBoard[p] == Shot.Hit)
            {
                if (Player.theShotBoard[p] == Shot.Miss)
                {
                    break; // Don't add p to the List 'bors.  
                }
                --p.Y;
            }
            if (p.Y >= 0 && Player.theShotBoard[p] == Shot.None) // Add next-target only if there is no shot here yet.
            {
                bors.Add(p);
            }

            //-------------------

            p = new Point(hit.X, vertExtent.Max+1);
            while (p.Y < Player.theBoardSize.Height && Player.theShotBoard[p] == Shot.Hit)
            {
                if (Player.theShotBoard[p] == Shot.Miss)
                {
                    break; // Don't add p to the List 'bors.  
                }
                ++p.Y;
            }
            if (p.Y < Player.theBoardSize.Height && Player.theShotBoard[p] == Shot.None)
            {
                bors.Add(p);
            }

            //-------------------

            p = new Point(horzExtent.Min-1, hit.Y);
            while (p.X >= 0 && Player.theShotBoard[p] == Shot.Hit)
            {
                if (Player.theShotBoard[p] == Shot.Miss)
                {
                    break; // Don't add p to the List 'bors.  
                }
                --p.X;
            }
            if (p.X >= 0 && Player.theShotBoard[p] == Shot.None)
            {
                bors.Add(p);
            }

            //-------------------

            p = new Point(horzExtent.Max+1, hit.Y);
            while (p.X < Player.theBoardSize.Width && Player.theShotBoard[p] == Shot.Hit)
            {
                if (Player.theShotBoard[p] == Shot.Miss)
                {
                    break; // Don't add p to the List 'bors.  
                }
                ++p.X;
            }
            if (p.X < Player.theBoardSize.Width && Player.theShotBoard[p] == Shot.None)
            {
                bors.Add(p);
            }

            return bors.ToArray();
        }

        private Point hit; 
        private Extent horzExtent;
        private Extent vertExtent;
        private USSMissouri Player;
    }

    public struct Extent
    {
        public Extent(Int32 min, Int32 max)
        {
            Min = min;
            Max = max;
        }
        public Int32 Min;
        public Int32 Max;
    }

    public class Board  // The potential-Board, which measures the full potential of each square.
    {
        // A Board is the status of many things.
        public Board(Size boardsize)
        {
            size = boardsize;
            grid = new int[size.Width , size.Height];
            Array.Clear(grid,0,size.Width*size.Height);
        }

        public int this[int c,int r]
        {
            get { return grid[c,r];  }
            set { grid[c,r] = value; }
        }
        public int this[Point p]
        {
            get { return grid[p.X, p.Y];  }
            set { grid[p.X, p.Y] = value; }
        }

        public Point GetWeightedRandom(double r)
        {
            Int32 sum = 0;
            foreach(Int32 i in grid)
            {
                sum += i;
            }

            Int32 index = (Int32)(r*sum);

            Int32 x=0, y=0;
            for(y=0; y<size.Height; ++y)
            {
                for(x=0; x<size.Width; ++x)
                {
                    if (grid[x,y] == 0) continue; // Skip any zero-cells
                    index -= grid[x,y];
                    if (index < 0) break;
                }
                if (index < 0) break;
            }

            if (x == 10 || y == 10)
                throw new Exception("WTF");

            return new Point(x,y);
        }

        public Point GetBestShot()
        {
            int max=grid[0,0];
            for(int y=0; y<size.Height; ++y)
            {
                for (int x=0; x<size.Width; ++x)
                {
                    max = (grid[x,y] > max)? grid[x,y] : max;
                }
            }

            for(int y=0; y<size.Height; ++y)
            {
                for (int x=0; x<size.Width; ++x)
                {
                    if (grid[x,y] == max)
                    {
                        return new Point(x,y);
                    }
                }
            }
            return new Point(0,0);
        }

        public bool IsZero()
        {
            foreach(Int32 p in grid)
            {
                if (p > 0)
                {
                    return false;
                }
            }
            return true;
        }

        public override String ToString()
        {
            String output = "";
            String horzDiv = "   +----+----+----+----+----+----+----+----+----+----+\n";
            String disp;
            int x,y;

            output += "      A    B    C    D    E    F    G    H    I    J    \n" + horzDiv;

            for(y=0; y<size.Height; ++y)
            {
                output += String.Format("{0} ", y+1).PadLeft(3);
                for(x=0; x<size.Width; ++x)
                {
                    switch(grid[x,y])
                    {
                        case (int)Shot.None:       disp = "";  break;
                        case (int)Shot.Hit:        disp = "#"; break;
                        case (int)Shot.Miss:       disp = "."; break;
                        case (int)Shot.Unresolved: disp = "?"; break;
                        default:                   disp = "!"; break;
                    }

                    output += String.Format("| {0} ", disp.PadLeft(2));
                }
                output += "|\n" + horzDiv;
            }

            return output;
        }

        protected Int32[,] grid;
        protected Size     size;
    }

    public class HunterBoard
    {
        public HunterBoard(USSMissouri root, Size boardsize, Ship target)
        {
            size = boardsize;
            grid = new int[size.Width , size.Height];
            Array.Clear(grid,0,size.Width*size.Height);

            Player = root;
            Target = target;
            Initialize();
        }

        public void Initialize()
        {
            int x, y, i;

            for(y=0; y<size.Height; ++y)
            {
                for(x=0; x<size.Width - Target.Length+1; ++x)
                {
                    for(i=0; i<Target.Length; ++i)
                    {
                        grid[x+i,y]++;
                    }
                }
            }

            for(y=0; y<size.Height-Target.Length+1; ++y)
            {
                for(x=0; x<size.Width; ++x)
                {
                    for(i=0; i<Target.Length; ++i)
                    {
                        grid[x,y+i]++;
                    }
                }
            }
        }

        public int this[int c,int r]
        {
            get { return grid[c,r];  }
            set { grid[c,r] = value; }
        }
        public int this[Point p]
        {
            get { return grid[p.X, p.Y];  }
            set { grid[p.X, p.Y] = value; }
        }

        public void ShotMiss(Point p)
        {
            int x,y;
            int min, max;

            min = Math.Max(p.X-Target.Length+1, 0);
            max = Math.Min(p.X, size.Width-Target.Length);
            for(x=min; x<=max; ++x)
            {
                DecrementRow(p.Y, x, x+Target.Length-1);
            }

            min = Math.Max(p.Y-Target.Length+1, 0);
            max = Math.Min(p.Y, size.Height-Target.Length);
            for(y=min; y<=max; ++y)
            {
                DecrementColumn(p.X, y, y+Target.Length-1);
            } 

            grid[p.X, p.Y] = 0;
        }

        public void ShotHit(Point p)
        {
        }

        public override String ToString()
        {
            String output = String.Format("Target size is {0}\n", Target.Length);
            String horzDiv = "   +----+----+----+----+----+----+----+----+----+----+\n";
            int x,y;

            output += "      A    B    C    D    E    F    G    H    I    J    \n" + horzDiv;
            for(y=0; y<size.Height; ++y)
            {
                output += String.Format("{0} ", y+1).PadLeft(3);
                for(x=0; x<size.Width; ++x)
                {
                    output += String.Format("| {0} ", grid[x,y].ToString().PadLeft(2));
                }
                output += "|\n" + horzDiv;
            }
            return output;
        }

        // If we shoot at point P, how does that affect the potential of the board?
        public Int32 GetWeightAt(Point p)
        {
            int x,y;
            int potential = 0;
            int min, max;

            min = Math.Max(p.X-Target.Length+1, 0);
            max = Math.Min(p.X, size.Width-Target.Length);
            for(x=min; x<=max; ++x)
            {
                if (Player.theShotBoard.isMissInRow(p.Y, x, x+Target.Length-1) == false)
                {
                    ++potential;
                }
            }

            min = Math.Max(p.Y-Target.Length+1, 0);
            max = Math.Min(p.Y, size.Height-Target.Length);
            for(y=min; y<=max; ++y)
            {
                if (Player.theShotBoard.isMissInColumn(p.X, y, y+Target.Length-1) == false)
                {
                    ++potential;
                }
            } 

            return potential;
        }

        public void DecrementRow(int row, int rangeA, int rangeB)
        {
            int x;
            for(x=rangeA; x<=rangeB; ++x)
            {
                grid[x,row] = (grid[x,row]==0)? 0 : grid[x,row]-1;
            }
        }
        public void DecrementColumn(int col, int rangeA, int rangeB)
        {
            int y;
            for(y=rangeA; y<=rangeB; ++y)
            {
                grid[col,y] = (grid[col,y]==0)? 0 : grid[col,y]-1;
            }
        }

        private Ship Target = null;
        private USSMissouri Player;
        private Int32[,] grid;
        private Size     size;
    }

    public enum Shot
    {
        None = 0,
        Hit = 1,
        Miss = 2,
        Unresolved = 3
    };

    public class ShotBoard
    {
        public ShotBoard(Size boardsize)
        {
            size = boardsize;
            grid = new Shot[size.Width , size.Height];

            for(int y=0; y<size.Height; ++y)
            {
                for(int x=0; x<size.Width; ++x)
                {
                    grid[x,y] = Shot.None;
                }
            }
        }

        public Shot this[int c,int r]
        {
            get { return grid[c,r];  }
            set { grid[c,r] = value; }
        }
        public Shot this[Point p]
        {
            get { return grid[p.X, p.Y];  }
            set { grid[p.X, p.Y] = value; }
        }

        public override String ToString()
        {
            String output = "";
            String horzDiv = "   +----+----+----+----+----+----+----+----+----+----+\n";
            String disp;
            int x,y;

            output += "      A    B    C    D    E    F    G    H    I    J    \n" + horzDiv;

            for(y=0; y<size.Height; ++y)
            {
                output += String.Format("{0} ", y+1).PadLeft(3);
                for(x=0; x<size.Width; ++x)
                {
                    switch(grid[x,y])
                    {
                        case Shot.None:       disp = "";  break;
                        case Shot.Hit:        disp = "#"; break;
                        case Shot.Miss:       disp = "."; break;
                        case Shot.Unresolved: disp = "?"; break;
                        default:              disp = "!"; break;
                    }

                    output += String.Format("| {0} ", disp.PadLeft(2));
                }
                output += "|\n" + horzDiv;
            }
            return output;
        }

        // Functions to find shots on the board, at a specific point, or in a row or column, within a range
        public bool ShotAt(Point p)
        {
            return !(this[p]==Shot.None);
        }
        public bool isMissInColumn(int col, int rangeA, int rangeB)
        {
            for(int y=rangeA; y<=rangeB; ++y)
            {
                if (grid[col,y] == Shot.Miss)
                {
                    return true;
                }
            }
            return false;
        }
        public bool isMissInRow(int row, int rangeA, int rangeB)
        {
            for(int x=rangeA; x<=rangeB; ++x)
            {
                if (grid[x,row] == Shot.Miss)
                {
                    return true;
                }
            }
            return false;
        }
        protected Shot[,] grid;
        protected Size     size;
    }
}

এবং এখন যেহেতু আমি আমার এন্ট্রি জমা দিয়েছি, কিছু মোটামুটি পরিসংখ্যান: বনাম বিপি 7 44% জয় w / বনাম। ভয়ঙ্কর 20% জয়। / বনাম ফার্নসওয়ার্থ 42% জিতেছে। এটি একটি মজার প্রকল্প ছিল।
অ্যাবেলেঙ্কি

2

এটি মিনিম্যাক্স নয়। আসলে জাহাজ রাখার পরে, প্রতিটি খেলোয়াড় নিজে থেকে খেলতে পারবেন না, ফলে প্রতিটি প্রতিপক্ষের জাহাজটি ডুবতে তাকে বেশ কয়েকবার ঘুরিয়ে ফেলতে হয়েছিল? যেটি কম পাল্টে নিয়েছে সে জিতল।

আমি মনে করি না যে হিট জাহাজগুলি ডুবে যাওয়া এবং জাহাজগুলি যে কোনও জায়গায় লুকিয়ে থাকতে পারে তার অবশিষ্ট জায়গাগুলি কভার করার জন্য শটের সংখ্যা হ্রাস করার চেষ্টা করার বাইরে কোনও ভাল সাধারণ কৌশল আছে are

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


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

2
আমি দেখি. একই প্রতিপক্ষের বিরুদ্ধে পূর্বের গেমসের ডেটা ব্যবহার করা যে কেউ তার সাথে মানিয়ে নিতে সক্ষম হতে পারে?
ziggystar

2

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

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

সম্পাদনা: আমি আমার প্রাথমিক বিষয়টি প্রত্যাহার করি, যেহেতু আমি প্রতিযোগিতার নিয়মগুলি যথেষ্ট পরিমাণে পড়িনি read


সমস্ত সমাধান অবশ্যই সি # তে থাকা উচিত নয়। আমি একটি পৃথক সমাবেশ সংকলন করতে এবং লিঙ্ক-ইন করতে পারি। এছাড়াও, আপনার প্রতিপক্ষকে পরিসংখ্যানগতভাবে মোকাবেলা করতে সক্ষম হওয়া উচিত।
জন গীটজেন

জে #? হতে পারে? লোল, জে কে। আমার এটির জন্য একটি টিসিপি কাঠামো আছে তবে এই টুর্নামেন্টটি খুব দ্রুত চালানো দরকার।
জন গীটজেন

আপনি কেন ধরে নেবেন যে একই মেশিনে দুটি প্রক্রিয়ার মধ্যে টিসিপি যোগাযোগ খুব দ্রুতগতিতে হবে না?
ঝাড়িকো

@ ঝেরিকো: আমি যদি টিসিপি ব্যবহার করতাম তবে আমি ইঞ্জিনগুলি তাদের নিজস্ব পিসিতে বিচ্ছিন্ন করতাম যাতে তারা যে কোনও সিপিইউ সংস্থান ব্যবহার করতে পারে।
জন গীটজেন

তবুও, একই
লেনে

2

আমি সর্বদা মাঝখানে শুরু করতে এবং সেই পয়েন্টটি থেকে দূরে স্ফীতভাবে পছন্দ করি যে god গডডাম সাব হিসাবে অ্যাকাউন্টের জন্য অন্য কোনও পয়েন্টের মধ্যে 1 টির বেশি ফাঁকা জায়গা না রেখে ... শটগুলির মধ্যে স্থান নির্ভর করে যে জাহাজগুলি ডুবে ছিল on বি-শিপটি যদি শেষ ছিল তবে নষ্ট শটগুলি হ্রাস করতে শটগুলিকে কেবল 4 টি স্পেস ছেড়ে যেতে হত


1
তো ... আমাকে শুধু মাঝখান থেকে দূরে থাকা দরকার? :)
darron

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

1
যদি আপনি 3 বা 4 টি স্পেস ছেড়ে দিয়ে শুরু করেন তবে আপনি যেভাবেই হোক না কেন সাবকে আঘাত করতে যথেষ্ট ভাগ্যবান হতে পারেন। যদি তা না হয় তবে ফিরে যান এবং শূন্যস্থান পূরণ করার চেষ্টা করুন। আরও এখানে: somethinkodd.com/oddthinking/2009/10/29/battleship-strategy
অডডিংকিং

18
দুটি ছিদ্রযুক্ত জাহাজ কোনও গডম্যান সাব নয় , এটি গডম্যামন পিটি নৌকা । উপটি তিনটি গর্ত আছে। :)
রেভেন

2

ব্রিটিশ কম্পিউটার সোসাইটির পক্ষ থেকে দ্য ইউনিভার্সিটি অফ সেরে ডাঃ জেমস হিথার পরিচালিত অনুরূপ প্রতিযোগিতা ছিল।

সীমাবদ্ধতাগুলি সংস্থানগুলিতে রাখা হয়েছিল - প্রতি পালা প্রতি সর্বাধিক প্রসেসরের সময়, কোনও রাজ্য চলার মধ্যে সংরক্ষণ করা যায় নি, সর্বাধিক স্তূপের আকার চাপানো হয়েছে। সময় সীমাবদ্ধ করতে এআই সময় স্লটের মধ্যে যে কোনও বিন্দুতে একটি পদক্ষেপ জমা দিতে পারে এবং পালাটি সমাপ্ত হওয়ার পরে একটি পদক্ষেপের জন্য বলা হবে।

খুব আকর্ষণীয় - এখানে আরও দেখুন: http://www.bcsstudentcontest.com/

আপনাকে আরও কিছু ধারণা দিতে পারে।


2

যেমনটি হ'ল, সমাধানটি খোলে এবং উবুন্টু 9.10 লিনাক্সের মনোডেলফলে কোনও পরিবর্তন ছাড়াই চলে


1

তুমি লিখেছিলে:

  • প্রতিযোগিতার চেতনার বিরুদ্ধে বিবেচিত যে কোনও কিছুই অযোগ্যতার কারণ হবে be
  • প্রতিপক্ষের সাথে হস্তক্ষেপ করা প্রতিযোগিতার চেতনার পরিপন্থী।

দয়া করে "প্রতিযোগিতার চেতনার বিরুদ্ধে" এবং "প্রতিপক্ষের সাথে হস্তক্ষেপ" সংজ্ঞায়িত করবেন?

এছাড়াও - সরল করতে, আমি আপনাকে সুপারিশ করছি:

  • প্রতিপক্ষের সিপিইউ স্লট চলাকালীন সিপিইউ ব্যবহার করা নিষেধ করুন।
  • থ্রেডের সমান্তরালতাটিকে অস্বীকার করুন এবং এর পরিবর্তে একটি থ্রেডে আরও সিপিইউ সেকেন্ড দিন। এটি এআই এর প্রোগ্রামিংকে সহজ করবে এবং যে কোনওভাবেই সিপিইউ / মেমরি-সীমাবদ্ধ এমন কাউকে আঘাত করবে না।

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


আমি "হস্তক্ষেপ" বলার সময় আমার মনে প্রতিচ্ছবি ছিল। আমি চাই না প্রতিযোগীরা জিতুক কারণ তারা অন্য ইঞ্জিনকে মৃত্যুর দিকে বিড়ম্বনা করেছিল।
জন গিয়েজেন

8
আমি পরামর্শ দিয়েছিলাম যে গুপ্তচরবৃত্তি আধুনিক যুদ্ধের একটি গুরুত্বপূর্ণ অঙ্গ, তাই লক্ষ্যগুলি সন্ধানের প্রতিফলন আদর্শ হবে - সর্বোপরি, দ্বিতীয় বিশ্বযুদ্ধের সময় এটি অন্যতম একটি পদ্ধতি ছিল ...
রোল্যান্ড শ

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

6
আমি জানতাম না তাদের তখন প্রতিবিম্ব ছিল!
মার্কাস নিগবুর

1

আমি পূর্বাভাস দিয়েছি যে যে ব্যক্তি তার বিরোধীদের এলোমেলো বীজ এবং কল প্যাটার্নকে রিভার্সিং ইঞ্জিনিয়ার করতে পারে সে জিতবে।

যদিও এটি সম্ভব তা নিশ্চিত নয়।


বিরোধীদের কাছে সিএসপিআরএনজি ব্যবহারের বিকল্প রয়েছে।
জন গিয়েজেন

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

যখন আমি গবেষণা ইন্টার্নশিপের জন্য আবেদন করছিলাম, আমরা যুদ্ধের প্রোগ্রাম লিখেছিলাম এবং প্রতিযোগিতা করেছি। এলোমেলো বীজ স্থাপন করে ঠিক কীভাবে আমি এক্স জিতেছি)
P 0

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

1

এটি সম্ভবত, গেমটির বিভিন্নতা সহ এগুলির একটি সিরিজ চালানো সম্ভব হবে।

3 ডি প্লেনের মতো জিনিসগুলিতে যুক্ত করা বা কোনও বারের জন্য অঙ্কুর পরিবর্তে একটি একক জাহাজ চলাচল করতে সক্ষম হওয়া সম্ভবত গেমটি মোটামুটি কিছুটা বদলে দেবে।


2
"সালভো" প্রকরণ রয়েছে। যেখানে আপনি পালা হিসাবে যতগুলি শট শট করতে পারবেন আপনার যতটা জাহাজ বাকি রয়েছে।
জন গিয়েজেন

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

অন্য ভিন্নতা: বোর্ডের আকার + জাহাজের সংখ্যা হও।
রুশউ

1

এক দ্বিতীয় মোট খেলার সময় মেশিন নির্দিষ্ট specific টুর্নামেন্ট মেশিনের তুলনায় আমার মেশিনে দ্বিতীয়বারের মতো সিপিইউ অপারেশনগুলি ভিন্ন হবে। যদি আমি 1 সেকেন্ডের মধ্যে সর্বাধিক সিপিইউ সময়টি ব্যবহার করতে ব্যাটেল শিপ অ্যালগরিদমকে অনুকূল করে তুলি, তবে এটি একটি সম্ভাব্য ধীর টুর্নামেন্ট মেশিনে চালিত হয়, এটি সর্বদা হারাবে।

কাঠামোর এই সীমাবদ্ধতাটি কীভাবে ঘোরানো যায় তা সম্পর্কে আমি নিশ্চিত নই, তবে এটির দিকে নজর দেওয়া উচিত।

...

একটি ধারণা হ'ল এই প্রতিযোগিতায় যা করা হয়েছিল তা করা http://www.bcsstudentcontest.com /

সর্বাধিক মোট খেলার সময়ের বিপরীতে প্রতি ঘুরে প্রতি সর্বোচ্চ সময় পান। এইভাবে আমি অ্যালগরিদমগুলি জানার টার্নের সময়ের মধ্যে ফিট করতে সীমাবদ্ধ করতে পারি। একটি গেমটি 50 থেকে 600+ টার্ন অবধি স্থায়ী হতে পারে, যদি আমার অ্যালগরিদম তার মোট গেমের সময় পরিচালনা করে তবে এটি তার সেরা কাজটি করার জন্য যথেষ্ট সময় দিতে পারে না বা এটি খুব বেশি সময় দিতে এবং হারাতে পারে। ব্যাটলশিপ অ্যালগরিদমের মধ্যে মোট গেমের সময় পরিচালনা করা খুব কঠিন।

আমি নিয়মের পরিবর্তনের সময়টি মোট খেলার সময়কে সীমাবদ্ধ করার জন্য প্রস্তাব করব।

সম্পাদন করা

যদি আমি একটি অ্যালগরিদম লিখি যা সমস্ত সম্ভাব্য শটকে গণ্য করে এবং তারপরে তার তালিকান হয়, তবে সর্বোচ্চ র‌্যাঙ্কিংয়ের শটটি নেয়। সমস্ত সম্ভাব্য শট তৈরি করতে খুব বেশি সময় লাগবে, তাই আমি অ্যালগরিদমকে একটি নির্দিষ্ট সময়ের জন্য চালাতে দেব এবং তারপরে এটি বন্ধ করে দেব।

যদি কোনও টার্ন ভিত্তিক সীমা থাকে, আমি অ্যালগরিদমটি 0.9 সেকেন্ডের জন্য চালাতে এবং সর্বোচ্চ র‌্যাঙ্কিং শটটি ফিরিয়ে দিতে পারি, এবং টার্ন সময় সীমাটি ভালভাবেই চালিয়ে যেতে পারি।

আমি যদি এক সেকেন্ডের মোট গেম টাইমের মধ্যে সীমাবদ্ধ থাকি তবে প্রতিটি টার্নের জন্য অ্যালগরিদম কতক্ষণ চলতে হবে তা নির্ধারণ করা কঠিন। আমি আমার সিপিইউ সময় সর্বাধিক করতে চাই। যদি একটি গেম 500 রাউন্ড স্থায়ী হয় তবে আমি প্রতিটি পালা 0.002 সেকেন্ডে সীমাবদ্ধ করতে পারতাম, তবে কোনও গেম যদি 100 রাউন্ড স্থায়ী হয় তবে আমি প্রতিটি ঘুরিয়ে সিপিইউয়ের 0.01 সেকেন্ড সময় দিতে পারি।

অ্যালগরিদমের পক্ষে বর্তমান সীমাবদ্ধতার সাথে সেরা শটটি খুঁজে পেতে শট স্পেসের একটি অর্ধ-বিস্তৃত অনুসন্ধান ব্যবহার করা অবৈধ হবে।

সর্বমোট 1 সেকেন্ড গেম সময়টি সেই গেমটিতে প্রতিযোগিতায় কার্যকরভাবে ব্যবহার করা যেতে পারে এমন ধরণের অ্যালগোরিদমকে সীমাবদ্ধ করে দিচ্ছে।


এটি একটি ইন্টেল কিউ 9550 এসএক্স কোয়াড কোর, 8 জিবি র‌্যাম, ভিস্তা 64 মেশিনে চালিত হবে। 1 সেকেন্ড কি একটি সীমাবদ্ধ ফ্যাক্টর হতে চলেছে?
জন গিয়েজেন

আমি অনুমান করি যে আপনার সময়সীমার পরে শটগুলির সর্বাধিক # গণনা করার জন্য আপনার যুদ্ধযুদ্ধ এআই মাল্টিথ্রেড করা উচিত।
জেফ অ্যাটউড

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

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

আপনার আপনার বাকি সময়টি ট্র্যাক করা উচিত এবং এটি উপলব্ধ সময়ের বাকি 1/2 অংশে সীমাবদ্ধ রাখুন।
জন গীটজেন

1

আমি এখানে আসল কোড না রেখে কপি করছি - তবে আমি কিছু সাধারণ পর্যবেক্ষণকে ঝুঁকিপূর্ণ করব:

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

1

! [সম্ভাব্যতা ঘনত্ব] [1] তার চিত্রের বিবরণ প্রবেশ করান

! [চিত্রের বিবরণ এখানে লিখুন] [2]

আমি রেকর্ড শ্যুটিং বনাম বোবা শিকার / লক্ষ্য এবং পরিশেষে একটি পরিশীলিত অনুসন্ধানের ফলাফলের সাথে তুলনা করে পরীক্ষা করেছি।

সর্বোত্তম সমাধানটি সম্ভবত কোনও জাহাজের বাকী জাহাজ দ্বারা কীভাবে ব্যবহৃত হতে পারে তার সম্ভাব্যতা ঘনত্বের ফাংশন তৈরি করা এবং সর্বোচ্চ মান সহ বর্গক্ষেত্রের সাথে লক্ষ্য রেখে লক্ষ্য করা যায়।

আপনি এখানে আমার ফলাফলগুলি দেখতে পারেন এখানে লিঙ্কের বিবরণ প্রবেশ করুন


আপনি সম্ভবত আপনার উত্তর এবং বিশেষত আপনার চিত্র এবং লিঙ্কটি ঠিক করতে পারেন?
বার্ট

-2

"যুদ্ধ" একটি ক্লাসিক কম্পিউটার বিজ্ঞান এনপি-সম্পূর্ণ সমস্যা হিসাবে পরিচিত।

http://en.wikipedia.org/wiki/List_of_NP-complete_problems

(যুদ্ধের সন্ধান করুন - এটি সেখানে, গেমস এবং ধাঁধাতে)


4
যা যুদ্ধক্ষেত্রের ধাঁধা ( এন.ইউইকিপিডিয়া.org / উইকি / ব্যাটলশীপ_জেপজল) ), ব্যাটলশিপ গেম নয় ( এন.ইউইউইকিপিডিয়া / উইকি / ব্যাটলশিপ_জেগেম ) )।
জেসন বারকান 19

হ্যাঁ, জেসন যেমন বলেছে এটি সম্পূর্ণ ভিন্ন প্রাণী।
জন গিয়েজেন

3
Hehehe। পরবর্তী কাজটি আমি কাজে নেমেছি আমি এটি এনপি-সম্পূর্ণ বলে যাচ্ছি, তারপরে দীর্ঘ দুপুরের খাবার খান। :-)
বার্ক ব্লাট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.