using System;
using System.Linq;

namespace Battle
{
    public class Game
    {
        private int[,] field = new int[7, 7];

        private Random random = new Random();

        public void Run()
        {
            DisplayIntro();

            while (true)
            {
                field = new int[7, 7];

                foreach (var shipType in new []{ 1, 2, 3})
                {
                    foreach (var ship in new int[] { 1, 2 })
                    {
                        while (!SetShip(shipType, ship)) { }
                    }
                }

                UserInteraction();
            }
        }

        private bool SetShip(int shipType, int shipNum)
        {
            var shipSize = 4 - shipType;
            int direction;
            int[] A = new int[5];
            int[] B = new int[5];
            int row, col;

            do
            {
                row = Rnd(6) + 1;
                col = Rnd(6) + 1;
                direction = Rnd(4) + 1;
            } while (field[row, col] > 0);

            var M = 0;

            switch (direction)
            {
                case 1:
                    B[1] = col;
                    B[2] = 7;
                    B[3] = 7;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        if (!(M > 1 || B[K] == 6 || field[row, B[K] + 1] > 0))
                        {
                            B[K + 1] = B[K] + 1;
                            continue;
                        }

                        M = 2;
                        var Z = 1;

                        if (B[1] < B[2] && B[1] < B[3]) Z = B[1];
                        if (B[2] < B[1] && B[2] < B[3]) Z = B[2];
                        if (B[3] < B[1] && B[3] < B[2]) Z = B[3];

                        if (Z == 1 || field[row, Z - 1] > 0) return false;

                        B[K + 1] = Z - 1;
                    }

                    field[row, col] = 9 - 2 * shipType - shipNum;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        field[row, B[K + 1]] = field[row, col];
                    }
                    break;

                case 2:
                    A[1] = row;
                    B[1] = col;
                    A[2] = 0;
                    A[3] = 0;
                    B[2] = 0;
                    B[3] = 0;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        if (!(M > 1
                            || A[K] == 1 || B[K] == 1
                            || field[A[K] - 1, B[K] - 1] > 0
                            || (field[A[K] - 1, B[K]] > 0 && field[A[K] - 1, B[K]] == field[A[K], B[K] - 1])))
                        {
                            A[K + 1] = A[K] - 1;
                            B[K + 1] = B[K] - 1;
                            continue;
                        }

                        M = 2;
                        var Z1 = 1;
                        var Z2 = 1;

                        if (A[1] > A[2] && A[1] > A[3]) Z1 = A[1];
                        if (A[2] > A[1] && A[2] > A[3]) Z1 = A[2];
                        if (A[3] > A[1] && A[3] > A[2]) Z1 = A[3];
                        if (B[1] > B[2] && B[1] > B[3]) Z2 = B[1];
                        if (B[2] > B[1] && B[2] > B[3]) Z2 = B[2];
                        if (B[3] > B[1] && B[3] > B[2]) Z2 = B[3];

                        if (Z1 == 6 || Z2 == 6
                            || field[Z1 + 1, Z2 + 1] > 0
                            || (field[Z1, Z2 + 1] > 0 && field[Z1, Z2 + 1] == field[Z1 + 1, Z2])) return false;

                        A[K + 1] = Z1 + 1;
                        B[K + 1] = Z2 + 1;
                    }

                    field[row, col] = 9 - 2 * shipType - shipNum;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        field[A[K + 1], B[K + 1]] = field[row, col];
                    }
                    break;

                case 3:
                    A[1] = row;
                    A[2] = 7;
                    A[3] = 7;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        if (!(M > 1 || A[K] == 6
                            || field[A[K] + 1, col] > 0))
                        {
                            A[K + 1] = A[K] + 1;
                            continue;
                        }

                        M = 2;
                        var Z = 1;

                        if (A[1] < A[2] && A[1] < A[3]) Z = A[1];
                        if (A[2] < A[1] && A[2] < A[3]) Z = A[2];
                        if (A[3] < A[1] && A[3] < A[2]) Z = A[3];

                        if (Z == 1 || field[Z - 1, col] > 0) return false;

                        A[K + 1] = Z - 1;
                    }

                    field[row, col] = 9 - 2 * shipType - shipNum;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        field[A[K + 1], col] = field[row, col];
                    }
                    break;

                case 4:
                default:
                    A[1] = row;
                    B[1] = col;
                    A[2] = 7;
                    A[3] = 7;
                    B[2] = 0;
                    B[3] = 0;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        if (!(M > 1 || A[K] == 6 || B[K] == 1
                            || field[A[K] + 1, B[K] - 1] > 0
                            || (field[A[K] + 1, B[K]] > 0 && field[A[K] + 1, B[K]] == field[A[K], B[K] - 1])))
                        {
                            A[K + 1] = A[K] + 1;
                            B[K + 1] = B[K] - 1;
                            continue;
                        }

                        M = 2;
                        var Z1 = 1;
                        var Z2 = 1;

                        if (A[1] < A[2] && A[1] < A[3]) Z1 = A[1];
                        if (A[2] < A[1] && A[2] < A[3]) Z1 = A[2];
                        if (A[3] < A[1] && A[3] < A[2]) Z1 = A[3];
                        if (B[1] > B[2] && B[1] > B[3]) Z2 = B[1];
                        if (B[2] > B[1] && B[2] > B[3]) Z2 = B[2];
                        if (B[3] > B[1] && B[3] > B[2]) Z2 = B[3];

                        if (Z1 == 1 || Z2 == 6
                            || field[Z1 - 1, Z2 + 1] > 0
                            || (field[Z1, Z2 + 1] > 0 && field[Z1, Z2 + 1] == field[Z1 - 1, Z2])) return false;

                        A[K + 1] = Z1 - 1;
                        B[K + 1] = Z2 + 1;
                    }

                    field[row, col] = 9 - 2 * shipType - shipNum;

                    for (var K = 1; K <= shipSize; K++)
                    {
                        field[A[K + 1], B[K + 1]] = field[row, col];
                    }

                    break;
            }

            return true;
        }

        public void DisplayIntro()
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Print(Tab(33) + "BATTLE");
            Print(Tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
            //-- BATTLE WRITTEN BY RAY WESTERGARD  10 / 70
            // COPYRIGHT 1971 BY THE REGENTS OF THE UNIV.OF CALIF.
            // PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY
        }

        public void UserInteraction()
        {
            Print();
            Print("THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION");
            Print("HAS BEEN CAPTURED BUT NOT DECODED:");
            Print();

            for (var row = 1; row <= 6; row++)
            {
                for (var col = 1; col <= 6; col++)
                {
                    Write(field[col, row].ToString());
                }

                Print();
            }

            Print();
            Print("DE-CODE IT AND USE IT IF YOU CAN");
            Print("BUT KEEP THE DE-CODING METHOD A SECRET.");
            Print();

            var hit = new int[7, 7];
            var lost = new int[4];
            var shipHits = new[] { 0, 2, 2, 1, 1, 0, 0 };
            var splashes = 0;
            var hits = 0;

            Print("START GAME");

            do
            {
                var input = Console.ReadLine().Split(',').Select(x => int.TryParse(x, out var num) ? num : 0).ToArray();

                if (!IsValid(input))
                {
                    Print("INVALID INPUT.  TRY AGAIN.");
                    continue;
                }

                var col = input[0];
                var row = 7 - input[1];
                var shipNum = field[row, col];

                if (shipNum == 0)
                {
                    splashes = splashes + 1;
                    Print("SPLASH!  TRY AGAIN.");
                    continue;
                }

                if (shipHits[shipNum] > 3)
                {
                    Print("THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT.");
                    Print("SPLASH!  TRY AGAIN.");
                    splashes = splashes + 1;
                    continue;
                }

                if (hit[row, col] > 0)
                {
                    Print($"YOU ALREADY PUT A HOLE IN SHIP NUMBER {shipNum} AT THAT POINT.");
                    Print("SPLASH!  TRY AGAIN.");
                    splashes = splashes + 1;
                    continue;
                }

                hits = hits + 1;
                hit[row, col] = shipNum;

                Print($"A DIRECT HIT ON SHIP NUMBER {shipNum}");
                shipHits[shipNum] = shipHits[shipNum] + 1;

                if (shipHits[shipNum] < 4)
                {
                    Print("TRY AGAIN.");
                    continue;
                }

                var shipType = (shipNum - 1) / 2 + 1;
                lost[shipType] = lost[shipType] + 1;

                Print("AND YOU SUNK IT.  HURRAH FOR THE GOOD GUYS.");
                Print("SO FAR, THE BAD GUYS HAVE LOST");
                Write($"{lost[1]} DESTROYER(S), {lost[2]} CRUISER(S), AND ");
                Print($"{lost[3]} AIRCRAFT CARRIER(S).");
                Print($"YOUR CURRENT SPLASH/HIT RATIO IS {splashes / hits}");

                if ((lost[1] + lost[2] + lost[3]) < 6) continue;

                Print();
                Print("YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET");
                Print($"WITH A FINAL SPLASH/HIT RATIO OF {splashes / hits}");

                if ((splashes / hits) == 0)
                {
                    Print("CONGRATULATIONS -- A DIRECT HIT EVERY TIME.");
                }

                Print();
                Print("****************************");
                Print();

                return;

            } while (true);
        }

        public bool IsValid(int[] input) => input.Length == 2 && input.All(Valid);

        public bool Valid(int value) => value > 0 && value < 7;

        public void Print(string str = "") => Console.WriteLine(str);

        public void Write(string value) => Console.Write(value);

        public string Tab(int pos) => new String(' ', pos);

        public int Rnd(int seed) => random.Next(seed);
    }
}
