{-# LANGUAGE ScopedTypeVariables,GeneralizedNewtypeDeriving #-} {- Copyright 2010 Ken Takusagawa This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -} module Main (main) where{ import Array; import System; import Char; import IO; import Control.Exception; import Monad; import Random; import Data.List; import qualified Data.Set as Set; import qualified Data.Map as Map; import Maybe; import Data.Array.ST; import Control.Monad.ST; main :: IO(()); main = (do{ (hPutStrLn stderr rcs_code); (setStdGen (mkStdGen 1)); (getArgs >>= (\lambda_case_var ->case lambda_case_var of { ["nothing"]-> (return ()); ["many-moves"]-> (many_moves initial_game_state); ["counter", n]-> (do{ (setStdGen(mkStdGen(read(n)))); (many_moves_counter 0 initial_game_state); }) })); }); map_tuple :: (a -> b) -> (a, a) -> (b, b); map_tuple fn x = ((fn (fst x)), (fn (snd x))); apply_first :: (a -> b) -> (a, c) -> (b, c); apply_first fn x = ((fn (fst x)), (snd x)); apply_second :: (a -> b) -> (c, a) -> (c, b); apply_second fn x = ((fst x), (fn (snd x))); zip_check_same_length :: [](a) -> [](b) -> []((a, b)); zip_check_same_length x1 x2 = (case (x1, x2) of { (([] ), ([] ))-> []; (((:) (a ) (arest )), ((:) (b ) (brest )))-> ((:) (a, b) (zip_check_same_length arest brest)) }); zipWith_check_same_length :: (a -> b -> c) -> [](a) -> [](b) -> [](c); zipWith_check_same_length f x1 x2 = (case (x1, x2) of { (([] ), ([] ))-> []; (((:) (a ) (arest )), ((:) (b ) (brest )))-> ((:) (f a b) (zipWith_check_same_length f arest brest)) }); zip_map :: (a -> b) -> [](a) -> []((a, b)); zip_map f l = (zip l (map f l)); flip_tuple :: (a, b) -> (b, a); flip_tuple x = ((snd x), (fst x)); show_list :: (Show (a)) => [](a) -> IO(()); show_list l = (putStr(unlines((map show)(l)))); compare_zipped :: (Ord (b)) => ((a, b) -> (a, b) -> Ordering); compare_zipped = (curry ((uncurry compare) . (map_tuple snd))); take_while_plus :: (a -> Bool) -> [](a) -> ([](a), Maybe(a)); take_while_plus p l = (case l of { ([] )-> ([], Nothing); ((:) (h ) (t ))-> (case (p h) of { (False )-> ([], (Just h)); (_ )-> (let { answer = (take_while_plus p t) } in (((:) h (fst(answer))), (snd answer))) }) }); random_from_list :: [](a) -> IO(a); random_from_list l = ((getStdRandom(randomR((0, (pred(length(l))))))) >>= (return . ((!!) l))); rcs_code :: String; rcs_code = "$Id: crazyhouseannihilation.ll,v 1.29 2010/11/15 09:35:03 kenta Exp kenta $"; test :: (Int, Int) -> Int; test xy = (case xy of { (v, z)-> z }); pparam :: (Int, Int) -> Int; pparam (q, r) = q; iopat :: IO(Int); iopat = (do{ (x, y) :: (Int, Int) <- undefined; (return x); }); ray :: Coord -> (Int, Int) -> [](Coord); ray origin delta = (let { nc :: Coord; nc = (add_coord origin delta) } in ((:) nc (ray nc delta))); add_coord :: Coord -> Delta -> Coord; add_coord (Coord (ox, oy)) (dx, dy) = (Coord (((+) ox dx), ((+) oy dy))); newtype Coord = Coord((Int, Int)) deriving (Eq, Ord, Ix); board_range :: (Coord, Coord); board_range = ((Coord (0, 0)), (Coord (bmax, bmax))); type Board = Array(Coord)(Maybe(Piece)); data Promotion_state = Original | Was_a_pawn deriving (Eq, Show); type Piece = (Color, (Type_piece, Promotion_state)); data Color = White | Black deriving (Show, Eq, Ord); data Type_piece = Pawn | Night | Bishop | Rook | Queen | King deriving (Eq, Show, Ord); random_piece :: IO(Type_piece); random_piece = (random_from_list all_pieces); random_mpiece :: IO(Maybe(Piece)); random_mpiece = ((random_from_list [False, True]) >>= (\lambda_case_var ->case lambda_case_var of { True-> (return Nothing); _ -> (do{ color :: Color <- (random_from_list [Black, White]); p :: Type_piece <- random_piece; promoted :: Promotion_state <- (case p of { (Pawn )-> (return Original); _ -> (random_from_list [Original, Was_a_pawn]) }); (return((Just (color, (p, promoted))))); }) })); show_type_piece :: Type_piece -> String; show_type_piece p = [(head(show(p)))]; show_color :: Color -> String; show_color c = (case c of { White-> "w"; Black-> "b" }); show_piece :: Maybe(Piece) -> String; show_piece p = (case p of { Nothing-> " ."; (Just (c, (t, promoted)))-> ((++) (show_color c) (map (case promoted of { Was_a_pawn-> toLower; Original-> toUpper }) (show_type_piece t))) }); show_row :: [](Maybe(Piece)) -> String; show_row lp = (concat((intersperse " ")((map show_piece)(lp)))); bmax :: Int; bmax = 7; sixty_four :: Int; sixty_four = ((*) ((+) 1 bmax) ((+) 1 bmax)); board_row :: Board -> Int -> [](Maybe(Piece)); board_row b r = (do{ i :: Int <- (enumFromTo 0 bmax); (return ((!) b (Coord (r, i)))); }); random_board :: IO(Board); random_board = ((sequence((replicate sixty_four)(random_mpiece))) >>= (return . (listArray board_range))); show_board :: Board -> String; show_board b = (concat((do{ r :: String <- ((map show_row)((map (board_row b))((enumFromThenTo bmax ((-) bmax 1) 0)))); (return ((++) r "\n")); }))); ray_possibilities :: Board -> Coord -> Delta -> [](Coord); ray_possibilities b origin delta = (case ((take_while_plus (\xy -> ((==) Nothing ((!) b xy))))((takeWhile (inRange (bounds b)))((ray origin delta)))) of { (empties, old_capture)-> ((++) empties (case old_capture of { (Just (xy ))-> (case ((==) (fst(fromJust(((!) b xy)))) (fst(fromJust(((!) b origin))))) of { False-> [xy]; _ -> [] }); _ -> [] })) }); many_ray_possibilities :: Board -> Coord -> [](Delta) -> [](Coord); many_ray_possibilities b origin delta = ((concatMap (ray_possibilities b origin))(delta)); type Delta = (Int, Int); queen_rays :: [](Delta); queen_rays = (let { p :: Int; p = 1; z :: Int; z = 0; n :: Int; n = (negate 1) } in (do{ x :: Int <- [p, z, n]; y :: Int <- [p, z, n]; (guard ((||) ((/=) x 0) ((/=) y 0))); (return (x, y)); })); rook_rays :: [](Delta); rook_rays = (do{ (x, y) :: Delta <- queen_rays; (guard ((==) 0 ((*) x y))); (return (x, y)); }); bishop_rays :: [](Delta); bishop_rays = (do{ (x, y) :: Delta <- queen_rays; (guard ((/=) 0 ((*) x y))); (return (x, y)); }); get_promotion :: Bool -> [](Maybe(Type_piece)); get_promotion do_promotion = (case do_promotion of { False-> (return Nothing); _ -> (map Just [Night, Bishop, Rook, Queen]) }); white_pawn_advance :: Board -> Coord -> [](Move_dest); white_pawn_advance b (Coord (row, col)) = (let { one :: Coord; one = (Coord (((+) row 1), col)); two :: Coord; two = (Coord (((+) row 2), col)) } in ((++) (do{ (guard (inRange (bounds b) one)); (guard ((==) Nothing ((!) b one))); promotion :: Maybe(Type_piece) <- (get_promotion ((==) ((+) row 1) bmax)); (return (Regular_move one promotion)); }) (do{ (guard ((==) row 1)); (guard ((==) Nothing ((!) b one))); (guard ((==) Nothing ((!) b two))); (return((Double_pawn (Empty_square_ep one) (Killed_piece_ep two)))); }))); black_pawn_advance :: Board -> Coord -> [](Move_dest); black_pawn_advance b (Coord (row, col)) = (let { one :: Coord; one = (Coord (((-) row 1), col)); two :: Coord; two = (Coord (((-) row 2), col)) } in ((++) (do{ (guard (inRange (bounds b) one)); (guard ((==) Nothing ((!) b one))); promotion :: Maybe(Type_piece) <- (get_promotion ((==) row 1)); (return (Regular_move one promotion)); }) (do{ (guard ((==) row ((-) bmax 1))); (guard ((==) Nothing ((!) b one))); (guard ((==) Nothing ((!) b two))); (return((Double_pawn (Empty_square_ep one) (Killed_piece_ep two)))); }))); pawn_attack_dir :: Int -> Board -> Coord -> [](Coord); pawn_attack_dir direction b (Coord (row, col)) = (do{ ncol :: Int <- [((-) col 1), ((+) col 1)]; let { advance :: Coord; advance = (Coord (((+) row direction), ncol)) }; (guard (inRange (bounds b) advance)); (return advance); }); night_steps :: [](Delta); night_steps = (let { sign :: [](Int); sign = [1, (negate 1)]; onetwo :: [](Int); onetwo = [1, 2] } in (do{ x :: Int <- onetwo; y :: Int <- onetwo; (guard ((/=) x y)); sx :: Int <- sign; sy :: Int <- sign; (return((((*) sx x), ((*) sy y)))); })); classify_pawn_capture :: Color -> Board -> Enpassant -> Coord -> [](Move_dest); classify_pawn_capture mycolor b enpassant c = (case enpassant of { (Enpassant (Empty_square_ep empty) killed) | ((==) c empty) -> (return (Enpassant_capture (Empty_square_ep empty) killed)) where { } ; _ -> (case ((!) b c) of { Nothing-> mzero; _ -> (do{ (guard ((/=) mycolor (get_color b c))); promotion :: Maybe(Type_piece) <- (get_promotion (is_promotion mycolor c)); (return (Regular_move c promotion)); }) }) }); is_promotion :: Color -> Coord -> Bool; is_promotion mycolor (Coord (row, _)) = ((||) ((&&) ((==) mycolor White) ((==) row bmax)) ((&&) ((==) mycolor Black) ((==) row 0))); data Move_dest = Double_pawn(Empty_square_ep)(Killed_piece_ep) | Enpassant_capture(Empty_square_ep)(Killed_piece_ep) | Regular_move(Coord)(Maybe(Type_piece)) deriving (Show); pawn_advance :: Color -> (Board -> Coord -> [](Move_dest)); pawn_advance color = (case color of { Black-> black_pawn_advance; White-> white_pawn_advance }); pawn_attack :: Color -> (Board -> Coord -> [](Coord)); pawn_attack color = (case color of { White-> (pawn_attack_dir 1); Black-> (pawn_attack_dir (negate 1)) }); get_pawn_moves :: Board -> Enpassant -> Coord -> [](Move_dest); get_pawn_moves b enpassant start = (let { color :: Color; color = (fst(fromJust(((!) b)(start)))) } in ((++) (pawn_advance color b start) ((concatMap (classify_pawn_capture color b enpassant))((pawn_attack color b start))))); ok_to_move :: Board -> Coord -> Coord -> Bool; ok_to_move b start destination = (case ((!) b destination) of { Nothing-> True; (Just (othercolor, _))-> ((/=) (get_color b start) othercolor) }); get_piece_moves :: Board -> Enpassant -> Coord -> [](Move_dest); get_piece_moves b enpassant start = (case (fst(snd(fromJust(((!) b)(start))))) of { Pawn-> (get_pawn_moves b enpassant start); _ -> (do{ c :: Coord <- (regular_moves b start); (return (Regular_move c Nothing)); }) }); regular_moves :: Board -> Coord -> [](Coord); regular_moves b start = (case (fst(snd(fromJust(((!) b)(start))))) of { night_or_king | ((||) ((==) night_or_king Night) ((==) night_or_king King)) -> ((filter (ok_to_move b start))((filter (inRange (bounds b)))((map (add_coord start))((case night_or_king of { Night-> night_steps; King-> queen_rays }))))) where { } ; ray_piece-> ((many_ray_possibilities b start)((case ray_piece of { Queen-> queen_rays; Bishop-> bishop_rays; Rook-> rook_rays }))) }); get_color :: Board -> Coord -> Color; get_color b start = (fst(fromJust(((!) b)(start)))); get_attacked_squares :: Board -> Coord -> [](Coord); get_attacked_squares b start = (do{ s :: Coord <- (case (fst(snd(fromJust(((!) b)(start))))) of { Pawn-> (pawn_attack (get_color b start) b start); _ -> (regular_moves b start) }); (guard ((==) Nothing ((!) b s))); (return s); }); board_my_pieces :: Board -> Color -> [](Coord); board_my_pieces b mycolor = (do{ (xy, mp) :: (Coord, Maybe(Piece)) <- (assocs b); (guard (isJust mp)); (guard(((==) mycolor)(fst(fromJust(mp))))); (return xy); }); all_attacked_squares :: Board -> Color -> [](Coord); all_attacked_squares b mycolor = (Set.toList(Set.fromList(concat((map (get_attacked_squares b))((board_my_pieces b mycolor)))))); type In_hand = Map.Map(Type_piece)(Int); foo :: Both_pieces_in_hand -> Int; foo a = (fromJust (Map.lookup King (fromJust((Map.lookup White)(a))))); instance Show (Coord) where { show (Coord (rank, file)) = ((++) [(chr ((+) (ord (head "a")) file))] (show ((+) rank 1))) } ; initial_board :: Board; initial_board = (let { w :: Color -> Type_piece -> Maybe(Piece); w color t = (Just (color, (t, Original))); first_rank :: [](Type_piece); first_rank = [Rook, Night, Bishop, Queen, King, Bishop, Night, Rook]; pawns :: [](Type_piece); pawns = (replicate 8 Pawn) } in (listArray board_range ((map (w White) first_rank) ++ (map (w White) pawns) ++ (replicate 32 Nothing) ++ (map (w Black) pawns) ++ (map (w Black) first_rank)))); type Both_pieces_in_hand = Map.Map(Color)(In_hand); data Game_state = Game_state(Board)(Enpassant)(Color)(Both_pieces_in_hand) deriving (Show); data Dmove = Pass | Rmove(Coord)(Move_dest) | Drop(Type_piece)(Coord) deriving (Show); data Enpassant = No_enpassant | Enpassant(Empty_square_ep)(Killed_piece_ep) deriving (Show); newtype Empty_square_ep = Empty_square_ep(Coord) deriving (Show, Eq); newtype Killed_piece_ep = Killed_piece_ep(Coord) deriving (Show, Eq); all_pieces :: [](Type_piece); all_pieces = [Pawn, Rook, Night, Bishop, Queen, King]; othercolor :: Color -> Color; othercolor c = (case c of { Black-> White; White-> Black }); execute_regular_move :: Game_state -> Coord -> Move_dest -> Game_state; execute_regular_move g@(Game_state oldboard _ color oldhand) origin (Regular_move dest mpromote) = (let { newboard :: Board; newboard = ((//) oldboard [(origin, Nothing), (dest, (case mpromote of { Nothing-> ((!) oldboard origin); (Just ty)-> (Just (color, (ty, Was_a_pawn))) }))]); newhand :: Both_pieces_in_hand; newhand = (case ((!) oldboard dest) of { Nothing-> oldhand; (Just (_, (ty, Original)))-> (increment_both_hand g ty); (Just (_, (_, Was_a_pawn)))-> (increment_both_hand g Pawn) }); theothercolor :: Color; theothercolor = (othercolor color) } in ((assert (case ((!) oldboard dest) of { Nothing-> True; (Just (oc, _))-> ((==) oc theothercolor) }))((assert ((==) color (fst(fromJust(((!) oldboard origin))))))((Game_state newboard No_enpassant theothercolor newhand))))); execute_enpassant :: Game_state -> Coord -> Move_dest -> Game_state; execute_enpassant g@(Game_state oldboard (Enpassant old_e old_k) color _) origin (Enpassant_capture e@(Empty_square_ep empty) k@(Killed_piece_ep killed)) = (let { newboard :: Board; newboard = ((//) oldboard [(origin, Nothing), (empty, ((!) oldboard origin)), (killed, Nothing)]); theothercolor :: Color; theothercolor = (othercolor color) } in ((assert ((==) (Just (theothercolor, (Pawn, Original))) ((!) oldboard killed)))((assert(isNothing(((!) oldboard)(empty))))((assert ((==) (Just (color, (Pawn, Original))) ((!) oldboard origin)))((assert ((&&) ((==) e old_e) ((==) k old_k)))((Game_state newboard No_enpassant theothercolor (increment_both_hand g Pawn)))))))); execute_double_pawn :: Game_state -> Coord -> Move_dest -> Game_state; execute_double_pawn (Game_state oldboard _ color oldpieces) origin (Double_pawn e@(Empty_square_ep empty) k@(Killed_piece_ep killed)) = (let { newboard :: Board; newboard = ((//) oldboard [(origin, Nothing), (killed, ((!) oldboard origin))]); theothercolor :: Color; theothercolor = (othercolor color) } in ((assert(isNothing(((!) oldboard)(killed))))((assert(isNothing(((!) oldboard)(empty))))((assert ((==) (Just (color, (Pawn, Original))) ((!) oldboard origin)))((Game_state newboard (Enpassant e k) theothercolor oldpieces)))))); execute_drop :: Game_state -> Type_piece -> Coord -> Game_state; execute_drop g@(Game_state oldboard _ color _) ty location = (let { newboard :: Board; newboard = ((//) oldboard [(location, (Just (color, (ty, Original))))]); theothercolor :: Color; theothercolor = (othercolor color) } in ((assert(isNothing(((!) oldboard)(location))))((Game_state newboard No_enpassant theothercolor (decrement_both_hand g ty))))); execute_pass :: Game_state -> Game_state; execute_pass (Game_state oldboard _ color oldhand) = (let { theothercolor :: Color; theothercolor = (othercolor color) } in (Game_state oldboard No_enpassant theothercolor oldhand)); execute_move :: Game_state -> Dmove -> Game_state; execute_move g dm = (case dm of { (Rmove origin m@(Regular_move _ _))-> (execute_regular_move g origin m); (Rmove origin m@(Enpassant_capture _ _))-> (execute_enpassant g origin m); (Rmove origin m@(Double_pawn _ _))-> (execute_double_pawn g origin m); (Drop ty loc)-> (execute_drop g ty loc); Pass-> (execute_pass g) }); initial_game_state :: Game_state; initial_game_state = (Game_state initial_board No_enpassant White (Map.fromList [(White, Map.empty), (Black, Map.empty)])); get_moves :: Game_state -> [](Dmove); get_moves g = ((:) Pass ((++) (get_drops g) (get_rmoves g))); get_drops :: Game_state -> [](Dmove); get_drops (Game_state board enpassant color hand) = (do{ empty :: Coord <- (all_attacked_squares board color); ((assert(isNothing(((!) board empty))))((return ()))); dropper :: Type_piece <- (available_pieces_in_hand ((Map.! ) hand color)); (guard (case dropper of { Pawn-> (pawn_drop_ok empty); _ -> True })); (return (Drop dropper empty)); }); get_rmoves :: Game_state -> [](Dmove); get_rmoves (Game_state board enpassant color hand) = (do{ p :: Coord <- (board_my_pieces board color); m :: Move_dest <- (get_piece_moves board enpassant p); (return (Rmove p m)); }); print_game_state :: Game_state -> IO(()); print_game_state (Game_state b _ _ hand) = (do{ (putStrLn(show_board(b))); (show_list(Map.toList(hand))); }); move_number :: Game_state -> Int -> Game_state; move_number g n = (execute_move g ((!!) (get_moves g) n)); st_execute_double_pawn :: STArray(s)(Coord)(Maybe(Piece)) -> ST(s)(()); st_execute_double_pawn oldgame = undefined; increment_in_hand :: In_hand -> Type_piece -> In_hand; increment_in_hand old t = (Map.insertWith (+) t 1 old); increment_both_hand :: Game_state -> Type_piece -> Both_pieces_in_hand; increment_both_hand (Game_state _ _ color hand) t = (let { old :: In_hand; old = ((Map.! ) hand color) } in (Map.insert color (increment_in_hand old t) hand)); decrement_both_hand :: Game_state -> Type_piece -> Both_pieces_in_hand; decrement_both_hand (Game_state _ _ color hand) t = ((assert ((<) 0 ((Map.! ) ((Map.! ) hand color) t)))((Map.insert color (Map.insertWith (+) t (negate 1) ((Map.! ) hand color)) hand))); available_pieces_in_hand :: In_hand -> [](Type_piece); available_pieces_in_hand hand = (do{ pc :: Type_piece <- all_pieces; (guard (case (Map.lookup pc hand) of { Nothing-> False; (Just (n ))-> ((<) 0 n) })); (return pc); }); numbered_move_list :: Game_state -> IO(()); numbered_move_list g = (show_list((zip (enumFrom 0))(get_moves(g)))); pawn_drop_ok :: Coord -> Bool; pawn_drop_ok (Coord (row, _)) = ((&&) ((<) 0 row) ((<) row bmax)); state_and_moves :: Game_state -> IO(()); state_and_moves g = (do{ (numbered_move_list g); ((getStdRandom(randomR((0, (pred(length(get_moves(g)))))))) >>= print); (print_game_state g); }); do_random_move :: Game_state -> IO(Maybe((Dmove, Game_state))); do_random_move g = (case (is_position_lost g) of { True-> (return Nothing); _ -> (do{ let { moves :: [](Dmove); moves = (get_moves g) }; (putStrLn ((show (length moves)) ++ " moves")); m :: Dmove <- (random_from_list moves); (return (Just (m, (execute_move g m)))); }) }); decer :: Integer -> IO(Integer); decer x = (do{ (return ((-) x 2)); }); manydecer :: Integer -> IO(()); manydecer start = (do{ once :: Integer <- (decer start); (case once of { 0-> (do{ (putStrLn "done"); }); _ -> (manydecer once) }); }); many_moves :: Game_state -> IO(()); many_moves start = (do{ mmove :: Maybe((Dmove, Game_state)) <- (depth_one_search start); (case mmove of { Nothing-> (return ()); (Just (move, newstate))-> (do{ (putStrLn (show move)); (print_game_state newstate); (putStrLn "====="); (many_moves newstate); }) }); }); is_position_lost :: Game_state -> Bool; is_position_lost (Game_state board _ color _) = (null (board_my_pieces board color)); depth_one_search :: Game_state -> IO(Maybe((Dmove, Game_state))); depth_one_search g = (case (is_position_lost g) of { True-> (return Nothing); _ -> (let { moves2 :: [](Dmove); moves2 = (depth_one_moves g) } in (do{ m :: Dmove <- (random_from_list moves2); (return (Just (m, (execute_move g m)))); })) }); capturing_rmove :: Game_state -> Dmove -> Bool; capturing_rmove (Game_state board _ _ _) m = (case m of { (Rmove _ (Double_pawn _ _))-> False; (Rmove _ (Enpassant_capture _ _))-> True; (Rmove _ (Regular_move dest _))-> (isJust ((!) board dest)) }); depth_one_moves :: Game_state -> [](Dmove); depth_one_moves g = (case ((filter (is_position_lost . (execute_move g)))(get_rmoves(g))) of { ([] )-> (get_moves g); x-> x }); many_moves_counter :: Int -> Game_state -> IO(()); many_moves_counter counter start = (do{ mmove :: Maybe((Dmove, Game_state)) <- (depth_one_search start); (case mmove of { Nothing-> (print counter); (Just (move, newstate))-> (do{ (let { } in (seq counter (many_moves_counter (succ counter) newstate))); }) }); }) }