ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# jim108dev's solution

## to Queen Attack in the Haskell Track

Published at Apr 06 2021 · 0 comments
Instructions
Test suite
Solution

Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.

In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal.

A chessboard can be represented by an 8 by 8 array.

So if you're told the white queen is at (2, 3) and the black queen at (5, 6), then you'd know you've got a set-up like so:

_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ B _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _

You'd also be able to answer whether the queens can attack each other. In this case, that answer would be yes, they can, because both pieces share a diagonal.

## Hints

To complete this exercise, you need to implement the following functions:

• boardString
• canAttack

You will find the type signatures already in place, but it is up to you to define the functions.

Positions are specified as two-tuples:

• The first element is the row (rank in Chess terms).
• The second element is is the column (file in Chess terms).
• (0, 0) is the top left of the board, (0, 7) is the upper right,
• (7, 0) is the bottom left, and (7, 7) is the bottom right.

## Getting Started

Please refer to the installation and learning help pages.

## Running the tests

To run the test suite, execute the following command:

stack test

#### If you get an error message like this...

No .cabal file found in directory

You are probably running an old stack version and need to upgrade it.

#### Otherwise, if you get an error message like this...

No compiler found, expected minor version match with...
Try running "stack setup" to install the correct GHC...

Just do as it says and it will download and install the correct compiler version:

stack setup

## Running GHCi

If you want to play with your solution in GHCi, just run the command:

stack ghci

## Feedback, Issues, Pull Requests

The exercism/haskell repository on GitHub is the home for all of the Haskell exercises.

If you have feedback about an exercise, or want to help implementing a new one, head over there and create an issue. We'll do our best to help you!

## Source

J Dalbey's Programming Practice problems http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### Tests.hs

{-# OPTIONS_GHC -fno-warn-type-defaults #-}

import Data.Foldable     (for_)
import Test.Hspec        (Spec, describe, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

import Queens (boardString, canAttack)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = do

-- Track-specific test cases.

describe "boardString" \$ do

it "empty board" \$ boardString Nothing Nothing
`shouldBe` unlines [ "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _" ]

it "board with just white queen" \$ boardString (Just (2, 4)) Nothing
`shouldBe` unlines [ "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ W _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _" ]

it "board with just black queen" \$ boardString Nothing (Just (0, 0))
`shouldBe` unlines [ "B _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _" ]

it "board" \$ boardString (Just (2, 4)) (Just (6, 6))
`shouldBe` unlines [ "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ W _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ _ _"
, "_ _ _ _ _ _ B _"
, "_ _ _ _ _ _ _ _" ]

-- The function described by the reference file as `create` doesn't
-- exist in this track, so only the `canAttack` test cases were
-- implemented here

describe "canAttack" \$ do

let test (description, white, black, expected) =
it description \$ canAttack white black `shouldBe` expected

cases = [ ("can not attack"               , (2, 4), (6, 6), False)
, ("can attack on same rank"      , (2, 4), (2, 6), True )
, ("can attack on same file"      , (4, 5), (2, 5), True )
, ("can attack on first diagonal" , (2, 2), (0, 4), True )
, ("can attack on second diagonal", (2, 2), (3, 1), True )
, ("can attack on third diagonal" , (2, 2), (1, 1), True )
, ("can attack on fourth diagonal", (2, 2), (5, 5), True ) ]

for_ cases test

-- cc646595d39e13c4d310da2629599bcc45e92bd9
module Queens
( boardString
, canAttack
) where

import           Control.Lens                   ( set )
import           Control.Lens.Traversal         ( element )
import           Data.List                      ( intersperse )
import           Data.List.Split                ( chunksOf )
import           GHC.OldList                    ( intercalate )

boardString :: Maybe (Int, Int) -> Maybe (Int, Int) -> String
boardString (Just w) (Just b) =
prettify \$ setQueen 'B' b \$ setQueen 'W' w emptyBoard
boardString (Just w) _        = prettify \$ setQueen 'W' w emptyBoard
boardString _        (Just b) = prettify \$ setQueen 'B' b emptyBoard
boardString _        _        = prettify \$ emptyBoard

setQueen :: Char -> (Int, Int) -> String -> String
setQueen c (i, j) = set (element (i * 8 + j)) c

emptyBoard :: String
emptyBoard = replicate 64 '_'

prettify :: String -> String
prettify board =
intercalate "\n" (intersperse ' ' <\$> chunksOf 8 board) ++ "\n"

canAttack :: (Int, Int) -> (Int, Int) -> Bool
canAttack (i1, j1) (i2, j2) =
(i1 == i2) || (j1 == j2) || abs (i2 - i1) == abs (j2 - j1)