سؤال

سفينة حربية!

في عام 2003 (عندما كان عمري 17 عاما) ، وتنافس في سفينة حربية منظمة العفو الدولية الترميز المنافسة.على الرغم من أنني فقدت تلك البطولة, كان لدي الكثير من المرح و تعلمت الكثير من ذلك.

الآن أود أن إحياء هذه المسابقة في البحث عن أفضل حربية منظمة العفو الدولية.

هنا إطار, الآن استضافتها على Bitbucket.

وسيتم منح الفائز +450 سمعة! وستعقد المسابقة ابتداء من 17 نوفمبر 2009.لا توجد إدخالات أو التعديلات في وقت لاحق من ساعة الصفر على 17 سوف تكون مقبولة.(التوقيت المركزي) تقديم الإدخالات الخاصة بك في وقت مبكر ، حتى لا تفوت فرصتك!

للحفاظ على هذا الهدف, يرجى اتباع روح المنافسة.

قواعد اللعبة:

  1. اللعبة يمكن أن تقوم على 10x10.
  2. كل منافس سيتم وضع كل من 5 سفن (من الأطوال 2, 3, 3, 4, 5) على الشبكة الخاصة بهم.
  3. أي السفن قد تتداخل ، ولكنها قد تكون مجاورة.
  4. المنافسين ثم يتناوبون إطلاق النار لقطات واحدة في الخصم.
    • الاختلاف على اللعبة تسمح بإطلاق عدة طلقات في تسديدة واحدة لكل سفينة النجاة.
  5. الخصم سوف يخطر المنافس اذا كان اطلاق النار المصارف, يضرب, أو يخطئ.
  6. تلعب لعبة ينتهي عند جميع السفن من أي لاعب واحد هي غرقت.

قواعد المسابقة:

  1. روح المنافسة لتجد أفضل حربية الخوارزمية.
  2. أي شيء يعتبر ضد روح المنافسة سوف تكون أسباب عدم الأهلية.
  3. التدخل مع الخصم هو ضد روح المنافسة.
  4. خاصية تعدد يمكن استخدامها في ظل القيود التالية:
    • أي أكثر من موضوع واحد قد تكون قيد التشغيل في حين أنه ليس دورك.(على الرغم من أي عدد من المواضيع قد يكون في الدولة "علق").
    • أي موضوع قد تشغيل في أولوية أخرى من "طبيعية".
    • بالنظر إلى اثنين من فوق القيود ، سوف تكون مضمونة على الأقل 3 مخصصة النوى وحدة المعالجة المركزية خلال دورك.
  5. حدود 1 في الثانية من الوقت وحدة المعالجة المركزية في المباراة الواحدة المخصص لكل منافس على ترابط الأساسي.
  6. الوقت ينفد النتائج في فقدان اللعبة الحالية.
  7. أي استثناء غير معالج سوف يؤدي إلى فقدان اللعبة الحالية.
  8. الوصول إلى شبكة الاتصال الوصول إلى القرص مسموح ، ولكن قد تجد الوقت القيود إلى حد ما الباهظة.لكن, عدد قليل من انشاء المسيل للدموع لأسفل أساليب قد أضيفت لتخفيف الوقت يصفى.
  9. يجب أن يكون الكود نشر على تجاوز سعة المكدس كما جوابا ، أو ، إذا كان كبيرا جدا ، مرتبطة.
  10. ماكس حجم إجمالي (غير مضغوط) من الدخول هو 1 ميغابايت.
  11. رسميا .Net 2.0 / 3.5 هو الإطار الوحيد شرط.
  12. الدخول الخاص بك يجب أن تنفذ IBattleshipOpponent واجهة.

التهديف:

  1. أفضل 51 مباراة من أصل 101 مباراة هو الفائز في المباراة.
  2. جميع المنافسين سوف تلعب يقابل بعضهم ضد البعض الآخر ، جولة روبن النمط.
  3. أفضل نصف المنافسين ثم لعب مزدوج البطولة القضاء لتحديد الفائز.(أصغر الطاقة من اثنين من أكبر من أو يساوي نصف في الواقع.)
  4. سوف تكون باستخدام TournamentApi في إطار البطولة.
  5. وسوف يتم نشر النتائج هنا.
  6. إذا قمت بتقديم أكثر من إدخال واحد فقط أفضل-سجل دخول مؤهلة مزدوجة-إيليم.

حظا سعيدا!وقد متعة!


تعديل 1:
شكرا تحررت, الذي وجد خطأ في Ship.IsValid وظيفة.تم إصلاح ذلك.يرجى تحميل آخر نسخة من الإطار.

تحرير 2:
حيث كان هناك اهتمام كبير في استمرار احصائيات القرص مثل هذا, يجب إضافة قليل من غير توقيت انشاء المسيل للدموع لأسفل الأحداث التي ينبغي أن توفر الوظائف المطلوبة.هذا هو شبه كسر تغيير.وهذا هو القول:واجهة تم تعديل لإضافة وظائف ، ولكن ليس الجسد هو مطلوب بالنسبة لهم.يرجى تحميل آخر نسخة من الإطار.

تحرير 3:
Bug Fix 1: GameWon و GameLost كنت فقط الحصول على ما يسمى في حالة الوقت.
علة فيكس 2:إذا كان المحرك هو توقيت كل لعبة المنافسة لن تنتهي أبدا.
يرجى تحميل آخر نسخة من الإطار.

تحرير 4:
نتائج بطولة:

هل كانت مفيدة؟

المحلول

أنا ثاني الحركة أن تفعل الكثير من الألعاب في المباراة الواحدة.القيام 50 مباراة فقط الضغط على العملة.أنا في حاجة إلى القيام 1000 ألعاب للحصول على أي تمييز بين اختبار الخوارزميات.

تحميل المدرعة البحرية 1.2.

الاستراتيجيات:

  • تتبع جميع المواقف المحتملة بالنسبة للسفن التي >0 الفعالية.القائمة لم يحصل أكبر من ~30K لذلك يمكن أن يوضع بالضبط ، على عكس قائمة من جميع المناصب الممكنة لجميع السفن (التي هي كبيرة جدا).

  • على GetShot الخوارزمية إلى قسمين, واحد الذي يولد لقطات عشوائية وغيرها من التي يحاول الانتهاء من غرق بالفعل ضرب السفينة.نقوم لقطات عشوائية إذا كان هناك موقف من الممكن (من القائمة أعلاه) في كل ضرب من السفن غرقت.وإلا فإننا في محاولة لإنهاء غرق سفينة خلال اختيار موقع إطلاق النار الذي يلغي معظم المواقف المحتملة (مرجح).

  • من أجل لقطات عشوائية ، تحسب أفضل موقع لإطلاق النار على أساس احتمال واحد من unsunk السفن تداخل الموقع.

  • التكيف خوارزمية والتي أماكن السفن في مواقع حيث يتم الخصم إحصائيا أقل عرضة النار.

  • التكيف الخوارزمية التي يفضل النار على مواقع الخصم إحصائيا أكثر عرضة مكان له السفن.

  • مكان السفن في الغالب لا تلامس بعضها البعض.

نصائح أخرى

هنا هو بلدي الدخول!(ساذج آخر حل ممكن)

"عشوائية 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() { }
    }
}

وهنا الخصم للناس للعب ضد:

بدلا من استخدام ثابت الهندسة مستوحاة من استراتيجية اعتقدت أنه سيكون من المثير للاهتمام أن محاولة تقدير الاحتمالات الكامنة أن أي غير مستكشفة الفضاء يحمل السفينة.

للقيام بذلك الحق ، كنت استكشاف جميع التشكيلات الممكنة من السفن التي تناسب العرض الحالي من العالم ، ومن ثم حساب الاحتمالات استنادا إلى تلك التشكيلات.يمكنك التفكير في الأمر مثل استكشاف شجرة:

توسيع ممكن حربية الدول http://natekohl.net/media/battleship-tree.png

بعد النظر في جميع أوراق تلك الشجرة التي رقص الجاز مع ما تعرفه عن العالم (مثلا ، السفن لا يمكن أن تتداخل كل ضرب المربعات يجب أن تكون السفن, الخ.) يمكنك الاعتماد كيف في كثير من الأحيان السفن تحدث في كل مستكشفة يمكنها من تقدير احتمال أن السفينة يجلس هناك.

هذا يمكن تصور مثل خريطة الحرارة ، حيث النقاط الساخنة من المرجح أن تحتوي على السفن:

خريطة الحرارة الاحتمالات لكل موقف غير مستكشفة http://natekohl.net/media/battleship-probs.png

شيء واحد أنا أحب حول هذا حربية المنافسة هو أن الشجرة أعلاه هو تقريبا صغيرة بما يكفي أن القوة الغاشمة هذا النوع من الخوارزمية.إذا كان هناك ~150 المواقف المحتملة لكل من 5 السفن ، 1505 = 75 مليار الاحتمالات.وهذا العدد فقط يحصل أصغر ، خاصة إذا كان يمكنك القضاء على كل السفن.

الخصم أنني مرتبطة أعلاه لا استكشاف كل شجرة ؛ 75 مليار دولار لا تزال كبيرة للوصول في أقل من ثانية.لا تحاول تقدير هذه الاحتمالات مع مساعدة من عدد قليل من الاستدلال.

غير مكتملة الإجابة ولكن يبدو أن هناك نقطة صغيرة التبعثر إجابات حقيقية مع البرمجية الشائعة.لذا نقدم بعض ملحقات/دروس عامة في روح مفتوحة المصدر.إذا كنت تستخدم هذه ثم الرجاء تغيير الاسم أو محاولة تجميع كل شيء في واحد dll لن ينجح.

BoardView يتيح لك العمل بسهولة مع مشروحة المجلس.

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

ليس لدي وقت الآن إلى كتابة كاملة الخوارزمية ، ولكن هنا الفكر:إذا كان الخصم الخاص بك في وضع السفن بشكل عشوائي ، ألن وضع الاحتمالات تكون بسيطة توزيع تركزت في (5.5,5.5)?على سبيل المثال ، وضع إمكانيات حربية (5 وحدات طويلة) في البعد x هنا:

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

ومن الواضح أن بعض العشوائية سوف تحتاج إلى أن تضاف إلى هذه الفكرة ، ولكن أعتقد أن رياضيا بحت وهذا هو الطريق للذهاب.

لا شيء متطورة ولكن هيريس ما جئت حتى مع.انه يتفوق على الخصم عشوائي 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() { }
    }
}

قليلا المكثف اتخاذ الحد الأدنى من المساحة هنا و لا تزال قابلة للقراءة.

بعض تعليقات حول المنافسة المحرك:

NewGame المعلمات:

إذا IBattleshipOpponent::NewGame المقصود الإعداد قبل المباراة ويأخذ boardsize ، فإنه ينبغي أيضا أن قائمة السفن و أحجام كل منها.فإنه من غير المنطقي أن تسمح متغير مجلس الحجم دون السماح متغير السفينة تكوينات.

السفن وختم:

أنا لا أرى أي سبب لماذا الدرجة السفينة مختومة.من بين غيرها من الأمور الأساسية ، أود السفن أن يكون له اسم ، لذا يمكن إخراج الرسائل مثل ("أنت غرقت بلدي {0}", السفينة.اسم) ؛ .لدي ملحقات أخرى في الاعتبار أيضا ، لذلك أعتقد أن السفينة يجب أن تكون القابلة للتوريث.

حدود زمنية:

في حين أن المهلة الثانية 1 المنطقي البطولة القاعدة مجرمي مع التصحيح.BattleshipCompetition يجب أن يكون الإعداد السهل تجاهل الوقت انتهاكات للمساعدة الإنمائية/التصحيح.أود أن أقترح أيضا التحقيق في النظام.تشخيص.العملية::UserProcessorTime / متميز ProcessorTime / TotalProcessorTime أكثر دقة عرض من كم من الوقت يتم استخدامه.

غرقت السفن:

الحالي API يعلمك عندما كنت قد غرقت وهي oppenent السفينة:

ShotHit(Point shot, bool sunk);

ولكن ليس التي السفينة غرقت!أنا أعتبر أنه جزء من الإنسان حربية القواعد التي يطلب منك التصريح "غرقت سفينة حربية بلدي!" (أو المدمرة ، أو دون ، وما إلى ذلك).

هذا أمر بالغ الأهمية خصوصا عند منظمة العفو الدولية تحاول طرد السفن التي بعقب ضد بعضها البعض.أود طلب API التغيير إلى:

ShotHit(Point shot, Ship ship);

إذا السفينة هو غير فارغة ، فإنه يعني أن الطلقة قد غرق بالرصاص ، و يمكنك أن تعرف أي سفينة غرقت ، متى كان.اذا كان اطلاق النار كان غير غرق النار, ثم السفينة فارغة و لا يوجد لديك مزيد من المعلومات.

تبادل لاطلاق النار تحديث.وأنا أعلم أنه لا يمكن أن تتنافس مع فارنسورث أو المدرعة البحرية لكنه أسرع بكثير من هذا الأخير و بسيطة للعب مع في حالة أي شخص يريد أن يحاول.هذا يعتمد على الحالة الراهنة من المكتبات المضمنة هنا أن تجعل من السهل استخدام.

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

}

هذا هو أفضل ما يمكن أن تضع معا في وقت فراغي ، وهي عبارة عن غير موجودة.هناك بعض لعبة المباراة فرز احصائيات يحدث ، حيث أقوم بإعداد الوظيفة الرئيسية إلى حلقة باستمرار تشغيل BattleshipCompetition حتى ضغطت مفتاح.

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

هذا المنطق هو الأقرب أنه علي أن ضرب المدرعة البحرية الفوز حوالي 41% من الألعاب الفردية.(في الحقيقة لم الفوز في مباراة واحدة من قبل عدد من 52 49.) ومن الغريب أن هذه الفئة لا تفعل كذلك ضد FarnsworthOpponent مثل الإصدار السابق الذي كان أقل بكثير المتقدمة.

جهاز الكمبيوتر يتم إصلاحه من قبل dell الآن ولكن هذا هو المكان الذي كنت في الأسبوع الماضي:

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

إذا كنت الغاشمة مما اضطر التحليل الخاص بك ثم قد تجد اليات الموردة RandomOpponent غير فعالة.انها تسمح لنفسها بالفعل تحديد المواقع المستهدفة ويتيح إطار القوة إلى تكرار حتى كان يضرب واحد لم تطرق بعد أو الرشاشات في نقل تنتهي.

هذا الخصم لديه سلوك مماثل (وضع الفعال التوزيع هو نفسه) لا مجرد العقل التحقق من نفسها فقط يستهلك واحدة توليد رقم عشوائي لكل دعوة (المطفأة)).

هذا يستخدم دروس في ملحقات/مكتبة الإجابة وأنا فقط توفير الوسائل الرئيسية/الدولة.

خلط ورق اللعب هو رفع من جون السكيت الجواب هنا

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 
}

أنا لن تكون قادرة على المشاركة, ولكن هنا هو خوارزمية كنت تنفذ إذا كان لدي الوقت:

الأولى عندما كشف ضرب لا متابعة بقية السفينة على الفور - بناء جدول السفينة المواقع و معرفة ما إذا كنت قد ضرب كل خمسة مرة واحدة على الأقل قبل البدء في الحوض بالكامل لهم.(لاحظ أن هذا هو سوء سياسة متعددة تسديدة البديل - انظر التعليقات)

  1. ضرب مركز (انظر الملاحظة أدناه - 'center' هو مجرد الراحة الوصف)
  2. ضرب بقعة 4 إلى اليمين من مركز
  3. ضرب بقعة 1 أسفل من مركز
  4. ضرب بقعة أربعة إلى اليمين من ضرب السابقة
  5. الاستمرار في هذا النمط (يجب أن ينتهي مع الخطوط القطرية مفصولة 3 مساحات ملء المجلس) هذا يجب ضرب كل 4 و 5 طول قوارب إحصائيا كبيرة عدد 3 و 2 القوارب.

  6. بدء يضرب عشوائيا البقع المنتصف الأقطار ، وهذا سوف قبض على 2 و 3 طول القوارب التي لم تكن قد لاحظت.

مرة واحدة وقد تم الكشف عن 5 إصابات ، أود أن تحديد ما إذا كان 5 يضرب على فصل القوارب.هذا هو السهل نسبيا خلال جعل بضع طلقات بالقرب من المواقع التي ضربتين على نفس خط أفقي أو عمودي و على مسافة 5 مواقع من بعضها البعض (قد تكون ضربتين في نفس القارب).إذا كانت منفصلة القوارب ثم الاستمرار تغرق جميع السفن.إذا وجدوا أن نفس القارب ، مواصلة التعبئة أنماط أعلاه حتى 5 قوارب تقع.

هذه الخوارزمية بسيطة ملء الخوارزمية.السمات الرئيسية هي أنه لا تضيع الوقت في غرق السفن يعرف عندما لا يزال هناك سفن انها علم و لا استخدام غير فعال ملء نمط (أي تماما نمط عشوائي سيكون الإسراف).

ملاحظات أخيرة:

أ) "Center" عشوائية نقطة الانطلاق على متن الطائرة.هذا يلغي ضعف الأساسي من هذه الخوارزمية.ب) في حين وصف يشير الرسم الأقطار فورا من البداية ، من الناحية المثالية الخوارزمية مجرد يطلق النار على "عشوائية" مواقع على طول تلك الأقطار.هذا يساعد على منع المنافس من توقيت كيف يمر وقت طويل حتى سفنهم ضرب من أنماط يمكن التنبؤ بها.

يصف هذا "الكمال" خوارزمية في أنه سوف تحصل على جميع السفن في إطار (9x9)/2+10 طلقات.

ومع ذلك ، فإنه يمكن أن تحسن بشكل كبير:

مرة واحدة في السفينة هو ضرب وتحديد حجمها قبل القيام 'الداخلية' الخطوط القطرية.كنت قد وجدت 2 السفينة ، وفي هذه الحالة الداخلية الأقطار يمكن أن تكون مبسطة إلى العثور على 3 حجم السفن بسرعة أكبر.

تحديد المراحل في اللعبة والتصرف وفقا لذلك.هذه الخوارزمية قد تكون جيدة تصل إلى نقطة معينة في اللعبة ، ولكن خوارزميات أخرى قد تسفر عن أفضل الفوائد كجزء من المرحلة النهائية.أيضا ، إذا كان لاعب آخر قريب جدا من هزيمة لك خوارزمية أخرى قد تعمل على نحو أفضل - على سبيل المثال مخاطر عالية الخوارزمية قد تفشل في كثير من الأحيان, ولكن عندما يعمل يعمل بسرعة و قد تغلب على خصمك الذي هو أقرب إلى الفوز من أنت.

تحديد أسلوب اللعب من منافس - قد تعطيك أدلة على كيفية التخطيط وضع السفينة (أي هناك احتمالات جيدة أن بأنفسهم خوارزمية بسرعة أكثر يحدد كيفية وضع السفن الخاصة - إذا كانت الأداة الوحيدة لديك هي مطرقة ، كل شيء يبدو وكأنه مسمار)

-آدم

دخول بلدي.

شيء رهيب خاصة, و لم أحصل على الوقت لإضافة جميع الأفكار الجيدة لدي.

ولكن يبدو أن اللعب بشكل جيد إلى حد ما.سنرى كيف يفعل في المنافسة:

(ضع هذا الملف 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;
    }
}

هذا ليس minimax.في الواقع بعد وضع السفن لا يمكن كل لاعب يلعب لوحده ، مما أسفر عن عدد من المنعطفات استغرق منه أن تغرق كل معارض السفينة ؟ الذي استغرق أقل يتحول انتصارات.

لا أعتقد أن هناك أي جيد العامة استراتيجيات ما وراء غرق ضرب السفن في محاولة للحد من عدد من الطلقات لتغطية ما تبقى من الممكن أماكن السفن قد تخفي.

بالطبع قد تكون هناك مكافحة استراتيجيات من أجل أي شيء هذا ليس عشوائي.ولكن لا أعتقد أن هناك استراتيجيات جيدة ضد جميع اللاعبين ممكن.

في الواقع, أعتقد أن أكبر مشكلة مع هذا اللغز هو أن أساسا اثنين من التحركات.خطوة واحدة يتم وضع السفن الخاصة بك ، والآخر هو العثور على سفن العدو (غير مجزأة أن الجزء الثاني قد يكون جانبا من محاولة للتغلب على مدار الساعة مع عامل عشوائي فقط 'تشغيل خوارزمية الخاص بك').لا يوجد آلية في محاولة لتحديد ومن ثم مواجهة عدو استراتيجية ، وهو ما يجعل مسابقات مماثلة حول جولات متعاقبة من "الصخرة ورقة مقص" مثيرة جدا للاهتمام.

أيضا, أعتقد أنه سيكون أكثر برودة إذا حددت اللعبة كما بروتوكول شبكة الاتصال ومن ثم توفير إطار تنفيذ هذا البروتوكول في C#, بدلا من أن تملي أن كل الحلول يجب أن تكون C#, ولكن هذا مجرد رأيي.

تحرير:أنا إلغاء النقطة الأولى, منذ أنا لم أقرأ قواعد المنافسة بعناية كافية.

أنا دائما أحب أن تنطلق في منتصف المتصاعد من أن نقطة واحدة دون ترك أي أكثر من 1 مساحة فارغة بين أي نقطة على حساب لهذه العينة الفرعية...الفضاء بين الطلقات كانت تعتمد على السفن التي غرقت.إذا كان B-السفينة الماضي ، طلقات فقط إلى ترك 4 مسافات بين للتقليل من إهدار طلقات

كان هناك مسابقة مماثلة تديرها الدكتور جيمس هيذر من جامعة سري باسم جمعية الكمبيوتر البريطانية.

وضعت قيود على الموارد - وهي أقصى وقت المعالج في المقابل لا يمكن لدولة أن تكون مخزنة بين الحركات أقصى حجم كومة الذاكرة المؤقتة المفروضة.للحد من الوقت منظمة العفو الدولية أن تقدم خطوة في أي نقطة داخل فتحة الوقت و سوف يطلب منك التحرك عند إنهاء تشغيل.

مثيرة جدا للاهتمام - انظر المزيد في: http://www.bcsstudentcontest.com/

قد تعطيك بعض الأفكار.

كما هو الحل يفتح ويعمل مع أي تعديل في monodevelop في أوبونتو 9.10 لينكس

كتبت:

  • أي شيء يعتبر ضد روح المنافسة سوف تكون أسباب عدم الأهلية.
  • التدخل مع الخصم هو ضد روح المنافسة.

يرجى تحديد "ضد روح المنافسة" و "التدخل مع الخصم"?

أيضا إلى تبسيط ، أوصي بأن عليك:

  • عدم السماح باستخدام وحدة المعالجة المركزية على الإطلاق خلال الخصم فتحة وحدة المعالجة المركزية.
  • عدم السماح موضوع التوازي وبدلا من إعطاء المزيد من وحدة المعالجة المركزية ثانية على موضوع واحد.وهذا تبسيط البرمجة من منظمة العفو الدولية و لن يؤذي أحدا من وحدة المعالجة المركزية/الذاكرة-لا بد على كل حال.

PS - سؤال CS مرحلة ما بعد الدكتوراه الكامنة هنا:أليست هذه لعبة قابلة للحل (أيهل هناك واحد أفضل استراتيجية؟).نعم, حجم مجلس الإدارة و عدد من الخطوات يجعل minimax وآخرون إلزامية, ولكن لا يزال لدي لنتساءل...انها أبعد ما تكون من الذهاب الشطرنج في التعقيد.

أتوقع أن الشخص الذي تمكن من عكس مهندس خصومهم عشوائي و دعوة نمط الفوز.

لا أدري كيف يحتمل هذا على الرغم من.

كما يفترض يكون من الممكن تشغيل سلسلة من هذه الاختلافات في اللعبة.

مضيفا في أشياء مثل 3d الطائرة أو أن تكون قادرة على التحرك سفينة واحدة بدلا من إطلاق النار بدوره ربما يغير اللعبة عادلة قليلا.

واحد ثاني مجموع لعبة الوقت هو آلة محددة.مرة ثانية يستحق من عمليات وحدة المعالجة المركزية سوف تكون مختلفة على الجهاز مقارنة البطولة آلة.إذا كنت تحسين معركة السفينة خوارزمية للاستفادة القصوى من الوقت وحدة المعالجة المركزية في حدود 1 في الثانية ، ثم يتم تشغيله على احتمال تباطؤ البطولة سوف تخسر دائما.

أنا غير متأكد حول كيفية الحصول على هذا الحد من الإطار ، ولكن ينبغي أن تعالج.

...

فكرة واحدة هي أن تفعل ما فعلت في هذه المسابقة http://www.bcsstudentcontest.com/

و أقصى قدر من الوقت في المقابل بدلا من الحد الأقصى لإجمالي لعبة الوقت.هذه الطريقة لا يمكن أن تحد من خوارزميات لتناسب داخل يعرفون أن تتحول الوقت.لعبة قد تستمر 50 إلى 600+ المنعطفات ، إذا خوارزمية يدير إجمالي لعبة الوقت, قد لا تعطي ما يكفي من الوقت للقيام بأفضل عمل أو أنها يمكن أن تعطي الكثير من الوقت و تخسر.فمن الصعب جدا لإدارة إجمالي لعبة الوقت داخل حربية الخوارزمية.

أود أن أقترح تغيير قواعد للحد من تحويل الوقت ليس مجموع زمن المباراة.

تحرير

إذا كتبت خوارزمية أن يعدد جميع الطلقات ممكن ثم رتب لهم ، ثم يأخذ أعلى مرتبة من النار.الأمر سيستغرق وقتا طويلا لتوليد جميع الطلقات ممكن, لذلك أود أن السماح خوارزمية تشغيل لفترة معينة من الوقت ثم توقف.

إذا كان هناك تقوم بدورها الحد ، اسمحوا لي أن الخوارزمية تشغيل 0.9 ثانية والعودة أعلى مرتبة النار ، وتكون withing بدوره المهلة.

إذا أنا تقتصر على مجموع الوقت لعبة ثانية واحدة, وسوف يكون من الصعب تحديد متى الخوارزمية يجب تشغيل كل منعطف.سوف ترغب في أقصى بلدي وحدة المعالجة المركزية في الوقت.إذا استمرت لعبة 500 الجولة لا يمكن أن يحد كل بدوره إلى 0.002 ثانية ، ولكن إذا استمرت لعبة 100 طلقة بوسعي أن أعطي كل بدوره 0.01 ثانية من الوقت وحدة المعالجة المركزية.

سيكون غير عملي على خوارزمية استخدام شبه شاملة البحث من النار الفضاء للعثور على أفضل لقطة مع الحد الحالي.

الثاني 1 المجموع لعبة الوقت هو الحد نوع من الخوارزميات التي يمكن استخدامها بشكل فعال للتنافس في اللعبة.

أنا بتوثيقه هنا لا نضع الرمز الفعلي في - ولكن سوف خطرا على بعض الملاحظات العامة:

  • لأن جميع السفن على الأقل 2 الخلايا في الحجم ، يمكنك استخدام الأمثل رأيت على تنفيذ اللعبة في الفضاء كويست V - الذي أطلق في بديل الخلايا في نمط الماس في حين أنها "تسعى" هدفا.هذا يلغي نصف الساحات, في حين لا يزال ضمان أن سوف تجد جميع السفن في نهاية المطاف.
  • عشوائي نمط الإطلاق عندما تسعى أهداف إحصائيا سوف تسفر عن نتائج أفضل على العديد من الألعاب.

![كثافة الاحتمال][1]أدخل وصف الصورة لها

![أدخل وصف الصورة هنا][2]

أنا جربت مع مقارنة نتائج randon اطلاق النار مقابل غبي هانت/الهدف و أخيرا بحث متطورة.

أفضل حل يبدو لخلق كثافة الاحتمال وظيفة كيف يحتمل أي فرد مربع يستخدم من قبل باقي السفن ، والهدف مع مربع مع أعلى قيمة.

يمكنك أن ترى النتائج هنا أدخل رابط الوصف هنا

"سفينة حربية" هو ما يعرف باسم الكلاسيكية علوم الكمبيوتر NP-complete المشكلة.

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

(ابحث عن سفينة حربية - إنه هناك تحت الألعاب والألغاز)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top