19
\$\begingroup\$

When studying numerology, you can say two words (strings consisting entirely of letters) are compatible if they produce the same number under the following operation (let's use the string hello as an example):

  • Map each letter to a number according to the following, ignoring case:

    1 2 3 4 5 6 7 8 9
    a b c d e f g h i
    j k l m n o p q r
    s t u v w x y z
    

    The number at the top of the column a letter is in is its mapped value (e.g. a -> 1, x -> 6)

    hello -> [8, 5, 3, 3, 6]

  • Take the sum of these numbers. hello -> 25

  • Repeatedly take the digital sum until it reaches a single digit (i.e. it's digital root). hello -> 2+5 = 7

For example, hello and world are not compatible (they yield 7 and 9 respectively), whereas coding and sandbox are (both 7).


You are to write a program which will take two strings as input and output two distinct consistent values which indicate whether the strings are compatible or not

  • The inputs will only consist of letters (ABCDEFGHIJKLMNOPQRSTUVWXYZ or abcdefghijklmnopqrstuvwxyz) in a consistent case
  • You may choose the case of the inputs, so long as it is consistent across inputs and runs
  • You may take input as a delimited string (e.g. space separated), so long as the delimiter is non-empty and consists of entirely non-letter characters of your chosen case (i.e. if you input in uppercase, the delimiter may contain lowercase letters, but not uppercase letters)
  • Otherwise, you may input and output in any convenient method

This is so the shortest code in bytes wins.

Test cases

a, b -> out

"hello", "world" -> 0
"raahyjc", "mvj" -> 0
"mpqtjmjd", "bwkhrh" -> 0
"VZZLCZTH", "DOJEIV" -> 0
"coding", "sandbox" -> 1
"vhw", "wl" -> 1
"HMCZQZZRC", "SIQYOBXK" -> 1
"a", "j" -> 1

These two programs can generate more test cases

\$\endgroup\$
  • \$\begingroup\$ Sandbox. Related \$\endgroup\$ – caird coinheringaahing Nov 20 at 16:01
  • 1
    \$\begingroup\$ @xash Nope, my mistake, I had them mixed up. Fixed \$\endgroup\$ – caird coinheringaahing Nov 20 at 16:31
  • 1
    \$\begingroup\$ Suggested edge case: "a", "j" -> 1 (one should not stop the process as soon as the length is 1, as the first step is mandatory). \$\endgroup\$ – Arnauld Nov 20 at 17:41
  • \$\begingroup\$ @Arnauld Good catch, added \$\endgroup\$ – caird coinheringaahing Nov 20 at 17:42
  • 1
    \$\begingroup\$ @user so long as it's the set that removes the duplicates (i.e. the program still takes "2" arguments), yeah that's fine. E.g. an answer f(s) must still take input as f({'a', 'a'}) rather than f({'a'}) \$\endgroup\$ – caird coinheringaahing Nov 20 at 19:34

19 Answers 19

12
\$\begingroup\$

Jelly, 6 bytes

O’§%9E

Try it online! All Tests.

We take input in capital letters. The key insight here is to note (ref. en.wikipedia.org/wiki/Digital_root that the digital root of \$n>0\$ is \$n\mod 9\$ except if \$n\$ is a multiple of 9, at which case it is 9. However, we only care if the digital roots are equal, so we can treat the digital root as \$n\mod 9\$ in all cases.

O’§%9E
O       # Character values A→65,...
 ’      # minus 1, A→64...
  §     # take the sum of each word
   %9   # modulo 9 (∑{A...} = ∑{1...})
     E  # are the two words' sums equal?
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Husk, 11 8 bytes

-7 bytes after looking at fireflame241's answer
-3 bytes thanks to Dominic van Essen

Ëo%9ṁo←c

Try it online!

Needs the input a list of uppercase words.

Ëo%9ṁo←c
    ṁ     Map each word and sum the results
       c  Get integer value of character
     o←   And decrement
 ȯ%9      Take that modulo 9
Ë         Check if they're equal
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ 9 bytes with uppercase input... \$\endgroup\$ – Dominic van Essen Nov 20 at 18:35
  • \$\begingroup\$ @DominicvanEssen Nice, thanks! \$\endgroup\$ – user Nov 20 at 18:41
  • 1
    \$\begingroup\$ ...and 8 bytes by using Ë, I think (first time for me using Ë...)... \$\endgroup\$ – Dominic van Essen Nov 20 at 18:43
  • \$\begingroup\$ @DominicvanEssen Ë is very smart, I didn't think of taking the input as a list \$\endgroup\$ – user Nov 20 at 18:45
4
\$\begingroup\$

K (oK), 10 9 bytes

=/9!+/'3+

Try it online!

Another port of fireflame241's answer.

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 32 27 bytes

9∣(#-#2&@@FromDigits/@#)&

Try it online!

Takes a list containing two strings.

Inspired by Neil's Charcoal solution: FromDigits still recognizes a=10, b=11, etc., even if those digits are not present in the base (by default, it interprets its input base 10).

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

05AB1E, 12 11 bytes

Takes input as lists of lists of characters.

-1 byte thanks to Kevin Cruijssen!

ÇÌ9%>ΔO€S}Ë

Try it online!

Commented:

ۂ             # convert both words to codepoint lists  a->97, b->98, ...
  Ì            # add 2 to each number                   a->99, b->100, ...
   9%          # modulo 9                               a->0, b->1, ...
     >         # increment                              a->1, b->2, ...
      Δ   }    # execute until the reult doesn't change:
       O       #   sum each list
        €S     #   split the results into lists of digits
           Ë   # are both lists equal?

A port of fireflame's excellent Jelly answer comes in at 6 bytes as well (provided by Kevin):

Ç<O9%Ë

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Why not add 3 to each number, you can skip off increment then, I suppose? I don't know osabie, btw.. \$\endgroup\$ – vrintle Nov 20 at 17:16
  • 1
    \$\begingroup\$ @vrintle Adding 3 will change the result of the modulo 9. The increment changes a 0 to a 1 for the digital sum calculation (it's (x+2) % 9 + 1, which is different from (x + 3) % 9) \$\endgroup\$ – caird coinheringaahing Nov 20 at 17:34
  • \$\begingroup\$ If you take the input as a list of character-lists, you can drop the first for -1. Also, a port of the Jelly answer is 6 bytes as well. \$\endgroup\$ – Kevin Cruijssen 22 hours ago
  • \$\begingroup\$ @KevinCruijssen I already input as a list of singleton lists containing the string, but this seems more reasonable ;). Added the port to the answer. \$\endgroup\$ – ovs 22 hours ago
3
\$\begingroup\$

Retina 0.8.2, 31 30 bytes

+T`_l`dl
.
$*
1{9}|(1*)¶\1

^$

Try it online! Takes input on separate lines, but link includes header which lowercases the test suite and splits on , for convenience. Explanation:

+T`_l`dl

Retina 0.8.2 doesn't have Y, but fortunately we can just repeatedly transliterate 9 digits at a time, shuffling the letters back 9 places in the alphabet.

.
$*

Convert all of the digits to unary.

1{9}|(1*)¶\1

Take the difference modulo 9.

^$

Check that the result is zero.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

J, 15 bytes

Based on fireflame241's Jelly answer.

=&(9|1#.3+3&u:)

Try it online!

Original approach: J, 29 bytes

-2 after reading ovs' answer: (x-97)|9 = (x+2)|9

=&(1(,.&.":@#.^:_)1+9|2+3&u:)

Try it online!

=&(1(,.&.":@#.^:_)1+9|2+3&u:)
f&(            g            ) call g on both arguments, then call f
                        3&u:  convert string to code points
                      2+      'a' -> 99, 'b' -> 100 …
                    9|        mod 9
                  1+          plus 1
   1(  f     )^:_             execute 1 f (list of digits)
                                until the result does not change
           @#.                sum digits and
       &.":                   convert the sum to a string and
     ,.                       itemize the characters
       &.":                   convert the characters back to digits
=&                            are the digital roots equal?
| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Perl 5 -MList::Util=sum -p, 61 bytes

y/a-z/1-91-91-8/;s|\d+|sum$&=~/./g|ge while/\d\d/;$_=/(.) \1/

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Three bytes less with: Try it online! Assuming - to be just as valid as a separator between the words as space. If the delimiter is == then one more byte (the !) can be dropped from the code. I think the question says such delimiters are ok. \$\endgroup\$ – Kjetil S. 2 days ago
3
\$\begingroup\$

Python 2, 61 \$\cdots\$ 53 51 bytes

Saved a byte thanks to ovs!!!
Saved 2 bytes thanks to Dingus!!!

lambda t:len({sum(ord(c)+3for c in w)%9for w in t})

Try it online!

Inputs a tuple of two strings in lowercase and returns \$1\$ if they are compatible or \$2\$ otherwise.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ You can do +3 or -6 instead of -96 for 1 byte less. \$\endgroup\$ – ovs Nov 20 at 18:49
  • \$\begingroup\$ @ovs Because \$-96\equiv +3\pmod 9\$, nice one - thanks! :D \$\endgroup\$ – Noodle9 Nov 20 at 19:24
2
\$\begingroup\$

Python 3, 203 145 bytes

-58 bytes thanks to @caird coinheringaahing

def f(a):
 x,y=[sum((ord(i)-97)%9+1for i in z)for z in a]
 g=lambda t:sum(int(i)for i in str(t))
 while x>9:x=g(x)
 while y>9:y=g(y)
 return x==y

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 145 bytes, taking input in lowercase (you can choose to only have to handle 1 case) \$\endgroup\$ – caird coinheringaahing Nov 20 at 16:39
  • \$\begingroup\$ And, if you're good switching it Python 2, 141 bytes \$\endgroup\$ – caird coinheringaahing Nov 20 at 16:42
  • \$\begingroup\$ 99 bytes, based on caird's suggestions. \$\endgroup\$ – ovs Nov 20 at 16:47
2
\$\begingroup\$

Retina, 31 bytes

Y`l_`1-9
{`\d
*
)`_+
$.&
(.) \1

Try it online!

A direct implementation of the given algorithm. Outputs 0/1 indicating incompatible/compatible taking the argument in lower case.

Explanation

Y`l_`1-9

Transliterate cyclically the sets a-z_ to 1-9. Here, the underscore is not a real character but a dummy, not that it particularly matters. To cyclically transliterate we extend both sequences infinitely, then each time we encounter a character in the input in the first set we output the corresponding character in the same location in the second set. This behaviour requires the dummy character to map to 9 after z is mapped to 8, as otherwise the second occurrence of each character will be off by one, the third occurrence off by two, etc.

{`\d
*
)`_+

Here we loop until a fixed point over these two stages, indicated by { and ). The first stage converts each individual digit to a corresponding number of _ characters, while the second converts each chain of _ characters to a number equal to the length of the chain. This reaches a fixed point naturally only at single digit numbers.

(.) \1

Count if the remaining digits are the same, so the total is zero if they are not the same and one if they are.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Scala, 27 bytes

Uses fireflame241's approach.

_.map(_.map(3+).sum%9).size

Try it online!

Accepts input as a Set of lowercase strings. Returns 2 if inputs are not compatible, 1 if they are. I'll probably go to hell for my abuse of the rules here.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Haskell, 44 bytes

a#b=o a-o b
o s=sum[fromEnum c-1|c<-s]`mod`9

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Ruby 2.7, 89 \$\cdots\$ 55 52 41 bytes

Saved a whooping 34 bytes, thanks to fireflame241's answer!
Saved extra 11 bytes, thanks to Dingus!

->w{!w.map{|s|s.bytes.sum{_1-6}%9}.uniq!}

Try it online!

This outputs with the boolean values swapped!
In Ruby 2.7, we can use _1 in place of |c|c to save 2 bytes.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ "You may choose the case of the inputs, so long as it is consistent across inputs and runs" so you can just take input in lowercase and remove the .downcase \$\endgroup\$ – caird coinheringaahing Nov 20 at 17:37
  • \$\begingroup\$ Oh, thank you @cairdcoinheringaahing \$\endgroup\$ – vrintle Nov 20 at 17:38
  • 1
    \$\begingroup\$ It looks like this fails for 'hmczqzzrc', 'siqyobxk' (and errors for the commented out examples, not sure how much of an issue that is) \$\endgroup\$ – caird coinheringaahing Nov 20 at 17:43
  • \$\begingroup\$ @cairdcoinheringaahing - it was a typo of n>9 in repeated digit sum. \$\endgroup\$ – vrintle Nov 20 at 17:49
  • 1
    \$\begingroup\$ @vrintle Answering both, so long as the outputs are distinct and consistent across runs, they can be anything you like. However, note that “non-empty array vs empty array” is not consistent, as the non-empty array may change across runs \$\endgroup\$ – caird coinheringaahing Nov 21 at 3:11
2
\$\begingroup\$

Charcoal, 13 bytes

¬﹪⁻⍘S³⁷⍘S³⁷¦⁹

Try it online! Link is to verbose version of code. Takes input in lower case. Outputs a Charcoal boolean, i.e. - for compatible, nothing if not. Explanation:

    S           First input string
   ⍘ ³⁷         Interpret as base 37
  ⁻             Subtract
       ⍘S³⁷     Second input string as base 37
 ﹪          ⁹   Reduced modulo 9
¬               Equals zero?
                Implicitly print

Base 37 interprets a=10, b=11 ... z=35 which have the required digital roots, plus also it interprets aa=380 which has a digital root of 2 etc.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Java 8, 50 bytes

a->b->a.map(v->v-1).sum()%9==b.map(v->v-1).sum()%9

Inputs in uppercase as character-Streams.

Port of @fireflame241's Jelly answer, so make sure to upvote him!

Try it online.

Explanation:

a->b->                    // Method with two IntStream parameters & boolean return-type
  a.map(v->               //  Map over the characters of the first input:
           v-1)           //   Decrease each value by 1
   .sum()                 //  Then sum them all together
         %9               //  And take modulo-9 on that
  ==b.map(v->v-1).sum()%9 //  Do the same for the second input,
                          //  and check if they're equal to one another
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6),  80 79 65  63 bytes

Saved 14 bytes by using @fireflame241's insight
Saved 2 more bytes thanks to @Neil

Expects (a)(b). Returns a Boolean value.

a=>b=>(g=s=>[...s].map(c=>t+=parseInt(c,36),t=0)&&t%9)(a)==g(b)

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ s=>[...s].map(c=>t+=parseInt(c,36),t=0)&&t%9 saves 2 bytes. \$\endgroup\$ – Neil Nov 20 at 18:50
1
\$\begingroup\$

Wolfram Language (Mathematica), 66 bytes

SameQ@@(Tr@*IntegerDigits~FixedPoint~Tr@#&/@LetterNumber@#~Mod~9)&

Try it online!

thanks @att

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Composition and prefix application have higher precedence than infix application (although //. would still be shorter), and LetterNumber is Listable. Using the third argument of Mod is shorter than using /., but the replacement currently doesn't do anything since it's performed just before SameQ. \$\endgroup\$ – att Nov 20 at 19:51
1
\$\begingroup\$

C (gcc), 67 bytes

Takes two lowercase strings and returns 0 if they match, non-zero otherwise. Uses the method from @fireflame241's answer.

i;g(char*s){for(i=0;*s;i+=(2+*s++)%9+1);s=i%9;}f(s,t){s=g(s)-g(t);}

Try it online!

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.