3

I am trying to write a small c# program that determines the correct move of a queen in chess. The coordinates of the initial and final position of the move are parsed by the string in the usual chess notation, for example, "a1". It seems to be easy, one just needs to add the isCorrectMove() method, but I don’t understand how we can convert the string to an integer without having a number and not even converting it to a number. That is, what the strings mean: var dx = Math.Abs (to [0] - from [0]); and so forth.

Here is an example code:

C#

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

class Program
{
   public static void Main()
   {
      TestMove("a1", "d4");
      TestMove("f4", "e7");
      TestMove("a1", "a4");
      TestMove("a1", "a1");
   }

   public static void TestMove(string from, string to)
   {
      Console.WriteLine("{0}-{1} {2}", from, to, IsCorrectMove(from, to));
   }


   public static bool IsCorrectMove(string from, string to)
   {
      var dx = Math.Abs(to[0] - from[0]); //horizontal move
      var dy = Math.Abs(to[1] - from[1]); //vertical move
      return (dx == dy || dx == 0 || dy == 0 && from != to); // this move, however does not yield appropriate result for a1-a1 Queen's move as it must be a false move or "no move".
   }

}

the condition described by the line return (dx == dy || dx == 0 || dy == 0 && from != to); does not yield proper result, as boolean check says that it is a correct move. I do not understand how to express this condition using logical operators in C#. Please suggest your solution or how to find it. In chess, the acceptable moves by a queen are the same either as for bishop or as for the rook but how to express "no move"?

sirandy
  • 1,834
  • 5
  • 27
  • 32
  • 1
    whoever is voting to close this as "too broad", could you explain? the bugfix may be trivial, but we have an mcve and helpful answers and an interesting aspect: applying implicit type conversion to chess position strings to find distances. – Cee McSharpface Nov 11 '18 at 16:49

4 Answers4

1

It is the correct move if letter stays the same (same row) and the second number changes (condition 1). from != to is to make sure that it has actually moved

if number stays the same, and letter changes (condition 2)

if number of squares moved in x direction is equal to those moved in y direction (condition 3)

public static bool IsCorrectMove(string from, string to)
{
     return ((from[0] == to[0]) ||    // (1)
            (from[1] == to[1]) ||    // (2)
            (Math.Abs((int)from[0] - (int)to[0])) == Math.Abs((int)from[1] - (int)to[1]))) && from != to);   // (3)
}
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
1

You need to add parentheses in your last line to make sure things evaluate correctly:

return (dx == dy || dx == 0 || dy == 0) && (from != to);

This makes sure that the function returns false whenever from == to, and otherwise returns true when any of the three other conditions is true.

As for your question about why Math.Abs() can work on a string, that's because when you index into a string (like from[0]), what you're getting is not a string but a char, and a char has an int underneath it. You can test this by checking the value of something like Math.Abs('a')

See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/char for more info about the value of a char.

asherber
  • 2,508
  • 1
  • 15
  • 12
1

You can do it with the dx and dy variables alone, but there is a mistake in the translation from chess rules to program logic: the C# logical or operator || in the expression

dx == dy || dx == 0 || dy == 0 && from != to

will result in true as soon as one of its conditions, including dx == 0 alone is true. This is because of the language's operator precedence and order of evaluation rules.

Translated to chess rules, this would mean "valid if there is no movement in x direction" which is incorrect.

You need to use parentheses to evaluate the left part as a whole and then apply the second condition with logical and &&:

(dx == dy || dx == 0 || dy == 0) && from != to

This corresponds nicely to the valid moves which are: any number of squares diagonally (dx equal dy, both signs), forward/back (no dx), and left/right (no dy) with the additional condition that you can not end up on the square you started from.

Cee McSharpface
  • 8,493
  • 3
  • 36
  • 77
1

Queens can move either horizontally, diagonally or vertically any number of spaces. Therefore, we should start by examining these cases separately:

isValidHorizontal = dy == 0 && dx != 0
isValidVertical = dx == 0 && dy != 0
isValidDiagonal = dx == dy && dx != 0 && dy != 0

Note that I have made these conditionals exhaustive. So, if we were to put them all together, we would have:

isValid = (dy == 0 && dx != 0) || (dx == 0 && dy != 0) || (dx == dy && dx != 0 && dy != 0)

Now, let's declare some Boolean variables to simplify this:

A <- dx == 0
B <- dy == 0
C <- dx == dy

Our equation then becomes B(~A) + A(~B) + C(~A)(~B). We can then simplify to (B + C(~B))(~A) + A(~B). This then simplifies to (B + C)(~A) + A(~B). We can then move some terms around to make ~AB + ~BA + ~AC. This then simplifies A ^ B + ~AC.

Translating this, we then have:

isValid = (dx == 0 ^ dy == 0) || (dx == dy && dx > 0)

Note that (dx == 0 ^ dy == 0) || (dx == dy && dy > 0) would also work. Also note that not-moving is not considered valid in this system (isValid will be false).

Woody1193
  • 7,252
  • 5
  • 40
  • 90