Mi tarea es escribir funciones simples relacionadas con el ajedrez. La función rook está funcionando bien, supongo que muestra dónde puede avanzar desde la coordenada de inicio dada. Y ahora estoy atascado con la función knight. Mi idea es filtrar la lista de coordenadas por la siguiente condición: si el valor abs de las diferencias de coordenadas es 3 y las filas son diferentes, entonces es un paso válido. Pero realmente no sé cómo debería implementar esto en Haskell. ¿Alguna idea de cómo debo hacer eso?

Mi código:

import Data.List

possibleMoves = [ (x, y) | x <- [0..7], y <- [7,6..0]]

rook :: (Int, Int) -> [(Int, Int)]
rook (x,y) = filter (/=(x,y)) (filter ((==y).snd) possibleMoves ++ filter ((==x).fst ) possibleMoves)

knight :: (Int, Int) -> [(Int, Int)] 
knight (x,y) = filter ((==3)((abs(y - head(map snd(possibleMoves))))).snd) possibleMoves

Resultando el siguiente error:

    * Couldn't match expected type `Int -> Bool'
                  with actual type `Bool'
    * Possible cause: `== 3' is applied to too many arguments
      In the first argument of `(.)', namely
        `(== 3) ((abs (y - head (map snd (possibleMoves)))))'
      In the first argument of `filter', namely
        `((== 3) ((abs (y - head (map snd (possibleMoves))))) . snd)'
      In the expression:
        filter
          ((== 3) ((abs (y - head (map snd (possibleMoves))))) . snd)
          possibleMoves
  |
9 | knight (x,y) = filter ((==3)((abs(y - head(map snd(possibleMoves))))).snd) possibleMoves
  |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0
vNSkyline 13 dic. 2019 a las 18:54

2 respuestas

La mejor respuesta

Parece que lo estás haciendo más difícil de lo necesario.

Dada la posición K a continuación, simplemente puede enumerar cada movimiento de caballero:

    1   2   3   4   5
  +---+---+---+---+---+
1 |   | H |   | A |   |
  +---+---+---+---+---+
2 | G |   |   |   | B |
  +---+---+---+---+---+
3 |   |   | K |   |   |
  +---+---+---+---+---+
4 | F |   |   |   | C |
  +---+---+---+---+---+
5 |   | E |   | D |   |
  +---+---+---+---+---+

Y quita las que están fuera del tablero de ajedrez.

knight :: (Int, Int) -> [(Int, Int)]
knight (x, y) = filter validPosition
  [ (x + 1, y + 2)
  , (x + 2, y + 1)
  , (x + 2, y - 1)
  , (x + 1, y - 2)
  , (x - 1, y - 2)
  , (x - 2, y - 1)
  , (x - 2, y + 1)
  , (x - 1, y + 2)
  ]

Entonces, si crees que te estás repitiendo demasiado:

knight' :: (Int, Int) -> [(Int, Int)]
knight' (x, y) = filter validPosition
  [ (x + dx, y + dy) | dx <- [-2,-1,1,2]
                     , dy <- [-2,-1,1,2]
                     , ... something about dx, dy and 3 ...
                     ]

Parece que las cosas (== y) . snd oscurecen un poco la solución.

1
Simon Shine 26 dic. 2019 a las 01:04

Su idea de filtrar las posiciones del caballero es realmente sucinta y fácil de implementar utilizando una comprensión de lista.

knight (x, y) = [(x', y') | x'<-[x-2..x+2], y'<-[y-2..y+2], abs (x' - x) + abs (y' - y) == 3 ]

Restringir los posibles valores de desplazamiento a -2 y +2 también evitará que la columna y la fila sean las mismas, por lo que puede eliminar esa condición.

Lo único es que también devolverá valores que hayan pasado el tablero. Puede verificar esto utilizando su función preexistente possibleMoves:

import Data.List (intersect)
safeKnight = intersect possibleMoves . knight
0
MikaelF 24 dic. 2019 a las 05:04