-- | Coordinate of one square on the Chu Shogi board -- Copyright 2009 Colin Adams -- -- This file is part of chu-shogi. -- -- Chu-shogi 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. -- Chu-shogi 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 chu-shogi. If not, see . module Coordinate ( -- * Types Coordinate, -- * Creation new_coordinate, -- * Access rank, file, path_to, distance_from, -- * Status report good_coordinates, -- * Output print_coordinate ) where import Data.Char (chr, ord) -- | Coordinate, pairs rank and file represnted as integers in range 0-11 newtype Coordinate = Coordinate (Int12, Int12) deriving (Eq, Show) instance Ord Coordinate where compare c1 c2 = case compare (file c1) (file c2) of o | o == EQ -> compare (rank c1) (rank c2) o | otherwise -> o -- | Integers restricted to the range 0-11 newtype Int12 = Int12 Int deriving (Eq, Ord, Read, Show) instance Num Int12 where Int12 x + Int12 y | x + y <= 11 = Int12 (x + y) | otherwise = error "Int12 addition out of range" Int12 x - Int12 y | x - y >= 0 = Int12 (x - y) | otherwise = error "Int12 subtraction out of range" Int12 x * Int12 y | x * y <= 11 = Int12 (x * y) | otherwise = error "Int12 multiplication out of range" abs (Int12 x) = Int12 x signum (Int12 x) | (x == 0) = Int12 0 | otherwise = Int12 1 fromInteger x | (x >= 0 && x <= 11) = Int12 (fromInteger x) | otherwise = error "Int12 fromInteger out of range" {-# contract new_coordinate :: {rank' | rank' >= 0 && rank' <= 11} -> {file' | file' >= 0 && file' <= 11} -> {r | rank' r == rank' && file' r == file'} #-} -- | Coordinated created from two 'Int's new_coordinate :: Int -- ^ Rank (0 = a in standard Chu Shogi notation) -> Int -- ^ File (0 = 1 in standard Chu Shogi notation) -> Coordinate new_coordinate rank' file' = Coordinate (Int12 rank', Int12 file') {-# contract rank :: Ok -> {r | r >= 0 && r <= 11} #-} -- | Rank expressed as an 'Int' (0 = a in standard Chu Shogi notation) rank :: Coordinate -> Int rank c = case c of Coordinate (Int12 r, Int12 _) -> r {-# contract file :: Ok -> {r | r >= 0 && r <= 11}#-} -- | File expressed as an 'Int' (0 = 1 in standard Chu Shogi notation) file :: Coordinate -> Int file c = case c of Coordinate (Int12 _, Int12 f) -> f {-# contract path_to :: Ok -> Ok -> ({x | x >= 0 && x <= 11}, {y | y >= 0 && y <= 11}) #-} -- | Change in rank and file to get from source to target path_to :: Coordinate -- ^ Origin -> Coordinate -- ^ Destination -> (Int, Int) -- ^ Change in (rank, file) path_to source target = let r = rank source f = file source r' = rank target f' = file target in (r' - r, f' - f) {-# contract distance_from :: Ok -> Ok -> {r | r >= 0 && r <= 11} #-} -- | Greater of unsigned diffences in ranks or file between target and source distance_from :: Coordinate -- ^ Any square -> Coordinate -- ^ Any other square -> Int distance_from target source = let r = rank source f = file source r' = rank target f' = file target ranks = abs (r - r') files = abs (f - f') in max ranks files -- | Are rank' and file' valid for 'new_coordinates'? good_coordinates :: Int -- ^ Rank -> Int -- ^ File -> Bool good_coordinates rank' file' = rank' >= 0 && rank' <= 11 && file' >= 0 && file' <= 11 -- | Standard Chu Shogi notation for coord print_coordinate :: Coordinate -- ^ Coordinate to be printed -> String print_coordinate coord = let r = chr ((rank coord) + (ord 'a')) in (show $ (file coord) + 1) ++ [r]