24
\$\begingroup\$

Two strings are "Caesar equivalent" if the distance (counting up) between the corresponding characters are the same. Yes, I made this term up. Here's an example:

"Abc" and "Cde" are equivalent because

distance from a-c == 2
distance from b-d == 2
distance from c-e == 2

The capitalization doesn't make any difference.

"Hello" and "World" are not Caesar equivalent because

distance from h-w == 15
distance from e-o == 10
distance from l-r == 6
distance from l-l == 0
distance from o-d == 15

"Abcd" and "Yzab" are Caesar equivalent because

distance from a-y = 24
distance from b-z = 24
distance from c-a = 24 (it wraps around)
distance from d-b = 24

You must write a full program that takes two strings from STDIN, and prints a truthy value if they are Caesar equivalent, and a falsy value if they are not.

Valid Input

  • Since capitalization doesn't matter, it is acceptable if your program requires the input to be all lower-case, all upper-case, or whatever mix you want, as long as this is specified in your answer.

  • The input will not have spaces or punctuation.

  • The inputs will be the same length.

\$\endgroup\$
  • 8
    \$\begingroup\$ Would have been nice to allow input as command line arguments. I was going to write a C solution, but reading from stdin requires fairly lengthy code, particularly if you don't have a maximum length ahead of time. \$\endgroup\$ – Reto Koradi May 21 '15 at 4:47
  • \$\begingroup\$ @RetoKoradi Why not? It probably won't win anyway, since C isn't exactly known for being concise. \$\endgroup\$ – DJMcMayhem May 21 '15 at 13:43
  • \$\begingroup\$ Right, I doubt that C would ever have a chance for an absolute win. At best, I compare to solutions that use "real" ;) programming languages. But even there, other languages tend to be more compact, particularly if it involves string processing. \$\endgroup\$ – Reto Koradi May 21 '15 at 14:57
  • 4
    \$\begingroup\$ Every time I see this in the question list, it has exactly as many upvotes as answers. \$\endgroup\$ – Alex A. May 21 '15 at 23:33
  • 1
    \$\begingroup\$ @AlexA. I wasn't paying any attention to the up vote to answer ratio until you pointed it out. Now it's all I notice. \$\endgroup\$ – DJMcMayhem May 25 '15 at 0:23

23 Answers 23

10
\$\begingroup\$

Pyth, 9 bytes

}wm=.rzGG

The two strings are expected in lowercase, newline separated.

Demonstration.

How it works:

.r is Pyth's rotary translation function. It maps each element in the first argument from its first occurance in the second argument to the next entry in the second argument. In this, case, the second argument is G, the lowercase alphabet, so this is equivalent to a Caesar shift of 1.

Putting an = in front of the function makes it in-place. Thus, =.rzG assigns the Caesar shift of z by one to z. Note that z is initialized to the first line of input in Pyth.

This expression is used inside a map. m=.rzGG applies this transformation to z 26 times, once for each element of G, and saves the results in a list. This gives the list of all possible Caesar shifts of z.

Finally, }w checks whether the next line of input is in that list.

\$\endgroup\$
14
\$\begingroup\$

CJam, 17 12 11 bytes

1 byte saved by Dennis.

ll.m26f%)-!

Test it here.

Expects the first string to be lower case and the second to be upper case. Prints 1 for Caesar-equivalent strings and 0 otherwise.

Explanation

ll           e# Read two lines of input.
  .m         e# Take the differences of corresponding characters.
    26f%     e# Take the differences modulo 26.
        )-   e# Remove all copies of the last difference from the array. This will 
             e# yield an empty array if and only if all differences are the same.
          !  e# Logical NOT, which yields 1 for an empty array and 0 otherwise.

The reason we require the first string in lower case and the second in upper case is to ensure that the difference is always positive. Otherwise taking the modulo might return something negative and would not necessarily be unique, even for Caesar-equivalent strings.

\$\endgroup\$
  • 1
    \$\begingroup\$ If you require the first word to be lowercase and the second one to uppercase, you can use 26f% to save one byte. \$\endgroup\$ – Dennis May 21 '15 at 2:59
  • \$\begingroup\$ You can use the shell convention (stackoverflow.com/questions/2933843/…) to bring it closer to Pyth answer. \$\endgroup\$ – VicAche May 23 '15 at 10:46
  • 1
    \$\begingroup\$ @VicAche The accepted convention is to interpret truthy and falsy in whatever way your language interprets it. Also, if I removed the ! I wouldn't have 0 or 1 but an empty or non-empty array. \$\endgroup\$ – Martin Ender May 23 '15 at 11:23
9
\$\begingroup\$

Python2, 68 67 70 69 Bytes

print len({(ord(y)-ord(x))%26for x,y in zip(*raw_input().split())})<2

Python3, 67 66 Bytes

print(len({(ord(y)-ord(x))%26for x,y in zip(*input().split())})<2)

It's a bit hard to ungolf, so just explaining the pieces:

  • zip(*raw_input().split()) takes the input, splits it into a list of two words, assuming words are separated by whitespace. After that each word is passed as a parameter of the the zip function, by use of * operator. The zip function will create a list of letter-pairs, for letters in the same position.
  • (ord(y)-ord(x))%26for x,y in ... This just transforms the list of 2 letters to an generator expression of the distances between those letters.
  • {...} reduces this expression to a set, essentially throwing out duplicates
  • len(...)<2 checks if there is only one item left in the set (or 0 for empty strings), which essentially means all letters had the same distance.
  • print outputs that value

Thanks to xnor for reminding me set(...) can be replaced with {...} and the space before for is not required. Also thanks to Josay for the <=1 to <2 optimization.

\$\endgroup\$
  • \$\begingroup\$ Pretty similar to my solution posted roughly in the same minute. You have been smarter than me to go the input but you can reduce <=1 into '<2'. \$\endgroup\$ – Josay May 21 '15 at 14:55
  • 1
    \$\begingroup\$ You can do a set comprehension directly as {...} rather than set((...)). Your code needs to actually print the result. \$\endgroup\$ – xnor May 21 '15 at 21:20
  • \$\begingroup\$ @KillianDS The default rules require printing to STDOUT or returning (not REPL evaluation), and here the OP specified printing. Otherwise, the generic shortest way is to use lambda to save on writing print or return. \$\endgroup\$ – xnor May 22 '15 at 9:01
  • 1
    \$\begingroup\$ By the way, you don't the space before for; the Python lexer correctly splits 26for. \$\endgroup\$ – xnor May 22 '15 at 9:07
5
\$\begingroup\$

APL (15)

1=≢∪26|-⌿⎕A⍳↑⍞⍞

It needs the letters to be uppercase, and prints either 1 or 0, like so:

      1=≢∪26|-⌿⎕A⍳↑⍞⍞
ABCD
YZAB
1

      1=≢∪26|-⌿⎕A⍳↑⍞⍞
HELLO
WORLD
0

Explanation:

  • ↑⍞⍞: read two lines from the keyboard, and arrange the characters in an N×2 matrix.
  • ⎕A⍳: for each character, find at which position it occurs in ⎕A (the uppercase alphabet).
  • -⌿: for each column, subtract the second value from the first value
  • 26|: take the mod-26 of each of those numbers.
  • If the strings are Caesar-equivalent, all numbers in this list are now equal, so:
  • ≢∪: find the number of unique values in the list
  • 1=: compare that to 1.
\$\endgroup\$
  • \$\begingroup\$ I'll never not upvote APL :) \$\endgroup\$ – orlp May 21 '15 at 16:04
  • \$\begingroup\$ @AlexA.: I'm using Dyalog APL 14. If you've got a Raspberry Pi, it's free; for students it's also free; otherwise you can download an unregistered version, which is nagware but otherwise functionally identical to the real ones. dyalog.com TryAPL is based on this, by the way. \$\endgroup\$ – marinus May 21 '15 at 20:41
  • \$\begingroup\$ I'd be interested to hear your thoughts on Dyalog vs. GNU APL, ngn/apl, and APLX, though the comments aren't really the place for such a discussion. ;) \$\endgroup\$ – Alex A. May 23 '15 at 16:59
3
\$\begingroup\$

J, 19 bytes

1=[:#@~.26|-&(3&u:)

Letters at the same position should have the same case.

After converting both input strings to their codepoint representation with &(3&u:) we compare 1 to the length # of the nub ~. of the modulo 26 26| of the difference - of the two arrays. The nub will be 1 if all Caesar-distances are the same.

Usage:

   'abcd' (1=[:#@~.26|-&(3&u:)) 'yzab'
1

Try it online here.

\$\endgroup\$
3
\$\begingroup\$

Julia, 91 87 83 bytes

a=readline()
b=readline()
show(length(Set([mod(a[i]-b[i],26)for i=1:length(a)]))<2)

Ungolfed + explanation:

# Read two strings from STDIN
a = readline()
b = readline()

# Get the absolute difference mod 26 of the character values in the strings
x = [mod(a[i] - b[i], 26) for i = 1:length(a)]

# Construct a set consisting of the elements of x. If the set has only a
# single element, the strings are Caesar equivalent. This will print a
# boolean value to STDOUT.
show(length(Set(x)) < 2)

This takes advantage of the fact that strings in Julia can be treated as character arrays and that arithmetic operations can be performed on character values. The input strings can have any mix of capitalization you want, so long as the capitalization at each position matches between the strings.

\$\endgroup\$
3
\$\begingroup\$

C99, 92 bytes with bug   101 92 bytes

  r,i;main(z,a)char**a;{for(;z=a[2][++i];)r|=(a[1][i]-z+*a[2]-*a[1]+52)%26;putchar(49-!!r);}

Pretty straightforward; assumes words come as first and second arguments, respectively. Compiled with -std=c99.

\$\endgroup\$
  • \$\begingroup\$ This gives the wrong result for the second sample input. \$\endgroup\$ – Reto Koradi May 24 '15 at 2:25
  • \$\begingroup\$ You're right, I missed it. Fixed. \$\endgroup\$ – rr- May 24 '15 at 18:02
3
\$\begingroup\$

Javascript (ES7 Draft), 87 bytes

Requires inputs to be the same case.

(p=prompt)(![z=(a[c='charCodeAt'](i)-b[c](i)+26)%26 for(i in b=p(a=p()))].some(x=>x^z))

\$\endgroup\$
2
\$\begingroup\$

CJam, 13 bytes

{r(fm26f%}2*=

It requires the first character in each word to be in upper case, others in lower case.

Try it here. (Firefox here.)

Too bad the APL variants doesn't support character arithmetics...

Explanation

{
    r       e# Read a word.
    (f-     e# Return each character value minus the first character.
    26f%    e# Mod 26.
}2*         e# Repeat 2 times.
=           e# Check if they are equal.
\$\endgroup\$
2
\$\begingroup\$

Perl, 80

Edit: A failed optimization had slipped into the golfed code. Now it matches the ungolfed version. (The byte count was correct, though.)

@a=unpack"W*",<>;for(<>=~/./g){$n=ord()-shift@a;$p=!$c++||$p&&$n==$o;$o=$n}say$p

Run with Perl version 5.10 (perl -M5.10.0 or perl -E …) for say(). Slightly expanded version:

@a=unpack"W*",<>;             # read first string, split and convert to numbers

for(<>=~/./g){                # reads the second string and splits it
   $n=ord()-shift@a;          # convert next character of second string and compare
   $p= !$c++ || $p && $n==$o; # compare differences (special case for first char)
   $o=$n
}

say $p

The code outputs 1 (truthy in Perl) if the strings are Caesar equivalent, and the empty string (falsy in Perl) if they are not. If this is too loose an interpretation, I need to add 2 bytes for say$p+0, which prints 1 or 0.

Character case must match between inputs.

\$\endgroup\$
  • \$\begingroup\$ Based on the comments on the question above, you can take input as command line arguments too. You could use -i to take in the second string, which would store it in the variable $^I. Also, using -E instead of -e when running on the command line will get you say for free, so you can use it without adding any bytes. Try running this: perl -iteststring -E'say$^I' You might be able to shorten this with the -i trick. \$\endgroup\$ – chilemagic May 21 '15 at 14:08
  • \$\begingroup\$ Thanks @chilemagic, the -i trick is neat (and I did not know it!). In this case I do not think it helps because $^I is longer than <>. \$\endgroup\$ – xebtl May 21 '15 at 19:25
  • \$\begingroup\$ @chilemagic Oh, and as per this discussion, I did not count the bytes for -M5.10.0 anyway. (But I mentioned the -E switch in the edit) \$\endgroup\$ – xebtl May 21 '15 at 19:56
2
\$\begingroup\$

Matlab, 49 48 bytes

This was a really quick one. Sadly getting a string from stdin is quite expensive.

x=@()input('','s');sum(diff(mod(x()-x(),26)))==0

Note that it is, like most if not all answers, case sensitive.

EDIT: shaved off one byte by defining an anonymous function!

\$\endgroup\$
2
\$\begingroup\$

Prolog, 56 bytes

b([],[],_).
b([A|C],[B|D],N):-N is mod(A-B,26),b(C,D,N).

Not all combinations of cases are supported.

usage

b(`abcd`,`yzab`,_).

Try it online here

\$\endgroup\$
2
\$\begingroup\$

C, 97 bytes

#define D (*a[2]++-*a[1]+++26)%26
d,r;main(int c,char**a){for(d=D;*a[1];r|=d-D);puts(r?"N":"Y");}
\$\endgroup\$
  • 1
    \$\begingroup\$ Yay! You have restored the balance! \$\endgroup\$ – DJMcMayhem May 24 '15 at 2:52
  • \$\begingroup\$ You can save 4 characters if you reuse d and declare a's type outside parameters like this: d,r;main(int c,char**a){r;main(d,a)char**a;{ \$\endgroup\$ – rr- May 26 '15 at 10:33
1
\$\begingroup\$

Scala, 57 bytes

(readLine zip readLine map(x=>x._1-x._2%26)toSet).size==1

Little longer than the others, and essentially equivalent, but it is in a vary different style of language!

I also have this version(56 bytes):

(readLine zip readLine map(_._1-x$1._2%26)toSet).size==1

But I don't know if the x$1 working is coincidence or by design...

\$\endgroup\$
  • 1
    \$\begingroup\$ That's really weird, how does x$1 work without x ever being defined? \$\endgroup\$ – Dan Getz May 22 '15 at 1:16
  • \$\begingroup\$ @DanGetz I'm fairly sure it's a compiler fluke. I may ask a question on stack overflow about it :D \$\endgroup\$ – Others May 22 '15 at 1:17
1
\$\begingroup\$

Python 2, 80 bytes

Takes 2 similarly-cased strings from stdin separated by a space :

s,t=raw_input().split();print len(set((ord(c)-ord(d))%26 for c,d in zip(s,t)))<2

Tested on following test cases :

tests = [
    ("abc", "abc", True),
    ("abcd", "abc", False),
    ("abc", "cde", True),
    ("Abc", "Cde", True),
    ("abc", "deg", False),
    ("Hello", "World", False),
    ("Abcd", "Yzab", True),
    ("", "", True)
]

for s, t, v in tests:
    if len(s) == len(t): # I didn't read that at first
        assert v == (len(set((ord(c) - ord(d)) % 26 for c, d in zip(s, t))) < 2)
\$\endgroup\$
1
\$\begingroup\$

Python 2 - 241 237 188 147 Bytes

Takes input as lowercase string enclosed in quotes, space separated. There has to be a better way..

s=[[ord(x)for x in y]for y in input().split()];v=[];v=[v+[(s[1][i]-s[0][i])%26]for i in xrange(0,len(s[0]))];v=sum(v,[]);print sum(v)//v[0]==len(v)

Ungolfed (260-odd bytes)

strs = [[ord(x) for x in y] for y in raw_input().split()]
vals = []
for i in xrange(0, len(strs[0])):
if strs[0][i]<strs[1][i]:
    vals += [strs[1][i]-strs[0][i]]
else:
    vals += [26-(strs[0][i]-strs[1][i])]
return sum(vals)//vals[0] == len(vals)
\$\endgroup\$
  • \$\begingroup\$ I'm sure that you could make all the variables 1 character long and save a bunch of bytes. You also have to add 4 to your score, as you expect 4 "s extra in your input. \$\endgroup\$ – user34736 May 21 '15 at 15:48
  • \$\begingroup\$ @Reticality I can't believe I didn't shorten the variables.. amateur move. I added 2 to the byte count, as I didn't explain properly; input works like "abc cde". \$\endgroup\$ – Kade May 21 '15 at 16:51
1
\$\begingroup\$

R, 83 84

Fairly much the same as the other solutions. Convert the strings into a vector of integers. Mod the difference of the vectors by 26. Do a unique over the list as check the length is 1. It expects the case to be the same in corresponding characters in each string.

length(unique(((S=strtoi)((R=charToRaw)((I=readline)()),16L)-S(R(I()),16L))%%26))<2

It waits for the two strings to be entered

> length(unique(((S=strtoi)((R=charToRaw)((I=readline)()),16L)-S(R(I()),16L))%%26))<2
abcdefghijklmnopqrstuvwxyz
opqrstuvwxyzabcdefghijklmn
[1] TRUE
> length(unique(((S=strtoi)((R=charToRaw)((I=readline)()),16L)-S(R(I()),16L))%%26))<2
Hello
World
[1] FALSE
> length(unique(((S=strtoi)((R=charToRaw)((I=readline)()),16L)-S(R(I()),16L))%%26))<2
Bob
Nan
[1] TRUE
>
\$\endgroup\$
  • \$\begingroup\$ You could save a byte by using <2 rather than ==1. \$\endgroup\$ – Alex A. May 21 '15 at 14:24
  • \$\begingroup\$ You could save 3 bytes by just outputting 1 or 0 \$\endgroup\$ – user34736 May 21 '15 at 15:50
  • \$\begingroup\$ @AlexA. Thanks Alex I missed that one ... and now I miss that one:) \$\endgroup\$ – MickyT May 21 '15 at 18:57
  • \$\begingroup\$ @Reticality: How? \$\endgroup\$ – Alex A. May 21 '15 at 18:57
  • \$\begingroup\$ @Reticality Unfortunately it would return 1 or greater than one. \$\endgroup\$ – MickyT May 21 '15 at 18:58
1
\$\begingroup\$

Matlab/Octave, 53 52

x=@()input('','s');isscalar(unique(mod(x()-x(),26)))

Input should all be of the same case.

Sadly, Matlab is not very good with user input. As an anonymous handle, this could be only 35 bytes:

@(a,b)isscalar(unique(mod(a-b,26)))

Matlab treats the characters of a string as a vector of numbers. Doing subtraction gets us their difference, and unique converts that vector into a vector containing only unique values. If there is only one number, the words are caeser equivalent and isscalar returns 1, otherwise it will return 0.

\$\endgroup\$
  • \$\begingroup\$ Oh! Another Matlab entry! Looked at answers only after answering myself. \$\endgroup\$ – Oebele May 22 '15 at 12:03
  • \$\begingroup\$ just found out you can save one byte by defining x=@()input('','s'); \$\endgroup\$ – Oebele May 22 '15 at 12:11
  • \$\begingroup\$ @Oebele Thanks! I think I'm going to start trying more golf problems in Matlab, I've found it actually rather fun. \$\endgroup\$ – FryAmTheEggman May 22 '15 at 16:49
  • \$\begingroup\$ Yup, it is. For a many problems it can be very concise with its matrix-based stuff. Octave has a bit more free syntax, which can sometimes save a few more bytes as well, such as inline variable definition. \$\endgroup\$ – Oebele May 27 '15 at 10:11
1
\$\begingroup\$

bash, 71 48

Using the “standard” Unix program caesar(6).

New version (with lots of help from @DigitalTrauma):

read a b;seq -f"caesar %g <<<$a" 26|bash|grep $b
  • Inputs have to be on the same line, separated by spaces
  • Character case must match between inputs.
  • Prints 1 for true or nothing for false.

If input via command line arguments is allowed, it can be shortened to 39 bytes:

 seq -f"caesar %g <<<$1" 26|bash|grep $2

Old version for the record:

 read a b;for i in `seq 26`;do [ `echo $a|caesar $i` = $b ]&&echo 1;done
\$\endgroup\$
  • \$\begingroup\$ 48 bytes, by my count: read a b;seq -f"caesar %g <<<$a" 26|bash|grep $b The result is in the $? builtin variable, where 0 == FALSE and 1 == TRUE, as per standard shell semantics. \$\endgroup\$ – Digital Trauma May 22 '15 at 4:34
  • \$\begingroup\$ @DigitalTrauma Those are some nifty ideas! I especially like the seq -f | bash bit. Result in $? is not valid by my reading of the challenge, but just like my code, yours outputs nothing for false and something for true (except in the borderline case of two empty input strings). Anyway, it would feel like cheating to use all of this in my answer, maybe you should submit your own. \$\endgroup\$ – xebtl May 22 '15 at 8:19
  • \$\begingroup\$ Don't worry - I'm offering the golfing tips for you to use. If I wanted to use them, I already would have done so :). As for the the truthy/falsey thing, I tend to interpret it to be what true and false are in your given language - try [ 0 == 0 ] ; echo $? and [ 0 == 1 ] ; echo $? \$\endgroup\$ – Digital Trauma May 23 '15 at 5:35
1
\$\begingroup\$

><> (Fish), 50 bytes

i:3b*(?v88+0.;n1<
0)?vc1.>~ri-&l?!^i-&:&-2d*%
;n0<

Expects letters at the same position to have the same case.

Explanation

  • i:3b*(?v reads the first word into the stack with 88+0. providing the looping jump
  • ~ri-& removes ~ the separating space from the stack, reverses the stack r (first letter will be on top), reads in the first letter of the second word i, calculates the offset from the first word's first letter - and stores it in the register &.
  • l?!^i-&:&-2d*%0)?v reads every next letter of the second word substracting it from the first word's corresponding letter which is at the top of the stack substracts the offset &:&- stored in the register and checks if the result is 0 mod 26 2d*%. If not prints 0 and terminates 0n;. c1. provides the looping jump.
  • If reached the end of the second word the program prints 1 and terminates 1n;.
\$\endgroup\$
0
\$\begingroup\$

KDB(Q), 35 bytes

{0=sum(1_-':)mod[;26](-)."i"$(x;y)}

Explanation

                         "i"$(x;y)      / convert to ascii decimal
                     (-).               / get differences
             mod[;26]                   / mod 26
      (1_-':)                           / difference between the differences
 0=sum                                  / sum should be 0 if equivalent
{                                 }     / lambda

Test

q){0=sum(1_-':)mod[;26](-)."i"$(x;y)}["abcd";"yzab"]
1b
\$\endgroup\$
0
\$\begingroup\$

Java 281

import java.util.*;enum C{E;Scanner s=new Scanner(System.in);public static void main(String[]z){char[]u=E.n(),v=E.n();int i=0,d=(u[0]-v[0]+26)%26;boolean e=true;for(;++i<u.length;)e&=d==(u[i]-v[i]+26)%26;System.out.print(e);}char[]n(){return s.next().toUpperCase().toCharArray();}}

expanded:

import java.util.*;
enum Caesar{
    Equivalence;
    Scanner input=new Scanner(System.in);
    public static void main(String[]z){
        char[]firstString=Equivalence.nextInput(),secondString=Equivalence.nextInput();
        int index=0,difference=(firstString[0]-secondString[0]+26)%26;
        boolean isEqual=true;
        for(;++index<firstString.length;)
            isEqual&=difference==(firstString[index]-secondString[index]+26)%26;
        System.out.print(isEqual);
    }
    char[]nextInput(){
        return input.next().toUpperCase().toCharArray();
    }
}

I could save 14 bytes if I got rid of converting everything to uppercase, but I feel like it's more complete to leave it in.

\$\endgroup\$
0
\$\begingroup\$

Jelly, 5 bytes

Oạ/ċ2

Try it online!

Outputs a positive integer for equivalent, 0 otherwise

How it works

Oạ/ċ2 - Main link. Argument A (a list of strings)  e.g. ["abc", "cde"]

O     - Ordinal. Cast to code point                     [[97, 98, 99], [99, 100, 101]]
  /   - Reduce the list by...
 ạ    -   absolute difference                           [2, 2, 2]
   ċ2 - Count the number of 2s in the list              3
\$\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.