user2509901
user2509901

Reputation:

Issue with Updating Array

I have a console Application that displays an array an moves the number to the left, right, top or bottom of '0' based on the input of the user

This is my code:

int[,] myNos = new int[3, 3] { { 3, 0, 7 }, { 9, 4, 8 }, { 2, 1, 5 } };

public void WriteData()
{
   Console.SetCursorPosition(0, 4);
   for (int col = 0; col < 3; col++)
   {
      for (int row = 0; row < 3; row++)
      {
         Console.Write("{0}\t", myNos[col, row]);
      }
      Console.WriteLine();
   }
}

public void Level1()
{
   Console.Clear();
   Console.SetCursorPosition(0, 0);
   Console.Write("Score : {0}", score);
   Console.SetCursorPosition(30, 0);
   Console.Write("Moves : {0}", moves);

   WriteData();

   string move = "a";

   while (move != "E")
   {
      Console.SetCursorPosition(0, 8);
      Console.Write("\nEnter your Move [L,R,T,B,E] : ");
      move = Console.ReadLine();
      move = move.ToUpper();

      while (move == "L")
      {
         if (myNos[0, 0] == 0)
         {
            WriteData();
         }
         else if (myNos[0, 1] == 0)
         {
            myNos[0, 1] = myNos[0, 0];
            myNos[0, 0] = 0;
            WriteData();
         }
         else if (myNos[0, 2] == 0)
         {
            myNos[0, 2] = myNos[0, 1];
            myNos[0, 1] = 0;
            WriteData();
         }
         else
         {
            WriteData();
         }
      }
   }
}

Everything is working as I want but the only problem is that after the array is updated and re-displayed, the cursor doesn't go back to where it will read the input. I have tried using:

Console.SetCursorPosition(0, 8);

and:

Console.ReadKey();

But neither seems to work.

Upvotes: 1

Views: 125

Answers (2)

Ken Kin
Ken Kin

Reputation: 4693

Well, have done the homework smells question.

From the point of the concept, the cursor display position is nothing related to the input stream, neither related to array updating.

The code is divided into partial classes. Although I didn't,I believe it can also be implemented in the MVC pattern, even it's a console application.

Need a [puzzle solver]?

p.s.: I have no idea how would you calculate the score, thus it's always zero.

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

class Program {
    static void Main(String[] args) {
        (new SlidingPuzzle(new[,] { 
            { 3, 0, 8 }, 
            { 6, 4, 7 }, 
            { 2, 1, 5 }, 
            })).Run();
    }
}

public partial struct Position {
    public Position(int left, int top) {
        Left=left;
        Top=top;
    }

    public int Left, Top;
}

For this part, is a candidate of the controller:

public partial class SlidingPuzzle {
    public void Run() {
        for(bool initialized=false, quit=false; ; ) {
            if(!initialized) {
                Reset();
                Console.Clear();
                ShowPrompt();
                initialized=true;
            }

            ShowStatics();
            ShowMatrix();

            if(quit||IsGameOver||IsFinished) {
                SetCursorToBottom();

                if(!quit)
                    ShowOnEnd();

                if(!(quit=IsExit)) {
                    initialized=false;
                    continue;
                }

                break;
            }

            var keyInput=Console.ReadKey(true).Key;

            if(ConsoleKey.Escape==keyInput)
                quit=true;
            else if(ConsoleKey.LeftArrow==keyInput)
                Move(new[] { +0, +1 });
            else if(ConsoleKey.UpArrow==keyInput)
                Move(new[] { +1, +0 });
            else if(ConsoleKey.RightArrow==keyInput)
                Move(new[] { +0, -1 });
            else if(ConsoleKey.DownArrow==keyInput)
                Move(new[] { -1, +0 });
        }
    }

    void ReadOnExit() {
        Console.WriteLine("Press any key to exit ... ");
        Console.ReadKey(true);
    }

    bool IsExit {
        get {
            Console.WriteLine("Try again? (Y/N)");
            var quit=ConsoleKey.Y!=Console.ReadKey(true).Key;

            if(quit)
                ReadOnExit();

            return quit;
        }
    }
}

And this, is for a candidate of the view:

partial class SlidingPuzzle {
    void SetCursorToBottom() {
        var pos=posBottom;
        Console.SetCursorPosition(pos.Left, pos.Top);
    }

    void ShowOnEnd() {
        if(IsGameOver) {
            Console.WriteLine("- Game Over -");
            Console.WriteLine("You've reached the limitation of movement. ");
        }
        else {
            Console.WriteLine("- Game Completed -");
            Console.WriteLine("Congratulations! You've solved the puzzle. ");
        }
    }

    void ShowStatics() {
        var pos=posStatics;
        Console.SetCursorPosition(pos.Left, pos.Top);

        Console.Write("Score: {0}", score);
        Console.Write(SlidingPuzzle.indentation);
        Console.WriteLine("Moves: {0}", moves);
    }

    void ShowPrompt() {
        var pos=posPrompt;
        Console.SetCursorPosition(pos.Left, pos.Top);

        Console.WriteLine("Enter your move [←, ↑, →, ↓, Esc] ");
    }

    void ShowMatrix() {
        var pos=posMatrix;
        Console.SetCursorPosition(pos.Left, pos.Top);

        for(int m=lengths[0], i=0, n, j; m-->0; ++i)
            for(n=lengths[1], j=0; n-->0; ++j) {
                var value=this[i, j].ToString();

                if("0"==value) {
                    value="\x20";
                    var left=indentation.Length+Console.CursorLeft;
                    pos=new Position(left, Console.CursorTop);
                }

                if(SlidingPuzzle.linesPerRow>0)
                    Console.Write(SlidingPuzzle.indentation+value);

                if(0==n)
                    for(var count=SlidingPuzzle.linesPerRow; count-->0; )
                        Console.WriteLine("");
            }

        Console.SetCursorPosition(pos.Left, pos.Top);
    }

    void SetLayoutPosition() {
        posMatrix=new Position(0, 2);
        posPrompt=new Position(0, posMatrix.Top+lengths[0]*linesPerRow);
        posBottom=new Position(0, 1+posPrompt.Top);
        posStatics=new Position(0, 0);
    }

    Position posBottom, posMatrix, posStatics, posPrompt;

    static readonly int linesPerRow=2;
    static readonly String indentation=new String('\x20', 4);
}

And the candidate of the model:

partial class SlidingPuzzle {
    void Reset() {
        Array.Copy(initial, mutable, initial.Length);
        current=IndexOf(0);
        moves=0;
        score=0;
    }

    void Move(int[] offset) {
        var indices=new int[lengths.Length];
        var i=0;

        for(i=indices.Length; i-->0; indices[i]=current[i]+offset[i])
            ;

        for(i=indices.Length; i-->0; )
            if(0>indices[i]||indices[i]>lengths[i]-1)
                break;

        if(i<0) {
            var value=this[current];
            this[current]=this[indices];
            this[indices]=value;
            current=indices;
            ++moves;
        }
    }

    int[] IndexOf(object value) {
        for(int m=lengths[0], i=0, n, j; m-->0; ++i)
            for(n=lengths[1], j=0; n-->0; ++j)
                if(this[i, j].ToString()==value.ToString())
                    return new[] { i, j };

        return SlidingPuzzle.emptyArray;
    }

    object this[params int[] indices] {
        set {
            mutable.SetValue(value, indices);
        }

        get {
            return mutable.GetValue(indices);
        }
    }

    bool IsFinished {
        get {
            for(int m=lengths[0], i=0, n, j; m-->0; ++i)
                for(n=lengths[1], j=0; n-->0; ++j)
                    if(this[i, j].ToString()!=(1+i*lengths[1]+j).ToString())
                        if(0!=m||0!=n)
                            return false;

            return true;
        }
    }

    bool IsGameOver {
        get {
            return !(maxMoves!=moves||IsFinished);
        }
    }

    public SlidingPuzzle(Array original) {
        var elementType=original.GetType().GetElementType();
        lengths=new int[original.Rank];

        for(var i=original.Rank; i-->0; lengths[i]=original.GetLength(i))
            ;

        initial=Array.CreateInstance(elementType, lengths);
        mutable=Array.CreateInstance(elementType, lengths);
        Array.Copy(original, initial, original.Length);
        SetLayoutPosition();
    }

    int[] current;
    Array mutable;
    readonly int[] lengths;
    readonly Array initial;
    int score, moves, maxMoves=25;

    static readonly int[] emptyArray=new int[] { };
}

Upvotes: 1

user2509901
user2509901

Reputation:

I thought of something which turned out to be the answer, i declared the move Variable as global and then modified my WriteData() Method and

      public void WriteData()
      {
           Console.SetCursorPosition(0, 4);
           for (int col = 0; col < 3; col++)
           {
                for (int row = 0; row < 3; row++)
                {
                    Console.Write("{0}\t", myNos[col, row]);
                }
                Console.WriteLine();
            }
            //This was the modification
            menu = "a";
     }

Upvotes: 3

Related Questions