21
\$\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\$
6
  • \$\begingroup\$ Sandbox. Related \$\endgroup\$ Nov 20, 2020 at 16:01
  • 1
    \$\begingroup\$ @xash Nope, my mistake, I had them mixed up. Fixed \$\endgroup\$ Nov 20, 2020 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, 2020 at 17:41
  • \$\begingroup\$ @Arnauld Good catch, added \$\endgroup\$ Nov 20, 2020 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\$ Nov 20, 2020 at 19:34

23 Answers 23

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?
\$\endgroup\$
5
\$\begingroup\$

K (oK), 10 9 bytes

=/9!+/'3+

Try it online!

Another port of fireflame241's 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
\$\endgroup\$
4
  • 1
    \$\begingroup\$ 9 bytes with uppercase input... \$\endgroup\$ Nov 20, 2020 at 18:35
  • \$\begingroup\$ @DominicvanEssen Nice, thanks! \$\endgroup\$
    – user
    Nov 20, 2020 at 18:41
  • 1
    \$\begingroup\$ ...and 8 bytes by using Ë, I think (first time for me using Ë...)... \$\endgroup\$ Nov 20, 2020 at 18:43
  • \$\begingroup\$ @DominicvanEssen Ë is very smart, I didn't think of taking the input as a list \$\endgroup\$
    – user
    Nov 20, 2020 at 18:45
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).

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice, I was able to port your "base 10" approach back to Charcoal to save me three bytes! \$\endgroup\$
    – Neil
    Nov 23, 2021 at 18:57
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!

\$\endgroup\$
4
  • \$\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, 2020 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\$ Nov 20, 2020 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\$ Nov 23, 2020 at 8:28
  • \$\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
    Nov 23, 2020 at 8:47
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.

\$\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?
\$\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!

\$\endgroup\$
1
  • \$\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
    Nov 22, 2020 at 5:04
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.

\$\endgroup\$
2
  • \$\begingroup\$ You can do +3 or -6 instead of -96 for 1 byte less. \$\endgroup\$
    – ovs
    Nov 20, 2020 at 18:49
  • \$\begingroup\$ @ovs Because \$-96\equiv +3\pmod 9\$, nice one - thanks! :D \$\endgroup\$
    – Noodle9
    Nov 20, 2020 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!

\$\endgroup\$
3
  • \$\begingroup\$ 145 bytes, taking input in lowercase (you can choose to only have to handle 1 case) \$\endgroup\$ Nov 20, 2020 at 16:39
  • \$\begingroup\$ And, if you're good switching it Python 2, 141 bytes \$\endgroup\$ Nov 20, 2020 at 16:42
  • \$\begingroup\$ 99 bytes, based on caird's suggestions. \$\endgroup\$
    – ovs
    Nov 20, 2020 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.

\$\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.

\$\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!

\$\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.

\$\endgroup\$
7
  • 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\$ Nov 20, 2020 at 17:37
  • \$\begingroup\$ Oh, thank you @cairdcoinheringaahing \$\endgroup\$
    – vrintle
    Nov 20, 2020 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\$ Nov 20, 2020 at 17:43
  • \$\begingroup\$ @cairdcoinheringaahing - it was a typo of n>9 in repeated digit sum. \$\endgroup\$
    – vrintle
    Nov 20, 2020 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\$ Nov 21, 2020 at 3:11
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
\$\endgroup\$
2
\$\begingroup\$

Vyxal a, 7 bytes

C‹v∑9%≈

Another port of fireflame241's Jelly solution. Takes input as newline-separated strings. Try it Online!

C‹v∑9%≈
C          Convert the input from a list of strings to a list of lists of their codepoints
 ‹         Decrement every number
  v∑       Sum each sublist
    9%     Mod 9 both sums
      ≈    Check if both sums are equal
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 13 10 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. Edit: Saved 3 bytes via inspiration from @att's Mathematica solution, which only seems fair. Explanation:

    S       First input string
   ⍘ χ      Interpret as "base 10"
  ⁻         Subtract
      ⍘Sχ   Second input string as "base 10"
 ﹪       ⁹  Reduced modulo 9
¬           Equals zero?
            Implicitly print

Like Mathematica, Charcoal interprets interprets a=10, b=11 ... z=35 even in bases which don't actually go up that high. Obviously it also interprets aa=110 which has a digital root of 2 etc.

\$\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!

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

Wolfram Language (Mathematica), 66 bytes

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

Try it online!

thanks @att

\$\endgroup\$
1
  • \$\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, 2020 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!

\$\endgroup\$
1
  • \$\begingroup\$ Suggest i+=1-~-~*s++%9 instead of i+=(2+*s++)%9+1) \$\endgroup\$
    – ceilingcat
    Jan 11, 2021 at 2:15
1
\$\begingroup\$

CJam, 14 bytes

S%{:i:(:+9%}/=

Try it online!

First attempt at CJam. Using Fireflame241's solution.

S%  # Split on spaces
{
 :i # Convert each to int
 :( # Decrement each
 :+ # Sum list
 9% # Modulo 9
}/  # For each word (push to stack)
=   # Are equal
\$\endgroup\$
1
\$\begingroup\$

Burlesque, 18 bytes

WDm{{**-.}ms9.%}sm

Try it online!

WD     # Split into words
m{     # Map over words
  {**  # To int
   -.  # Decrement
  }ms  # Map sum
  9.%  # Modulo 9
}
sm     # Are the same

Using Fireflame241's solution.

Burlesque, 36 bytes

WDm{{**2.-9.%+.}ms{XX++}{ln1!=}w!}sm

Try it online!

Full solution. Saving a byte using 2.- rather than 65.- having looked at some other answers. Otherwise much the same as other answers.

wd          # Split into words
m{          # For each word
  {
   **       # ord(a)
   2.+9.%+. # ((x+2)%9)+1
  }ms       # Map each letter then sum result
  {
   XX       # XXplode into digits
   ++       # Sum digits
  }
  {ln       # Number of digits
   1!=      # Not equal 1
  }w!       # While
 }
 sm        # Are all the same
\$\endgroup\$
1
\$\begingroup\$

TI-Basic, 92 bytes

Prompt Str1,Str2
"BCDEFGHIJKLMNOPQRSTUVWXYZ→Str3
"fPart(1/9sum(1+seq(9fPart(inString(Str3,sub(Ans,I,1))/9),I,1,length(Ans→u
Str1
u→S
Str2
u=S

Output is stored in Ans and displayed. Outputs 0 for incompatible numbers and 1 for compatible ones.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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