0votos

Movimientos y fichas Ajedrez en Haskell

por josejuan hace 5 años

Las restricciones del tablero y la dirección del ataque (blancas a negras) quedan aseguradas por tipos (los tipos aseguran, por ejemplo, que siempre una blanca ataca a una negra y no una blanca a blanca, negra a blanca, etc...).

Siguiendo con los ejercicios de uso de matrices... Declara las diferentes piezas y sus posibles movimientos. Construye una función que dando dos fichas (una por color) y sus posiciones, determine quien "come" a quien (si se pueden "comer"). Empiezan siempre blancas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import Data.Maybe 
import Data.List 
 
-- Todos los datos quedan asegurados por tipos (ej. es imposible indicar una coordenada no válida) 
data Row        = R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8         deriving (Read, Show, Eq, Enum, Bounded) 
data Col        = A  | B  | C  | D  | E  | F  | G  | H          deriving (Read, Show, Eq, Enum, Bounded) 
data Coord      = Coord Row Col                                 deriving (Read, Show, Eq) 
data Color      = White | Black                                 deriving (Read, Show, Eq, Enum) 
data PieceType  = King  | Queen | Rook | NightK | Bishop | Pawn deriving (Read, Show, Eq, Enum) 
data Piece      = Piece Color PieceType                         deriving (Read, Show, Eq) 
data PieceCoord = PieceCoord Piece Coord                        deriving (Show, Eq) 
 
-- Si puede, desplaza una pieza 
addCoord (Coord r c) (x, y) = do r' <- toEnum' (fromEnum r + x) 
                                 c' <- toEnum' (fromEnum c + y) 
                                 return $ Coord r' c' 
 
-- Movimientos (de mate) posibles, en blancas, de cada tipo de ficha 
-- NOTA: mate al paso del peón requiere conocer no sólo la posición de la opuesta, también su último movimiento 
captureMoves King   = [(x, y) | x <- [-1..1], y <- [-1..1], x /= 0 || y /= 0] 
captureMoves Queen  = [(r * x, r * y) | (x, y) <- captureMoves King, r <- [1..8]] 
captureMoves Rook   = [(r * x, r * y) | (x, y) <- captureMoves King, x == 0 || y == 0, r <- [1..8]] 
captureMoves NightK = [(a * x, b * y) | a <- [-1, 1], b <- [-1, 1], (x, y) <- [(1, 2), (2, 1)]] 
captureMoves Bishop = [(r * x, r * y) | (x, y) <- captureMoves King, x /= 0 && y /= 0, r <- [1..8]] 
captureMoves Pawn   = [(-1, 1), (1, 1)] 
 
-- Entonces, la función solicitada, puede escribirse como 
whiteCaptureBlack (PieceCoord (Piece White wp) wc) (PieceCoord (Piece Black _) bp) = 
  not $ null $ filter (==bp) $ catMaybes $ map (addCoord wc) $ captureMoves wp 
 
 
 
 
 
 
 
 
 
 
-- Así, un programa por consola que lee posiciones e indica mates podría ser 
main = do 
  white <- readLn 
  black <- readLn 
  putStrLn $ if whiteCaptureBlack white black 
                then "Captured!   :D" 
                else "No captured :(" 
  main 
 
{- 
 
Por ejemplo: 
 
 
$ runghc chess.hs 
WKA1 
BKA2 
Captured!   :D 
WKA1 
BKB2 
Captured!   :D 
WKA1 
BKB3 
No captured :( 
WNA1 
BPA3 
No captured :( 
WNA1 
BPB3 
Captured!   :D 
WQA1 
BPH5 
No captured :( 
WQA1 
BPH8 
Captured!   :D 
 
 
-} 
 
 
 
-- Por comodidad a la hora de pedir los datos, podemos escribir un parser específico para las piezas 
-- (ej. WKE3 significa "White King on E3") 
instance Read PieceCoord where 
  readsPrec _ (o:t:c:r:xs) = let w = do o' <- elemIndex o "WB"       >>= return.toEnum -- [WB] 
                                        t' <- elemIndex t "KQRNBP"   >>= return.toEnum -- [KQRNBP] 
                                        c' <- elemIndex c "ABCDEFGH" >>= return.toEnum -- [ABCDEFGH] 
                                        r' <- elemIndex r "12345678" >>= return.toEnum -- [12345678] 
                                        return $ PieceCoord (Piece o' t') (Coord r' c') 
                             in case w of 
                                  Just p  -> [(p, xs)] 
                                  Nothing -> [] 
  readsPrec _ _ = [] 
4 comentarios
0votos

Escrito por adr hace 5 años

¿El peón negro tiene el mismo movimiento para comer (posiciones) en el tablero que el peón blanco?
El peón que empieza desde abajo (penúltima fila) tendría que comer en -1-1 y -11 con respecto a su posición y el que se inicia en la parte superior(segunda fila) 1-1 y 11.
No sé si me estoy perdiendo algo o está planteado de otra forma los casos del peón.

Por cierto se colaron las erratas en Knight.
0votos

Escrito por adr hace 5 años

Poner el símbolo + en las posiciones me añadió subrayados. Disculpen.


El peón que empieza desde abajo (penúltima fila) tendría que comer en -1-1 y -1+1 con respecto a su posición y el que se inicia en la parte superior(segunda fila) +1-1 y +1+1.
0votos

Escrito por josejuan hace 5 años

Siempre bajo mi criterio, el enunciado es confuso respecto qué debe devolver la función. En mi solución, es obvio que la función determina si la blanca se come a la negra (se llama whiteCaptureBlack).

De todos modos, excepto por el turno inicial, el ajedrez es un juego reversible (si sabes jugar con blancas, sabes jugar con negras), por lo que sólo hay que darle la vuelta al tablero para obtener la función blackCaptureWhite:

flipCoord (Coord r c) = Coord (f r) (f c) where f x = toEnum (7 - fromEnum x)

blackCaptureWhite (PieceCoord (Piece White wp) wc) (PieceCoord (Piece Black bp) bc) =
  whiteCaptureBlack (PieceCoord (Piece White bp) $ flipCoord bc) (PieceCoord (Piece Black wp) $ flipCoord wc)


Por otro lado, escribir NightK no es una errata, está escrito así con la idea de diferenciar esa enumeración con el rey (y poder escribir "WKA1" frente a "WNA1").
0votos

Escrito por adr hace 5 años

Ok, la K al final es para evitar la coincidencia con King.

La salida que se debía retornar es la que estaba subrayada en cada uno de los tres ejemplos dados. En ingles, en español, en chino, abreviada o no, daba lo mismo, pero pasando dos fichas.

No es sacar si las blancas capturan a la negra, es que pieza come a a cual, y si las dos podían comerse entre sí, se da prioridad a la blanca.

Puse tres casos: No se comen, peón blanco comiendo a caballo negro, y dos fichas que se pueden comer entre sí pero que gana blanca por prioridad.

Por supuesto que si se tiene whiteCaptureBlack y blackCaptureWhite sólo se necesitaría señalar la preferencia de las blancas y usar ambas funciones para realizar el ejercicio... bueno y tener en cuenta lo del peón.

Gracias por participar en este desafío también :)

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.