Can you connect the dots?

18

2

This challenge is based off of Flow Free. An online version can be found here: http://www.moh97.us/

You will be given a puzzle, and you must return 1 if the puzzle is solvable, or 0 if it is not.

To solve a puzzle, the player must create a path to connect each pair of numbers using every empty square exactly once.

You are passed in the dimensions of the square, and then the x,y,c (where c is a number representing the color) of each dot. For example:

If 5,5 0,0,0 3,0,1 1,1,2 1,2,2 4,2,1 4,4,0 was passed to you, it would represent:

0..1.
.2...
.2..1
....0

And should return 1.


Here are some more test problems:

5,2 2,0,1 0,1,2 4,1,2 represents:

..1..
2...2

and is not solvable because there is only 1 1.

4,2 0,0,0 3,0,0 0,1,0 3,1,0 represents:

0..0
0..0

and is not solvable because it includes more than 2 0s.

8,6 0,0,1 7,5,1 represents:

1.......
........
........
........
........
.......1

and is not solvable (as you can't use every square).

2,5 0,0,1 2,0,6 4,0,6 0,1,4 3,1,4 4,1,1 represents:

1.6.6
4..41

and is not solvable because you cannot connect the 1s.

6,3 1,0,4 5,0,1 0,1,4 1,1,3 5,1,3 0,2,2 3,2,2 5,2,1 represents:

.4...1
43...3
2..2.1

and is not solvable because you cannot connect the 1s (or the 3s), as the two paths must necessarily cross.

5,2 0,0,1 3,0,1 0,1,3 4,1,1 represents:

1..1.
3...3

and is not solvable because you cannot use all of the squares in building a path.

2,2 0,0,0 1,1,0 represents:

1.
.1

and is not solvable because you can't use all of the squares here either

Here are some more tests:

5,5 0,3,0 0,4,1 1,2,2 1,3,1 2,0,0 3,0,4 3,1,2 3,3,5 3,4,4 4,4,5 should return 1

13,13 1,1,0 9,1,1 10,1,2 11,1,3 1,2,4 2,2,5 5,2,6 7,2,7 3,3,0 5,4,6 6,4,1 9,6,3 4,7,8 5,8,9 12,8,8 11,9,10 2,10,4 4,10,2 9,10,5 11,10,7 1,11,9 12,12,10 should return 1

7,7 0,0,0 0,1,1 1,1,2 2,1,3 4,2,4 0,3,1 5,3,3 0,4,4 2,4,5 5,4,2 0,5,0 1,5,5 3,5,6 3,7,6 should return 0


This is a code golf, and the standard rules apply.

Nathan Merrill

Posted 2014-09-30T16:26:21.357

Reputation: 13 591

Is 13,13 1,1,0 9,1,1 10,1,2 11,1,3 1,2,4 2,2,5 5,2,6 7,2,7 3,3,0 5,4,6 6,4,1 9,6,3 4,7,8 5,8,9 12,8,8 11,9,10 2,10,4 4,10,2 9,10,5 11,10,7 1,11,9 12,12,10 actually a valid input? You refer to "digit color"s, but 10 is not a digit - is this a mistake, or else what are the constraints on c? – VisualMelon – 2015-04-16T16:00:15.623

1@VisualMelon Digit color is the wrong word. Each color is represented by a different number, not digit. – Nathan Merrill – 2015-04-16T16:03:21.827

Can we assume that color "numbers" are non-negative and have some upper bound? – Geobits – 2015-04-21T15:25:38.627

They are non-negative, and assume that they are in the integer range for your language. – Nathan Merrill – 2015-04-21T15:28:51.560

Any style of IO & args acceptable? e.g. function vs program, return value vs stdout, etc. – Darren Stone – 2014-09-30T16:51:54.403

@DarrenStone yes. – Nathan Merrill – 2014-09-30T16:58:04.117

2Does a solution have to be "realistically" correct or just theoretically correct? For instance, the state space can be broken down into assigning one of 6 possible input-to-input configurations to each empty cell. Solvability is easily determined by attempting all 6^N combinations and returning 1 if any one of them visits all cells and connects all terminals. Obviously this approach wouldn't complete in a reasonable amount of time for anything but the smallest N (number of empty cells), but we still have a mathematical guarantee that the algorithm would eventually return the correct value. – COTO – 2014-09-30T17:46:16.370

I would expect the algorithm to solve the 13x13 board I gave in under a minute. If brute force works, then go ahead. – Nathan Merrill – 2014-09-30T20:48:30.850

@NathanMerrill: In that case, you may have some kind of NP hardness combined with state explosion working against you here. For the case of a 13x13 grid with 1's in opposing corners, the number of potential solutions is astronomical. A general solver realistically couldn't rely on brute force of any kind. Barring that as an option, the only solutions I can envision would be topological in nature and would require small libraries worth of code to implement. – COTO – 2014-10-01T13:33:31.260

1Perhaps if you came up with two huge sets of playing grids (one public for testing, one private for validation) using a common algorithm and deemed the winner to be the submission that correctly identified the solvability of the most grids in the private set in some reasonable amount of time per grid, with program size as a tiebreaker if two submissions had equal utility. I'd definitely try my hand at that. – COTO – 2014-10-01T13:33:54.633

@COTO I do not think this is a NP hard problem. A person would easily be able to determine if it is solvable or not. A correct puzzle is possible to solve logically. – Nathan Merrill – 2014-10-01T13:59:44.790

1

@NathanMerrill: The problem is reducible to SAT and thus NP hard.

– COTO – 2014-10-01T17:13:53.307

3@NathanMerrill reducing a problem to SAT means that the problem is in NP, not that it is NP-hard -- it's reducing SAT to a problem that shows NP-hardness of the problem. The page you linked to does have a link to a proof of NP-completeness though. – cardboard_box – 2014-10-02T14:47:45.843

Answers

3

Haskell

import Data.List.Split
import qualified Data.Sequence as Q
import Data.List
import Control.Monad

data A a = S a | E a | P a | X deriving Eq

sc = foldr1 (Q.><)
sp b x y p = Q.update y (Q.update x p $ b `Q.index` y) b
dt b c | S c `elem` sc b = E c
       | otherwise = S c
ad b [x, y, c] = sp b x y (dt b c)

ep b [x, y, c] = do
  let nps = filter ob [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
      ns = map gp nps
  [b | E c `elem` ns] ++ do
    (x', y') <- filter ((== X) . gp) nps
    ep (sp b x' y' (P c)) [x', y', c]
  where ob (u, v) = 0 <= u && u < length (b `Q.index` 0) && 0 <= v && v < length b
        gp (u, v) = b `Q.index` v `Q.index` u

rd i = let [c, r] : ps = (map read . splitOn ",") <$> words i :: [[Int]]
           e = Q.replicate r $ Q.replicate c X
           cs = map last ps
           ss = nubBy (\[_,_,c1] [_,_,c2] -> c1 == c2) ps
           b = foldl ad e ps
           bs = foldM ep b ss
       in if even (length cs) && length ss == length cs `div` 2 &&
             (all (\[j,k] -> j==k) . chunksOf 2 . sort $ cs) &&
             any (null . Q.elemIndicesL X . sc) bs
           then 1
           else 0

main = rd <$> getContents >>= print

Key

  • sc: Seq concat
  • sp: set position
  • dt: dot type (ie, start or end of line)
  • ad: add dot
  • ep: extend path
  • rd: run dots (primary pure algorithm)

Matt

Posted 2014-09-30T16:26:21.357

Reputation: 164

2Thanks for the submission, and welcome to PPCG stack exchange. This is a code golf challenge, meaning the purpose is to write the shortest program which solves the challenge. You're in the lead, because you have the only answer, but you should try to shorten your program as much as possible. – isaacg – 2015-05-25T01:13:15.270

I'm honestly impressed that you answered this question after all this time. Also, this problem was more of a code-challenge, but I used code-golf, as it was hard to come up with a different scoring basis. – Nathan Merrill – 2015-05-25T14:03:33.617

Yes, I didn't worry too much about the "golf" aspect; I'm trying to learn Haskell and it seemed like a fun problem :-) – Matt – 2015-05-26T15:46:39.013