Exemplo n.º 1
0
        static void Main()
        {
            string firstLine = Console.ReadLine(); // reads the first line from console

            StreamReader file = null; // since there is option to read data from file, opens empty StreamReader
            bool hasFileData = false; // by default the data should be read from console
            if (firstLine[0] == '@') // but if the first character is "@" (non digit), that means the content is filename (and path)
            {
                hasFileData = true; // then all input data should be read from the file
                firstLine = firstLine.Replace('@', ' ').Trim(); // removes "@" and any leading/trailing spaces
                file = new StreamReader(firstLine); // opens the file for reading
            }

            int C;
            int N;
            if (hasFileData) // reads from file
            {
                C = int.Parse(file.ReadLine());
                N = int.Parse(file.ReadLine());
            }
            else //reads from Console
            {
                C = int.Parse(firstLine);
                N = int.Parse(Console.ReadLine());
            }

            if (N == 1) // marginal case, one dimensional playfield
            {
                int height = int.Parse(Console.ReadLine()); // reads the single tower
                for (int i = 0; i < C; i++)
                {
                    Console.WriteLine("take 0 0"); // for a single tower playfiled only C times "take" move is allowed
                }
                return; // then program finishes
            }

            Playfield theBoard = new Playfield(N); // creates empty playfield
            for (int i = 0; i < N; i++) // iterates through rows
            {
                string[] Row;
                if (hasFileData) Row = file.ReadLine().Split(' '); // reads each line from file and separates it to array of string values
                else Row = Console.ReadLine().Split(' '); // reads each line from console and separates it to array of string values
                for (int j = 0; j < Row.Length; j++) // iterates through cells in current row
                {
                    theBoard.Set(i, j, int.Parse(Row[j])); // and pumps up the Playfield
                }
            }

            if (hasFileData) // if the data source is file
            {
                file.Close(); // closes that file
                file.Dispose(); // releases all used resources
            }
            int thsIterations = C * N * N / 1000; //calculates some estimation of the number of interations required
            // this should be used to select proper algorythm in order to fit into the 3 sec. time limit

            // Choosing algorythm depending on board and moves complexity in order to fit within 3 seconds calculation interval
            if (thsIterations < 6000) // for small and medium range a complex algorithm is selected
            {
                Move bestMove = new Move();
                //FULL WALKTROUGH - on each level (move's depth) the best result is selected
                for (int depth = 0; depth < C; depth++) // iterates through possible moves
                {
                    int maxRank = int.MinValue; // the resultng rank, initially the minimal possible value
                    for (int r = 0; r < N; r++) // iterates through possible rows
                        for (int c = 0; c < N; c++) // iterates through possible colunms
                            for (int m = 0; m < 2; m++) // iterates through possible type of moves
                            {
                                int diff = theBoard.NeighboursDiff(bestMove.row, bestMove.column) - theBoard.NeighboursDiff(r, c); // calculates if the neighbour difference of best move and current
                                int rank = theBoard.Score; // gets current score of the board
                                if (m == 0 && theBoard.Get(r, c) == 0) m = 1; // checks for invalid TAKE move, goes directly to PUT

                                if (m == 0) rank = rank - theBoard.Take(r, c); // take = 0 and calculates the rank of the move
                                else rank = rank - theBoard.Put(r, c); // put = 1 and calculates the rank of the move

                                // SELECTION OF THE BEST MOVE
                                if (rank > maxRank || // 1.
                                        (rank == maxRank && diff > 0) || // 2. and 3.
                                            (rank == maxRank && diff == 0 && theBoard.Get(r, c) >= theBoard.Get(bestMove.row, bestMove.column))) // 2. and 4.
                                // a better move has been found if one of the following three conditons has been reached:
                                // 1. the current rank is better than the previous one (or)
                                // 2. the current rank is equal to previous one, but
                                //      2.1. the difference with some neighbours is less, (or)
                                // 3. the current rank and the differnece are equal to previous one, but
                                //      3.1. but current height is greater
                                {
                                    maxRank = rank; // assigns better rank of the move
                                    bestMove.type = m; // take = 0, put = 1
                                    bestMove.row = r; // row
                                    bestMove.column = c; // column
                                }
                                theBoard.Resume(); // returns to previous move
                            }
                    // now makes the best move over all iterations of current depth
                    if (bestMove.type == 0)
                    {
                        theBoard.Take(bestMove.row, bestMove.column); // take = 0
                        Console.Write("take ");
                    }
                    else
                    {
                        theBoard.Put(bestMove.row, bestMove.column); // put = 1
                        Console.Write("put ");
                    }
                    Console.WriteLine("{0} {1}", bestMove.row, bestMove.column);
                }
            }

            else // for most complex boards only one iteration is possible (or half! or less!!)
            {
                // creates a pair of arrays for moves and their ranks
                Move[] moves = new Move[C];
                int[] ranks = new int[C];

                int rowFactor = 1; // normally all cells in the board are reached
                if (thsIterations > 300000) rowFactor = 2 + (thsIterations > 650000 ? 1 : 0);
                // unfortunately in order to fit into the time limit, for most complex boards only a half/third of them could be reached

                //SINGLE WALKTROUGH - on each iteration the result is put into the sorted array of ranks
                for (int r = 0; r < N; r = r + rowFactor) // iterates through possible rows (or half of them)
                    for (int c = 0; c < N; c++) // iterates through possible colunms
                        for (int m = 0; m < 2; m++) // iterates through possible type of moves
                        {
                            int rank = theBoard.Score; // gets current score of the board
                            if (m == 0 && theBoard.Get(r, c) > 0) rank = rank - theBoard.Take(r, c); // take = 0 and calculates the rank of the move
                            else
                            {
                                rank = rank - theBoard.Put(r, c);
                                m = 1; // put = 1 and calculates the rank of the move
                            }
                            int i = 0;
                            while (i < C && rank <= ranks[i]) i++; // looks where the current rank is suitable to place

                            if (i < C) // only if the place has found
                            {
                                if (moves[i].Equals(null)) // if the list is not full makes new item
                                    moves[i] = new Move();
                                else //and finally we found the place to insert a new better move
                                    for (int k = C - 1; k > i; k--)
                                    {
                                        moves[k] = moves[k - 1];
                                        ranks[k] = ranks[k - 1];
                                    }
                                moves[i].type = m;
                                moves[i].row = r;
                                moves[i].column = c;
                                ranks[i] = rank;
                            }
                            theBoard.Resume(); // returns to previous move
                        }

                // prints first C best ranked moves
                for (int i = 0; i < C; i++)
                // iterates through alreeady sorted best moves
                {
                    if (moves[i].type == 0)
                    {
                        theBoard.Take(moves[i].row, moves[i].column); // take = 0
                        Console.Write("take ");
                    }
                    else
                    {
                        theBoard.Put(moves[i].row, moves[i].column); // put = 1
                        Console.Write("put ");
                    }
                    Console.WriteLine("{0} {1}", moves[i].row, moves[i].column);
                }
            }
        }
Exemplo n.º 2
0
        static void Main()
        {
            Console.WriteLine(@"
                 ****************************
                 *                          *
                 *  Trolls Game Visualizer  *
                 *                          *
                 *  author:  Pavel Sotirov  *
                 ****************************

            Here you must enter input data as per the rules and conditions
            set in the   ""Troll Game""   competition,  organized by Telerik
            and PCMagazine. More details you can obtain here:
            http://konkurs.pcmagbg.net/task-1-season-2012-2013/

            The game visialization will proceed in the following steps:

            1. Entering the number of moves, board dimensions and data.
            You can select two ways to enter the board  - by using already
            prepared text file  or  manually via the console.  If you omit
            a filename when asked, that means you are choosing manual way.

            2. Solving the board.
            Please be patient!  Depending on board's dimensions and number
            of desired moves, this process can take some time - up to four
            minutes. You will be informed about the progress.

            3. Creating output HTML files
            For each move a corresponding  HTML  file will be created that
            will hold the  board's content  after the move.  For each move
            a separate file will be created with move's index.  Start file
            with initial board content (0 index) also will be created. You
            will be asked  to enter the proper filename.  If this filename
            is omited or invalid, a default filename of  ""Trolls xxxx.html""
            will be used (xxxx is move's index from 0 to 1000).

            4. Finally the default browser will be invoked to show result.
            ");

            Console.Write("\n\nEnter input filename [empty for console]: ");
            string filename = Console.ReadLine(); // reads the filename from console

            StreamReader file = null; // since there is option to read data from file, opens empty StreamReader
            bool hasFileData = false; // by default the data should be read from console
            if (filename.Length > 0) // but if the content is filename (and path)
            {
                hasFileData = true; // then all input data should be read from the file
                try
                {
                    file = new StreamReader(filename); // opens the file for reading
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error! ", e.ToString());
                    Console.WriteLine("Manual entering from console");
                    hasFileData = false;
                }
            }

            int C;
            int N;
            if (hasFileData) // reads from file
            {
                if (!int.TryParse(file.ReadLine(), out C) || C < 1 || C > 1000)
                {
                    Console.WriteLine("Invalid input file: wrong number of moves");
                    return;
                };
                if (!int.TryParse(file.ReadLine(), out N) || N < 1 || N > 1000)
                {
                    Console.WriteLine("Invalid input file: wrong board dimension");
                    return;
                };
            }
            else //reads from Console
            {
                do
                {
                    Console.Write("\nEnter number of moves to solve, C [1,1000]: ");
                } while (!int.TryParse(Console.ReadLine(), out C) || C < 1 || C > 1000);
                do
                {
                    Console.Write("\nEnter board dimensions N x N, N [2,1000]: ");
                } while (!int.TryParse(Console.ReadLine(), out N) || N < 2 || N > 1000);
                Console.WriteLine("\n\nPlease enter board data: {0} lines, {0} values per line, separated by space", N);
            }

            Playfield theBoard = new Playfield(N); // creates empty playfield
            for (int i = 0; i < N; i++) // iterates through rows
            {
                string[] Row;

                while (true)
                {
                    if (hasFileData) Row = file.ReadLine().Split(' '); // reads each line from file and separates it to array of string values
                    else
                    {
                        Console.Write("Row {0, 4}: ", i);
                        Row = Console.ReadLine().Split(' '); // reads each line from console and separates it to array of string values
                    }
                    if (Row.Length != N)
                    {
                        Console.WriteLine("\nWrong number of elements in Row {0}\n", i);
                        if (hasFileData) return; // if the input is from file stops the program
                        continue; // else goes to start of the loop
                    }
                    int j;
                    for (j = 0; j < N; j++) // iterates through cells in current row
                    {
                        int h = 0;
                        if (!int.TryParse(Row[j], out h) || h < 0 || h > Tower.maxHeight)
                        {
                            Console.WriteLine("\nWrong element value in Row {0}, Column {1}\n", i, j);
                            if (hasFileData) return; // if the input is from file stops the program
                            break; // else goes out of the loop
                        }
                        if (h > 0 && ((j > 0 && h == theBoard.Get(i, j - 1)) || (i > 0 && h == theBoard.Get(i - 1, j)))) //checks for duplicate heights in left and upper elements
                        {
                            Console.WriteLine("\nDuplicate height - Element in Row {0}, Column {1}\n", i, j);
                            if (hasFileData) return; // if the input is from file stops the program
                            break; // else goes out of the loop
                        }
                        theBoard.Set(i, j, h); // and pumps up the Playfield
                    }
                    if (j == N) break; // correct row data - exits the while loop
                }
            }

            if (hasFileData) // if the data source is file
            {
                file.Close(); // closes that file
                file.Dispose(); // releases all used resources
            }

            Console.Write("\n\nEnter output filename [up to 10 characters, only : ");
            while (true)
            {
                filename = Console.ReadLine(); // reads the filename from console
                if (filename.Length < 1)
                {
                    Console.WriteLine("\nName too short\n");
                    continue;
                }
                if (filename.Length > 10)
                {
                    Console.WriteLine("\nName too long\n");
                    continue;
                }
                int i;
                for (i = 0; i < filename.Length; i++)
                    if (!char.IsLetter(filename[i]))
                    {
                        Console.WriteLine("\nInvalid filename\n");
                        break;
                    }
                if (i == filename.Length) break; // if filename is correct, goes out of the loop
            }

            int initScore = theBoard.Score;
            int maxRank = 0; // the resultng rank of the best move, initially 0

            Console.WriteLine("Initial score: " + initScore);
            Move bestMove = new Move();
            //FULL WALKTROUGH - on each level (move's depth) the best result is selected
            for (int depth = 0; depth < C; depth++) // iterates through possible moves
            {
                if (!theBoard.PrintBoard(filename, depth, initScore, maxRank)) return; // prints the board into HTML file, returns on error

                maxRank = int.MinValue; // the resultng rank of the best move, initially the minimal possible value
                for (int r = 0; r < N; r++) // iterates through possible rows
                    for (int c = 0; c < N; c++) // iterates through possible colunms
                        for (int m = 0; m < 2; m++) // iterates through possible type of moves
                        {
                            int diff = theBoard.NeighboursDiff(bestMove.row, bestMove.column) - theBoard.NeighboursDiff(r, c); // calculates if the neighbour difference of best move and current
                            int rank = theBoard.Score; // gets current score of the board
                            if (m == 0 && theBoard.Get(r, c) == 0) m = 1; // checks for invalid TAKE move, goes directly to PUT

                            if (m == 0) rank = rank - theBoard.Take(r, c); // take = 0 and calculates the rank of the move
                            else rank = rank - theBoard.Put(r, c); // put = 1 and calculates the rank of the move

                            // SELECTION OF THE BEST MOVE
                            if (rank > maxRank || // 1.
                                    (rank == maxRank && diff > 0) || // 2. and 3.
                                        (rank == maxRank && diff == 0 && theBoard.Get(r, c) >= theBoard.Get(bestMove.row, bestMove.column))) // 2. and 4.
                            // a better move has been found if one of the following three conditons has been reached:
                            // 1. the current rank is better than the previous one (or)
                            // 2. the current rank is equal to previous one, but
                            //      2.1. the difference with some neighbours is less, (or)
                            // 3. the current rank and the differnece are equal to previous one, but
                            //      3.1. but current height is greater
                            {
                                maxRank = rank; // assigns better rank of the move
                                bestMove.type = m; // take = 0, put = 1
                                bestMove.row = r; // row
                                bestMove.column = c; // column
                            }
                            theBoard.Resume(); // returns to previous move
                        }
                // now makes the best move over all iterations of current depth
                if (bestMove.type == 0)
                {
                    theBoard.Take(bestMove.row, bestMove.column); // take = 0
                    Console.Write("take ");
                }
                else
                {
                    theBoard.Put(bestMove.row, bestMove.column); // put = 1
                    Console.Write("put ");
                }
                Console.WriteLine("{0} {1}", bestMove.row, bestMove.column);
            }
            if (!theBoard.PrintBoard(filename, -C, initScore, maxRank)) return; // prints the last board into HTML file, returns on error (index is negative in order to inform the method this is the last file)
            Console.WriteLine("Final score: " + theBoard.Score);
            Console.Write("All files generated successfully!\nPress any key to continue to browser...\n");
            Console.ReadKey(true);
            Process.Start(filename + ".0.html");
        }