Checking the validity of a pyramid of dominoes

Viewed 6421

I came across this question in a coding interview and couldn't figure out a good solution.

You are given 6 dominoes. A domino has 2 halves each with a number of spots. You are building a 3-level pyramid of dominoes. The bottom level has 3 dominoes, the middle level has 2, and the top has 1.

The arrangement is such that each level is positioned over the center of the level below it. Here is a visual:

         [ 3 | 4 ]
    [ 2 | 3 ] [ 4 | 5 ]
[ 1 | 2 ][ 3 | 4 ][ 5 | 6 ]

The pyramid must be set up such that the number of spots on each domino half should be the same as the number on the half beneath it. This doesn't apply to neighboring dominoes on the same level.

Is it possible to build a pyramid from 6 dominoes in the arrangement described above? Dominoes can be freely arranged and rotated.

Write a function that takes an array of 12 ints (such that arr[0], arr[1] are the first domino, arr[2], arr[3] are the second domino, etc.) and return "YES" or "NO" if it is possible or not to create a pyramid with the given 6 dominoes.

Thank you.

4 Answers

You can do better than brute-forcing. I don't have the time for a complete answer. So this is more like a hint.

Count the number of occurrences of each number. It should be at least 3 for at least two numbers and so on. If these conditions are not met, there is no solution. In the next steps, you need to consider the positioning of numbers on the tiles.

Just iterate every permutation and check each one. If you find a solution, then you can stop and return "YES". If you get through all permutations then return "NO". There are 6 positions and each domino has 2 rotations, so a total of 12*10*8*6*4*2 = 46080 permutations. Half of these are mirrors of each other so we're doubling our necessary workload, but I don't think that's going to trouble the user. I'd fix the domino orientations, then iterate through all the position permutations, then iterate the orientation permutations and repeat.

So I'd present the algorithm as:

For each permutation of domino orientations
    For each permutation of domino positions
        if arr[0] == arr[3] && arr[1] == arr[4] && arr[2] == arr[7] && arr[3] == arr[8] && arr[4] == arr[9] && && arr[5] == arr[10] then return "YES"
return "NO"

At that point I'd ask the interviewer where they wanted to go from there. We could look at optimisations, equivalences, implementations or move on to something else.

We can formulate a recursive solution:

valid_row:
  if row_index < N - 1:
    copy of row must exist two rows below
  if row_index > 2:
    matching left and right must exist
    on the row above, around a center
    of size N - 3, together forming
    a valid_row
  if row_index == N - 1:
    additional matching below must
    exist for the last number on each side

One way to solve it could be backtracking while tracking chosen dominoes along the path. Given the constraints on matching, a six domino pyramid ought to go pretty quick.

Before I start... There is an ambiguity in the question, which may be what the interviewer was more interested than the answer. This would appear to be a question asking for a method to validate one particular arrangement of the values, except for the bit which says "Is it possible to build a pyramid from 6 dominoes in the arrangement described above? Dominoes can be freely arranged and rotated." which implies that they might want you to also move the dominoes around to find a solution. I'm going to ignore that, and stick with the simple validation of whether it is a valid arrangement. (If it is required, I'd split the array into pairs, and then brute force the permutations of the possible arrangements against this code to find the first one that is valid.)

I've selected C# as a language for my solution, but I have intentionally avoided any language features which might make this more readable to a C# person, or perform faster, since the question is not language-specific, so I wanted this to be readable/convertible for people who prefer other languages. That's also the reason why I've used lots of named variables.

Basically check that each row is duplicated in the row below (offset by one), and stop when you reach the last row.

The algorithm drops out as soon as it finds a failure. This algorithm is extensible to larger pyramids; but does no validation of the size of the input array: it will work if the array is sensible.

using System;

public static void Main()
{
    int[] values = new int[] { 3, 4, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6 };
    bool result = IsDominoPyramidValid(values);
    Console.WriteLine(result ? "YES" : "NO");
}

private const int DominoLength = 2;

public static bool IsDominoPyramidValid(int[] values)
{
    int arrayLength = values.Length;

    int offset = 0;
    int currentRow = 1; // Note: I'm using a 1-based value here as it helps the maths
    bool result = true;
    while (result)
    {
        int currentRowLength = currentRow * DominoLength;

        // Avoid checking final row: there is no row below it
        if (offset + currentRowLength >= arrayLength)
        {
            break;
        }

        result = CheckValuesOnRowAgainstRowBelow(values, offset, currentRowLength);
        offset += currentRowLength;
        currentRow++;
    }

    return result;
}

private static bool CheckValuesOnRowAgainstRowBelow(int[] values, int startOfCurrentRow, int currentRowLength)
{
    int startOfNextRow = startOfCurrentRow + currentRowLength;
    int comparablePointOnNextRow = startOfNextRow + 1;
    for (int i = 0; i < currentRowLength; i++)
    {
        if (values[startOfCurrentRow + i] != values[comparablePointOnNextRow + i])
        {
            return false;
        }
    }

    return true;
}
Related