Peter
Peter Campbell Smith

Matching and returning

Weekly challenge 293 — 28 October 2024

Week 293: 28 Oct 2024

Task 1

Task — Similar dominoes

You are given a list of dominoes, @dominoes. Write a script to return the number of dominoes that are similar to any other domino.

$dominoes[i] = [a, b] and $dominoes[j] = [c, d] are similar if either:
(a = c and b = d) or (a = d and b = c).

Examples


Example 1
Input: @dominos = ([1, 3], [3, 1], [2, 4], [6, 8])
Output: 2
Similar Dominos: $dominoes[0], $dominoes[1]

Example 2
Input: @dominos = ([1, 2], [2, 1], [1, 1], [1, 2], 
   [2, 2])
Output: 3
Similar Dominos: $dominoes[0], $dominoes[1], $dominoes[3]

Analysis

Ever the pedant, my first observation is that dominoes, at least as played in the UK, have 0-6 spots on each side, so the 8 in example 1 is a little surprising. However, in the spirit of agreeing with the boss, I have provided a solution that works for any integral non-negative number of spots.

It's a slightly awkward challenge in that we are required to return the indices of the similar dominoes in the original array. My first thought was to sort the array, but that would lose the original order.

So my solution does this:

  • change all the dominoes to have the lower spot count first:
    eg 2, 1 becomes 1, 2
  • loop through @dominoes, appending each to an element of %matches, for example, $matches{'1|2'}
  • listing as similar those elements in %matches where the hash value contains more than one domino

Try it 

Try running the script with any input:



example: [1, 3], [3, 1], [2, 4], [6, 8]

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2024-10-28
use utf8;     # Week 293 - task 1 - Similar dominoes
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

similar_dominoes([6, 8], [1, 3], [3, 1], [2, 4]);
similar_dominoes([10, 12], [12, 10], [33, 34], [34, 33]);
similar_dominoes([6, 8], [1, 3], [4, 1], [2, 4]);

# bigger example
my @d;
for (0 .. 19) {
    push @d, [int(rand(7)), int(rand(7))];
}
similar_dominoes(@d);

sub similar_dominoes {
    
    my ($input, @dominoes, $d, %matches, $some);
    @dominoes = @_;
    $input .= qq{[$_->[0], $_->[1]], } for @dominoes;
    say qq[\nInput:  (] . substr($input, 0, -2) . ')';
    
    # sort each domino to have smallest value first (eg 2, 1 -> 1, 2)
    @dominoes = map ($_->[0] <= $_->[1] ? [$_->[0],  $_->[1]] :  [$_->[1],  $_->[0]], @dominoes);
    
    # gather together ones that match
    for $d (0 .. $#dominoes) {
        $matches{qq[$dominoes[$d]->[0]|$dominoes[$d]->[1]]} .= qq[\$dominoes[$d], ];
    }
    
    # list the ones where >1 match
    $some = 0;
    say qq[Output: Similar Dominoes:];
    for $d (keys %matches) {
        print qq[   ] . substr($matches{$d}, 0, -2) if $matches{$d} =~ m|,.*,|;
        if ($matches{$d} =~ m|(\d+).+?(\d+)|) {
            say qq[ ($dominoes[$1]->[0] and $dominoes[$1]->[1])];
            $some = 1;
        }
    }
    say qq[   None] unless $some;
}

Output


Input:  ([6, 8], [1, 3], [3, 1], [2, 4])
Output: Similar Dominoes:
   $dominoes[1], $dominoes[2] (1 and 3)

Input:  ([10, 12], [12, 10], [33, 34], [34, 33])
Output: Similar Dominoes:
   $dominoes[0], $dominoes[1] (10 and 12)
   $dominoes[2], $dominoes[3] (33 and 34)

Input:  ([6, 8], [1, 3], [4, 1], [2, 4])
Output: Similar Dominoes:
   None

Input:  ([5, 0], [0, 1], [0, 1], [6, 0], [5, 1], [6, 3],
   [6, 0], [2, 6], [2, 5], [4, 4], [6, 5], [1, 6],
   [1, 0], [5, 0], [6, 2], [1, 6], [4, 4], [6, 1],
   [3, 5], [0, 5])
Output: Similar Dominoes:
   $dominoes[3], $dominoes[6] (6 and 0)
   $dominoes[11], $dominoes[15], $dominoes[17] (1 and 6)
   $dominoes[1], $dominoes[2], $dominoes[12] (0 and 1)
   $dominoes[7], $dominoes[14] (2 and 6)
   $dominoes[0], $dominoes[13], $dominoes[19] (5 and 0)
   $dominoes[9], $dominoes[16] (4 and 4)

 

Any content of this website which has been created by Peter Campbell Smith is in the public domain