Peter
Peter Campbell Smith

Mean Brazilians

Weekly challenge 157 — 21 March 2022

Week 157 - 21 Mar 2022

Task 2

Task — Brazilian number

You are given a number $n > 3. Write a script to output 1 if the given number is a Brazilian Number or 0 if it isn't.

A Brazilian number is a positive integer N for which a base B exists where N written in that base consists of repetitions of the same digit - excluding 11. (See Wikipedia for more info.)

Examples


Example 1:
Input: $n = 7
Output: 1
Since 7 in base 2 is 111.

Example 2:
Input: $n = 6
Output: 0
Since 6 in base 2 is 110,
      6 in base 3 is 20 and
      6 in base 4 is 12.

Example 3:
Input: $n = 8
Output: 1
Since 8 in base 3 is 22.

Analysis

My solution simply checks $n in every base up to $n / 2. You can stop there, because any higher base will give representations between 1x (where x is the representation of (base - 1), eg 9 in decimal) down to 11. That means that I don't quite replicate Mohammad's example output because, for example, I don't check 6 base 4 because I know it won't be a repeating number.

And another reason for not going beyond base $n/2 is that for base $n you need $n symbols to represent a number. I used 0-9, A-Z, a-z and then various symbols, giving 100 symbols and - using my algorithm - the ability to check $n up to 301.

Try it 

Try running the script with any input:



example: 47

Script


#!/usr/bin/perl

# Peter Campbell Smith - 2022-03-22
# PWC 157 task 1

use v5.28;
use strict;
use warnings;
use utf8;

my (@tests, $n, $base, $based, $brazilian, $reason);

# tests as stated in the challenge and then some more
@tests = (7, 6, 8, 9, 10, 97, 98, 99, 100);

# loop over numbers to be tested
for $n (@tests) {
    $reason = '';
    
    # loop over possible bases (see blog for why we can stop at $n / 2)
    for $base (2 .. int($n / 2)) {
        $based = base($n, $base);
        $brazilian = $based =~ m|^(.)\1+$|;  # succeeds if the first character is followed by 1+ repeats of the same
        
        # it is, and we can stop looking
        if ($brazilian) {
            say qq[\nInput:  \$n = $n\nOutput: 1\nSince $n in base $base is $based];
            last;
        }
        $reason .= qq[\n      $n in base $base is $based];
    }
    
    # so we've been through all the bases and it isn't brazilian
    say qq[\nInput:  \$n = $n\nOutput: 0\nSince] . substr($reason, 6) unless $brazilian;
}

sub base {

    my ($base, $digit, $digits, $integer, $result);
    
    # converts $integer to 123AB representation in base $base
    # nicked from week 149 task 2
    
    ($integer, $base) = @_;
    $digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!"£$%^&*()';
    $result = '';
    
    # strip digits 1 at a time
    while ($integer) {
        $digit = $integer % $base;
        $integer = ($integer - $digit) / $base;
        $result = substr($digits, $digit, 1) . $result;
    }
    return $result;
}

Output


Input:  $n = 7
Output: 1
Since 7 in base 2 is 111

Input:  $n = 6
Output: 0
Since 6 in base 2 is 110
      6 in base 3 is 20

Input:  $n = 8
Output: 1
Since 8 in base 3 is 22

Input:  $n = 9
Output: 0
Since 9 in base 2 is 1001
      9 in base 3 is 100
      9 in base 4 is 21

Input:  $n = 10
Output: 1
Since 10 in base 4 is 22

Input:  $n = 97
Output: 0
Since 97 in base 2 is 1100001
      97 in base 3 is 10121
      97 in base 4 is 1201
      97 in base 5 is 342
      97 in base 6 is 241
      97 in base 7 is 166
      97 in base 8 is 141
      97 in base 9 is 117
      97 in base 10 is 97
      97 in base 11 is 89
      97 in base 12 is 81
      97 in base 13 is 76
      97 in base 14 is 6D
      97 in base 15 is 67
      97 in base 16 is 61
      97 in base 17 is 5C
      97 in base 18 is 57
      97 in base 19 is 52
      97 in base 20 is 4H
      97 in base 21 is 4D
      97 in base 22 is 49
      97 in base 23 is 45
      97 in base 24 is 41
      97 in base 25 is 3M
      97 in base 26 is 3J
      97 in base 27 is 3G
      97 in base 28 is 3D
      97 in base 29 is 3A
      97 in base 30 is 37
      97 in base 31 is 34
      97 in base 32 is 31
      97 in base 33 is 2V
      97 in base 34 is 2T
      97 in base 35 is 2R
      97 in base 36 is 2P
      97 in base 37 is 2N
      97 in base 38 is 2L
      97 in base 39 is 2J
      97 in base 40 is 2H
      97 in base 41 is 2F
      97 in base 42 is 2D
      97 in base 43 is 2B
      97 in base 44 is 29
      97 in base 45 is 27
      97 in base 46 is 25
      97 in base 47 is 23
      97 in base 48 is 21

Input:  $n = 98
Output: 1
Since 98 in base 13 is 77

Input:  $n = 99
Output: 1
Since 99 in base 10 is 99

Input:  $n = 100
Output: 1
Since 100 in base 19 is 55