# Implementing the rules of 3 Man Chess: Variant “In The Round”. Part 1, Fundamental Types Of Fundamental Values

Apr 22, 2018 · 5 min read

For the past three years, my go-to project for learning new programming languages and paradigms was the implementation of the rules of 3 Man Chess: Variant “In The Round”. I have used it to learn much about Go, Dart, Java, Clojure and Haskell. All the implementation attempts are available on my Github profile. So what’s the matter with the “attempts” word, why none of them is working, what’s so difficult? This is what this series is going to be about. But these it this “pilot” article, in this part, will be just fundamental data types because I don’t have much time. I have festival presentation deadlines for this project. One of them is today, in four hours. So, if you could look at the entirety of the code and help me, please do. https://github.com/ArchieT/ThreeManChess

First, the board. It is a circular board, consisting of six rings, later called `Rank`s, numbered from `0` (`MostOuter`) to `5` (`MostInner`).

`data Rank = MostOuter | SecondOuter | MiddleOuter           | MiddleInner | SecondInner | MostInner   deriving (Eq, Ord, Read, Show)ranks :: [Rank]inw :: Rank -> Rankout :: Rank -> Maybe Rank`

Each of those ranks consists of 24 `File`s.

The board is divided in three, one for each of the players. Opponents’ rooks are next to each other, but they cannot capture each other because of a feature called “moats”. Neither can pawns, because of a feature called “creeks”. If you want to know how it looks or have other questions, www.3manchess.com may answer them.

0. Set all Kings on white. White goes first, then clockwise to gray, then black.

`data Color = White | Gray | Black  deriving (Eq, Ord, Read)next :: Color -> Colorprev :: Color -> Color`

So now we also need some data type that would correspond to number from `0` to `7`, why not just use an `Integer` type? Because we want to be protected with our Haskellish type system, and another way we do this data type of ours may turn beneficial to us in some ways. So. Say hello to

`data SegmentHalf = FirstHalf | SecondHalf   deriving (Eq, Ord, Read, Show)data SegmentQuarter = SegmentQuarter   { half :: SegmentHalf  , halfQuarter :: SegmentHalf }  deriving (Eq, Ord, Read, Show)data SegmentEight = SegmentEight   { segmentQuarter :: SegmentQuarter  , quarterHalf :: SegmentHalf }   deriving (Eq, Ord, Read, Show)type ColorSegment = Colordata File = File { segmColor :: ColorSegment                 , colorSegmFile :: SegmentEight }  deriving (Eq, Ord, Read, Show)opposite :: File -> Fileplus :: File -> Fileminus :: File -> File-- and finallytype Pos = (Rank, File)rank :: Pos -> Rankfile :: Pos -> File-- |'kfm' is where the King standskfm :: SegmentEightkfm = (SegmentEight (SegmentQuarter SecondHalf FirstHalf) FirstHalf)`

Okay, enough about the board coordinates data structures.

1. The center of the board may be passed through, but has no square to be occupied.

a. Adjoining vertical squares, through the center, maintain the same color.

i. Queen, King, Rook, or Pawn, advancing 1 square through center, retains same color.

ii. Knight also will retain same color.

iii. This phenomenon is necessary to maintain ‘round board’ integrity. As players should be aware of this, conventional Chess strategy is not compromised.

[…]

3. VERTICAL MOVES (Queen, King, Rook, Pawn)

a. Follows straight, (and if necessary, through the center), along the checkerboard file.

And a Pawn can go only forward. So, we do not want to prove that it is not possible for a Pawn to perform so many captures as to it become unsure if it’s directed inwards or outwards, and am unsure if I had proven it to be impossible sometime ago already, but anyway such distinction helps. Therefore,

`data FigType = InwardPawn | OutwardPawn | Rook | Knight             | Bishop | King | Queen  deriving (Eq, Read)--for promotion purposes, we will also definedata Promotion = RookPromotion | KnightPromotion |               | BishopPromotion | QueenPromotion  deriving (Eq, Show)desiredType :: Promotion -> FigType`

4. HORIZONTAL MOVES (Queen, King, Rook)

a. Rotate about the center on the same row (rank).

So the moves are, like, modulo 24.

2. DIAGONAL MOVES (Queen, King, Bishop, or Pawn capturing)

a. Follow 1 of the 2 trajectory lines out from the square it rest on.

On the board, there are 48 diagonal trajectory lines, pairs of them crossing over each one of the squares. On the `MostOuter` rank, on each of the files a pair of trajectory lines forms a corner. Each of those pairs forms a loop over the center.

b. May rotate through the center.

c. Can not ‘turn the corner’ at the outer rank, in 1 move.

Also, what is not included in the rules but what was stated to be the right thing by Mr Clif King, the owner of 3 Man Chess, and I guess their creator, in our correspondence when I asked for this specifically and argumented for it, and which is not yet included in the rules, the figure must not go diagonally through the center or filewise(horizontally) around the center back to the square it went from — it would cause oft something like a lack of zugzwang (compulsion to move), an important feature of chess, and would have serious consequences in gameplay, especially in case of computer gameplay.

5. KNIGHT MOVES

a. 2 squares vertically then 1 square horizontally, or

b. 1 square vertically then 2 horizontally.

c. Use 1 of the 2 methods above (i.e., do not follow a trajectory line through the center). Also, these 2 methods are necessary for BORDER CONTROL described below.

These are just about the same, until when it comes to “border control”, i.e. “moats”.

So, there are multiple ways to perform a single from→to move, which we need to handle separately to avoid unnecessary computations. Therefore, we need data structures for that

`data Orientation = Rankwise | Filewise deriving (Eq, Read, Show)data RankwiseDirection = Inwards | Outwards  deriving (Eq, Show)data FilewiseDirection = Pluswards | Minuswards  deriving (Eq, Show)filewiseInc :: FilewiseDirection -> File -> Filedata DiagonalDirection = DiagonalDirection                         RankwiseDirection                         FilewiseDirection  deriving (Eq, Show)data Count = Once | OnceMore Count deriving (Eq, Read, Show)class (Eq a) => LinearDirection a where  addOne :: a -> Pos -> Maybe Posinstance LinearDirection RankwiseDirection where  addOne Inwards (MostInner, file) =     Just (MostInner, opposite file)  addOne Inwards (rank, file) =     Just (inw rank, file)  addOne Outwards (rank, file) =    do { o <- out rank;         return (o, file) }instance LinearDirection FilewiseDirection where  addOne w (rank, file) = Just (rank, filewiseInc w file)instance LinearDirection DiagonalDirection where  addOne (DiagonalDirection Inwards p)         (MostInner, file) = ... --long case expressions here  addOne (DiagonalDirection Inwards p) (rank, file) =     Just (inw rank, filewiseInc p file)  addOne (DiagonalDirection Outwards p) (rank, file) =     do { o <- out rank; return (o, filewiseInc p file) }`

I have to go back to work now, and I am not sure if I have good reasons not to publish this beginning. There were almost no difficulties so far in this post, though even those few caveats took me many man-days of thinking back in the days. I am writing this post to motivate myself and to clarify the fundamentals of my code. Aaaand I’m hoping for collaborators. Really. Any. Any collaborators. You don’t need to know Haskell for more than a few hours, you will learn Haskell along the way.

If you want more information about something like “why don’t the rooks capture each other” or “what does it all look like”, look at www.3manchess.com.

Should I update this post later or just post next parts? Maybe posting next parts will be better.

Written by