78
\$\begingroup\$

Introduction

The Enigma was one of the first electro-mechanical rotor cipher machines used in World War II. That means that after a single letter is coded, it would change the key for the next letter. This was considered unbreakable by the Germans, due to the enormous key space. Even brute-forcing was almost impossible. However, there was a design error in the Enigma. Encrypting a letter would never result into itself. That means that the letter A can encrypt to every letter except the letter A.

Let's take an example of a coded message:

BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ

A typical German word was WETTERBERICHT, or weather report in English. With the principe above, we can determine at which locations the word could possibly be:

BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ
WETTERBERICHT
         ^

This is not possible, because the I can't be encrypted to itself, so we move on 1 place:

BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ
 WETTERBERICHT
             ^

This is also not possible, so we move another place again:

BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ
  WETTERBERICHT
   ^

This again is not possible. In fact, the first possible occurence of WETTERBERICHT is:

BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ
             WETTERBERICHT
0123456789012345678901234567890123456789012345678901234567890123
             ^
             13

So, we return the 0-indexed position of the first possible occurence, which is 13.

The Task

  • Given a coded message and a word, find the index of the first possible occurence.
  • Assume that only basic uppercase alphabetic characters will be used (ABCDEFGHIJKLMNOPQRSTUVWXYZ).
  • If no occurence is found, you can output any negative integer, character, or nothing (e.g. -1, X).
  • Input may be accepted as argument, on seperate newlines, lists or anything else.
  • This is , so the submission with the least amount of bytes wins!

Test cases

Input: BHGEFXWFTIUPITHHLPETTTCLOEWOELM, WETTERBERICHT
Output: 13

Input: ABCDEFGHIJKL, HELLO
Output: 0

Input: EEEEEEEEEEEE, HELLO
Output: -1

Input: XEEFSLBSELDJMADNADKDPSSPRNEBWIENPF, DEUTSCHLAND
Output: 11

Input: HKKH, JJJJJ
Output: -1
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Umm, why does the encoded string change in the middle of the example? \$\endgroup\$
    – Doorknob
    Dec 30, 2015 at 15:56
  • 40
    \$\begingroup\$ @Doorknob冰 ¯\_(ツ)_/¯ \$\endgroup\$
    – Adnan
    Dec 30, 2015 at 15:59
  • \$\begingroup\$ There are issues with the introduction: 1. it wasn't considered unbreakable because of the key space, but because of the system that a letter changes what it is translated to 2. "Encrypting a letter would never result into itself." - yes it would, after the number of available characters it would have to repeat one. \$\endgroup\$ Jan 1, 2016 at 13:38
  • 5
    \$\begingroup\$ @Zelphir with encrypting to itself, I meant that the E would never result into an E. That is what this whole challenge is about. \$\endgroup\$
    – Adnan
    Jan 1, 2016 at 16:22
  • 3
    \$\begingroup\$ Can we use 1-indexing if that's our language's default? \$\endgroup\$ Nov 23, 2020 at 14:23

31 Answers 31

57
\$\begingroup\$

JavaScript, 40

(c,p)=>c.search(p.replace(/./g,"[^$&]"))

Using replace, this maps the plaintext input into a regular expression of form /[^H][^E][^L][^L][^O]/ (e.g., for plaintext input HELLO) and then uses search to test for the first index of the ciphertext substring that matches that regex. This regex means "a pattern where the first character is not H, the second character is not E, etc."

$& is a special sequence for replace output that substitutes in the value matched by the first replace argument (in this case, each single character matched by /./).

\$\endgroup\$
4
  • 17
    \$\begingroup\$ Oh, wow, that's a really clever solution! \$\endgroup\$
    – Doorknob
    Dec 30, 2015 at 16:07
  • 3
    \$\begingroup\$ I didn't know about $&! Thanks for teaching my something today. \$\endgroup\$ Dec 30, 2015 at 16:19
  • 1
    \$\begingroup\$ @ETHproductions Me neither, until today! I also learned about $` and $' in the process of researching this answer, which provide "the portion of the string that precedes/follows the matched substring" \$\endgroup\$
    – apsillers
    Dec 30, 2015 at 16:22
  • 1
    \$\begingroup\$ Wow, that's awesome! I should read the docs more often ;) \$\endgroup\$ Dec 30, 2015 at 16:24
45
\$\begingroup\$

Turing Machine Simulator - 15660 bytes (Non-Competing)

Can't have an Enigma challenge without turing machine code.

0 * * l 0
0 _ _ l ,
, _ , l 1
1 _ 0 r 2
2 * * r 2
2 , * r 3
3 * * r 3
3 , * r 4
4 * * r 4
4 _ * r 13
4 A a l a'                                                                                                                                                                                                        
4 B b l b'                                                                                                                                                                                                        
4 C c l c'                                                                                                                                                                                                        
4 D d l d'                                                                                                                                                                                                        
4 E e l e'                                                                                                                                                                                                        
4 F f l f'                                                                                                                                                                                                        
4 G g l g'                                                                                                                                                                                                        
4 H h l h'                                                                                                                                                                                                        
4 I i l i'                                                                                                                                                                                                        
4 J j l j'                                                                                                                                                                                                        
4 K k l k'                                                                                                                                                                                                        
4 L l l l'                                                                                                                                                                                                        
4 M m l m'                                                                                                                                                                                                        
4 N n l n'                                                                                                                                                                                                        
4 O o l o'                                                                                                                                                                                                        
4 P p l p'                                                                                                                                                                                                        
4 Q q l q'                                                                                                                                                                                                        
4 R r l r'                                                                                                                                                                                                        
4 S s l s'                                                                                                                                                                                                        
4 T t l t'                                                                                                                                                                                                        
4 U u l u'                                                                                                                                                                                                        
4 V v l v'                                                                                                                                                                                                        
4 W w l w'                                                                                                                                                                                                        
4 X x l x'                                                                                                                                                                                                        
4 Y y l y'                                                                                                                                                                                                        
4 Z z l z'
a' * * l a'
a' , * l a
b' * * l b'
b' , * l b
c' * * l c'
c' , * l c
d' * * l d'
d' , * l d
e' * * l e'
e' , * l e
f' * * l f'
f' , * l f
g' * * l g'
g' , * l g
h' * * l h'
h' , * l h
i' * * l i'
i' , * l i
j' * * l j'
j' , * l j
k' * * l k'
k' , * l k
l' * * l l'
l' , * l l
m' * * l m'
m' , * l m
n' * * l n'
n' , * l n
o' * * l o'
o' , * l o
p' * * l p'
p' , * l p
q' * * l q'
q' , * l q
r' * * l r'
r' , * l r
s' * * l s'
s' , * l s
t' * * l t'
t' , * l t
u' * * l u'
u' , * l u
v' * * l v'
v' , * l v
w' * * l w'
w' , * l w
x' * * l x'
x' , * l x
y' * * l y'
y' , * l y
z' * * l z'
z' , * l z

a * * l a
a _ * r A
a a * r A
a b * r A
a c * r A
a d * r A
a e * r A
a f * r A
a g * r A
a h * r A
a i * r A
a j * r A
a k * r A
a l * r A
a m * r A
a n * r A
a o * r A
a p * r A
a q * r A
a r * r A
a s * r A
a t * r A
a u * r A
a v * r A
a w * r A
a x * r A
a y * r A
a z * r A
b * * l b
b _ * r B
b a * r B
b b * r B
b c * r B
b d * r B
b e * r B
b f * r B
b g * r B
b h * r B
b i * r B
b j * r B
b k * r B
b l * r B
b m * r B
b n * r B
b o * r B
b p * r B
b q * r B
b r * r B
b s * r B
b t * r B
b u * r B
b v * r B
b w * r B
b x * r B
b y * r B
b z * r B
c * * l c
c _ * r C
c a * r C
c b * r C
c c * r C
c d * r C
c e * r C
c f * r C
c g * r C
c h * r C
c i * r C
c j * r C
c k * r C
c l * r C
c m * r C
c n * r C
c o * r C
c p * r C
c q * r C
c r * r C
c s * r C
c t * r C
c u * r C
c v * r C
c w * r C
c x * r C
c y * r C
c z * r C
d * * l d
d _ * r D
d a * r D
d b * r D
d c * r D
d d * r D
d e * r D
d f * r D
d g * r D
d h * r D
d i * r D
d j * r D
d k * r D
d l * r D
d m * r D
d n * r D
d o * r D
d p * r D
d q * r D
d r * r D
d s * r D
d t * r D
d u * r D
d v * r D
d w * r D
d x * r D
d y * r D
d z * r D
e * * l e
e _ * r E
e a * r E
e b * r E
e c * r E
e d * r E
e e * r E
e f * r E
e g * r E
e h * r E
e i * r E
e j * r E
e k * r E
e l * r E
e m * r E
e n * r E
e o * r E
e p * r E
e q * r E
e r * r E
e s * r E
e t * r E
e u * r E
e v * r E
e w * r E
e x * r E
e y * r E
e z * r E
f * * l f
f _ * r F
f a * r F
f b * r F
f c * r F
f d * r F
f e * r F
f f * r F
f g * r F
f h * r F
f i * r F
f j * r F
f k * r F
f l * r F
f m * r F
f n * r F
f o * r F
f p * r F
f q * r F
f r * r F
f s * r F
f t * r F
f u * r F
f v * r F
f w * r F
f x * r F
f y * r F
f z * r F
g * * l g
g _ * r G
g a * r G
g b * r G
g c * r G
g d * r G
g e * r G
g f * r G
g g * r G
g h * r G
g i * r G
g j * r G
g k * r G
g l * r G
g m * r G
g n * r G
g o * r G
g p * r G
g q * r G
g r * r G
g s * r G
g t * r G
g u * r G
g v * r G
g w * r G
g x * r G
g y * r G
g z * r G
h * * l h
h _ * r H
h a * r H
h b * r H
h c * r H
h d * r H
h e * r H
h f * r H
h g * r H
h h * r H
h i * r H
h j * r H
h k * r H
h l * r H
h m * r H
h n * r H
h o * r H
h p * r H
h q * r H
h r * r H
h s * r H
h t * r H
h u * r H
h v * r H
h w * r H
h x * r H
h y * r H
h z * r H
i * * l i
i _ * r I
i a * r I
i b * r I
i c * r I
i d * r I
i e * r I
i f * r I
i g * r I
i h * r I
i i * r I
i j * r I
i k * r I
i l * r I
i m * r I
i n * r I
i o * r I
i p * r I
i q * r I
i r * r I
i s * r I
i t * r I
i u * r I
i v * r I
i w * r I
i x * r I
i y * r I
i z * r I
j * * l j
j _ * r J
j a * r J
j b * r J
j c * r J
j d * r J
j e * r J
j f * r J
j g * r J
j h * r J
j i * r J
j j * r J
j k * r J
j l * r J
j m * r J
j n * r J
j o * r J
j p * r J
j q * r J
j r * r J
j s * r J
j t * r J
j u * r J
j v * r J
j w * r J
j x * r J
j y * r J
j z * r J
k * * l k
k _ * r K
k a * r K
k b * r K
k c * r K
k d * r K
k e * r K
k f * r K
k g * r K
k h * r K
k i * r K
k j * r K
k k * r K
k l * r K
k m * r K
k n * r K
k o * r K
k p * r K
k q * r K
k r * r K
k s * r K
k t * r K
k u * r K
k v * r K
k w * r K
k x * r K
k y * r K
k z * r K
l * * l l
l _ * r L
l a * r L
l b * r L
l c * r L
l d * r L
l e * r L
l f * r L
l g * r L
l h * r L
l i * r L
l j * r L
l k * r L
l l * r L
l m * r L
l n * r L
l o * r L
l p * r L
l q * r L
l r * r L
l s * r L
l t * r L
l u * r L
l v * r L
l w * r L
l x * r L
l y * r L
l z * r L
m * * l m
m _ * r M
m a * r M
m b * r M
m c * r M
m d * r M
m e * r M
m f * r M
m g * r M
m h * r M
m i * r M
m j * r M
m k * r M
m l * r M
m m * r M
m n * r M
m o * r M
m p * r M
m q * r M
m r * r M
m s * r M
m t * r M
m u * r M
m v * r M
m w * r M
m x * r M
m y * r M
m z * r M
n * * l n
n _ * r N
n a * r N
n b * r N
n c * r N
n d * r N
n e * r N
n f * r N
n g * r N
n h * r N
n i * r N
n j * r N
n k * r N
n l * r N
n m * r N
n n * r N
n o * r N
n p * r N
n q * r N
n r * r N
n s * r N
n t * r N
n u * r N
n v * r N
n w * r N
n x * r N
n y * r N
n z * r N
o * * l o
o _ * r O
o a * r O
o b * r O
o c * r O
o d * r O
o e * r O
o f * r O
o g * r O
o h * r O
o i * r O
o j * r O
o k * r O
o l * r O
o m * r O
o n * r O
o o * r O
o p * r O
o q * r O
o r * r O
o s * r O
o t * r O
o u * r O
o v * r O
o w * r O
o x * r O
o y * r O
o z * r O
p * * l p
p _ * r P
p a * r P
p b * r P
p c * r P
p d * r P
p e * r P
p f * r P
p g * r P
p h * r P
p i * r P
p j * r P
p k * r P
p l * r P
p m * r P
p n * r P
p o * r P
p p * r P
p q * r P
p r * r P
p s * r P
p t * r P
p u * r P
p v * r P
p w * r P
p x * r P
p y * r P
p z * r P
q * * l q
q _ * r Q
q a * r Q
q b * r Q
q c * r Q
q d * r Q
q e * r Q
q f * r Q
q g * r Q
q h * r Q
q i * r Q
q j * r Q
q k * r Q
q l * r Q
q m * r Q
q n * r Q
q o * r Q
q p * r Q
q q * r Q
q r * r Q
q s * r Q
q t * r Q
q u * r Q
q v * r Q
q w * r Q
q x * r Q
q y * r Q
q z * r Q
r * * l r
r _ * r R
r a * r R
r b * r R
r c * r R
r d * r R
r e * r R
r f * r R
r g * r R
r h * r R
r i * r R
r j * r R
r k * r R
r l * r R
r m * r R
r n * r R
r o * r R
r p * r R
r q * r R
r r * r R
r s * r R
r t * r R
r u * r R
r v * r R
r w * r R
r x * r R
r y * r R
r z * r R
s * * l s
s _ * r S
s a * r S
s b * r S
s c * r S
s d * r S
s e * r S
s f * r S
s g * r S
s h * r S
s i * r S
s j * r S
s k * r S
s l * r S
s m * r S
s n * r S
s o * r S
s p * r S
s q * r S
s r * r S
s s * r S
s t * r S
s u * r S
s v * r S
s w * r S
s x * r S
s y * r S
s z * r S
t * * l t
t _ * r T
t a * r T
t b * r T
t c * r T
t d * r T
t e * r T
t f * r T
t g * r T
t h * r T
t i * r T
t j * r T
t k * r T
t l * r T
t m * r T
t n * r T
t o * r T
t p * r T
t q * r T
t r * r T
t s * r T
t t * r T
t u * r T
t v * r T
t w * r T
t x * r T
t y * r T
t z * r T
u * * l u
u _ * r U
u a * r U
u b * r U
u c * r U
u d * r U
u e * r U
u f * r U
u g * r U
u h * r U
u i * r U
u j * r U
u k * r U
u l * r U
u m * r U
u n * r U
u o * r U
u p * r U
u q * r U
u r * r U
u s * r U
u t * r U
u u * r U
u v * r U
u w * r U
u x * r U
u y * r U
u z * r U
v * * l v
v _ * r V
v a * r V
v b * r V
v c * r V
v d * r V
v e * r V
v f * r V
v g * r V
v h * r V
v i * r V
v j * r V
v k * r V
v l * r V
v m * r V
v n * r V
v o * r V
v p * r V
v q * r V
v r * r V
v s * r V
v t * r V
v u * r V
v v * r V
v w * r V
v x * r V
v y * r V
v z * r V
w * * l w
w _ * r W
w a * r W
w b * r W
w c * r W
w d * r W
w e * r W
w f * r W
w g * r W
w h * r W
w i * r W
w j * r W
w k * r W
w l * r W
w m * r W
w n * r W
w o * r W
w p * r W
w q * r W
w r * r W
w s * r W
w t * r W
w u * r W
w v * r W
w w * r W
w x * r W
w y * r W
w z * r W
x * * l x
x _ * r X
x a * r X
x b * r X
x c * r X
x d * r X
x e * r X
x f * r X
x g * r X
x h * r X
x i * r X
x j * r X
x k * r X
x l * r X
x m * r X
x n * r X
x o * r X
x p * r X
x q * r X
x r * r X
x s * r X
x t * r X
x u * r X
x v * r X
x w * r X
x x * r X
x y * r X
x z * r X
y * * l y
y _ * r Y
y a * r Y
y b * r Y
y c * r Y
y d * r Y
y e * r Y
y f * r Y
y g * r Y
y h * r Y
y i * r Y
y j * r Y
y k * r Y
y l * r Y
y m * r Y
y n * r Y
y o * r Y
y p * r Y
y q * r Y
y r * r Y
y s * r Y
y t * r Y
y u * r Y
y v * r Y
y w * r Y
y x * r Y
y y * r Y
y z * r Y
z * * l z
z , * r Z
z a * r Z
z b * r Z
z c * r Z
z d * r Z
z e * r Z
z f * r Z
z g * r Z
z h * r Z
z i * r Z
z j * r Z
z k * r Z
z l * r Z
z m * r Z
z n * r Z
z o * r Z
z p * r Z
z q * r Z
z r * r Z
z s * r Z
z t * r Z
z u * r Z
z v * r Z
z w * r Z
z x * r Z
z y * r Z
z z * r Z
A * * * 5
A A * l 6
B * * * 5
B B * l 6
C * * * 5
C C * l 6
D * * * 5
D D * l 6
E * * * 5
E E * l 6
F * * * 5
F F * l 6
G * * * 5
G G * l 6
H * * * 5
H H * l 6
I * * * 5
I I * l 6
J * * * 5
J J * l 6
K * * * 5
K K * l 6
L * * * 5
L L * l 6
M * * * 5
M M * l 6
N * * * 5
N N * l 6
O * * * 5
O O * l 6
P * * * 5
P P * l 6
Q * * * 5
Q Q * l 6
R * * * 5
R R * l 6
S * * * 5
S S * l 6
T * * * 5
T T * l 6
U * * * 5
U U * l 6
V * * * 5
V V * l 6
W * * * 5
W W * l 6
X * * * 5
X X * l 6
Y * * * 5
Y Y * l 6
Z * * * 5
Z Z * l 6
5 , * r 15
5 A a r 7
5 B b r 7
5 C c r 7
5 D d r 7
5 E e r 7
5 F f r 7
5 G g r 7
5 H h r 7
5 I i r 7
5 J j r 7
5 K k r 7
5 L l r 7
5 M m r 7
5 N n r 7
5 O o r 7
5 P p r 7
5 Q q r 7
5 R r r 7
5 S s r 7
5 T t r 7
5 U u r 7
5 V v r 7
5 W w r 7
5 X x r 7
5 Y y r 7
5 Z z r 7
7 * * r 7
7 , * r 4
6 * * l 6
6 _ * r 8
8 * _ r 9
9 * * r 9
9 _ * l 10
9 a A r 9
9 b B r 9
9 c C r 9
9 d D r 9
9 e E r 9
9 f F r 9
9 g G r 9
9 h H r 9
9 i I r 9
9 j J r 9
9 k K r 9
9 l L r 9
9 m M r 9
9 n N r 9
9 o O r 9
9 p P r 9
9 q Q r 9
9 r R r 9
9 s S r 9
9 t T r 9
9 u U r 9
9 v V r 9
9 w W r 9
9 x X r 9
9 y Y r 9
9 z Z r 9
10 * * l 10
10 , * l 11
11 * * l 11
11 , * l 12
12 _ 1 r 2
12 0 1 r 2
12 1 2 r 2
12 2 3 r 2
12 3 4 r 2
12 4 5 r 2
12 5 6 r 2
12 6 7 r 2
12 7 8 r 2
12 8 9 r 2
12 9 0 l 12
13 * _ l 13
13 , _ l 14
14 * _ l 14
14 , _ l halt
15 * * r 15
15 _ * l 16
16 * _ l 16
16 , _ l 17
17 * _ l 17
17 , _ l 18
18 * _ l 18
18 _ x * halt

Test it out here

Brief overview:

  1. Set up a counter on the left
  2. Find first uppercase letter in target and make it lowercase. If all letters are lowercase move to step 5.
  3. Find first uppercase letter in code. If most recent letter matches, move on to step 4. Else make letter lowercase and go back to step 2.
  4. Increment counter, make all letters capital, delete first letter in code. Go back to step 2. If no letters are left in code, return clear tape and print x.
  5. Clear all the tape but the counter.
\$\endgroup\$
8
  • \$\begingroup\$ Also, when testing, the format of the input should be: code,target (no space) \$\endgroup\$ Dec 30, 2015 at 21:23
  • \$\begingroup\$ How long did it take to make this? \$\endgroup\$
    – Adnan
    Dec 30, 2015 at 21:24
  • 18
    \$\begingroup\$ Started my homework at 2:00. Got distracted at 2:15. Started this at 2.20. Posted this at 4:20. So about 2 hours. \$\endgroup\$ Dec 30, 2015 at 21:25
  • 5
    \$\begingroup\$ +1, in PPCGSE, it doesn't have to be competing to be appreciated! \$\endgroup\$
    – user15259
    Jan 1, 2016 at 20:33
  • \$\begingroup\$ 9575 bytes (and the current bytecount in the header is false, there are extraneous spaces and some unnecessarily long state names). \$\endgroup\$ Oct 14, 2018 at 11:36
10
\$\begingroup\$

Pyth, 14 bytes

f!s.eqb@>zTkQ0

I'm not sure if this is Ok but if the input is impossible, nothing is written to stdout and a zero division error is written to stderr. Takes the input on 2 lines, the second one is surrounded by quotes.

Explanation:

               - autoassign z to first input
               - autoassign Q to second input
f            0 - The first value starting from 0 where the output is truthy
   .e       Q  - Enumerate over the second value
        >zT    - z[T:]
       @   k   - The kth item (number in enumeration)
      b        - The character in the enumeration
     q         - Are the two characters equal?
  s            - Sum the values
 !             - Invert them (want first where there isn't a collision)

Try it here!

\$\endgroup\$
8
\$\begingroup\$

SWI-Prolog, 115 bytes

a(S,W,R):-length(S,L),length(W,M),N is L-M,between(0,N,I),\+ (between(0,M,J),K is I+J,nth0(J,W,A),nth0(K,S,A)),R=I.

Usage example: a(`ABCDEFGHIJKL`,`HELLO`,R).. This uses the character codes strings declared with backticks. The answer is unified with R. If no match is found, this outputs false..

Explanation:

a(S,W,R):-
    length(S,L),length(W,M),     
    N is L-M,
    between(0,N,I),             % I is successively unified with an integer between 0 
                                % and the last possible index of the coded message

    \+ (                        % This will only be true if what's inside the parentheses 
                                % cannot be proven to be true

        between(0,M,J),         % J is successively unified with an integer between 0 
                                % and the length of the desired word
        K is I+J,
        nth0(J,W,A),nth0(K,S,A) % Check if one letter is the same in both string at 
                                % the same index
    ),                          % If it the case, then it will be 'true' and thus 
                                % the predicate \+ will be false, meaning we need to
                                % backtrack to try a different value of I

    R=I.                        % If we get here it means it didn't find any matching 
                                % letter for this value of I, which is then the answer.

Try it here

\$\endgroup\$
7
\$\begingroup\$

Ruby, 91 79 bytes

->a,b{[*a.chars.each_cons(b.size)].index{|x|x.zip(b.chars).all?{|y|y.uniq==y}}}

Curse you, Enumerator! Why do I have to convert from string to array to Enumerator to array and waste precious bytes? >:(

->a,b{                  # define lambda
[*                      # convert to array...
  a.chars               # get enumerator from string
  .each_cons(b.size)    # each consecutive group of (b.size) letters
]
.index{|x|              # find index of...
  x.zip(b.chars)        # zip group with second input string
  .all?{|y|             # is the block true for every element?
    y.uniq==y           # uniqueify results in same array (no dups)
}}}
\$\endgroup\$
1
  • \$\begingroup\$ Using [*...] as a golfy alternative to #to_a is a nice touch. \$\endgroup\$ Dec 30, 2015 at 19:55
7
\$\begingroup\$

CJam, 17 16 bytes

ll:A,ew{A.=:+!}#

Try it here.

Thanks to @PeterTaylor for saving a byte.

Explanation:

ll:A,ew    e# Finds every slice in the coded message with the length of the word
{A.=:+     e# Compare the characters in each slice to the characters in the word, and add up the result. If the sum is zero, then the slice and the word have no characters in common.
!}#        e# Invert truthiness (0 -> 1, non-0 -> 0) Return index of first truthy value.
\$\endgroup\$
3
  • \$\begingroup\$ array block # can save you a char: ll:A,ew{A.=:+!}# \$\endgroup\$ Dec 30, 2015 at 18:33
  • \$\begingroup\$ Amazing how far CJam can be golfed in almost every task... :-o \$\endgroup\$
    – agtoever
    Dec 30, 2015 at 19:35
  • \$\begingroup\$ @agtoever I wouldn't say it's really golfing, because 17 bytes was my very first try. The key feature is ew (make slices), everything else just follows. \$\endgroup\$
    – geokavel
    Dec 30, 2015 at 19:41
6
\$\begingroup\$

MATL, 27 bytes

jYbZ)tnb!wlhYCw!=a~ftn?1)1-

Examples

>> matl jYbZ)tnb!wlhYCw!=a~ftn?1)1-
> EEEEEEEEEEEE, HELLO

>> matl jYbZ)tnb!wlhYCw!=a~ftn?1)1-
> XEEFSLBSELDJMADNADKDPSSPRNEBWIENPF, DEUTSCHLAND
11

Explanation

j           % input string
YbZ)        % split into two strings based on space. Trailing comma is not a problem
tnb!wlhYC   % arrange first string into sliding columns of the size of the second
w!=         % compare with transposed second string, element-wise with broadcast
a~          % detect columns where all values are 0 (meaning unequal characters)
f           % find indices of such columns
tn?         % if there's at least one such column
1)1-        % pick index of the first and subtract 1 for 0-based indexing
\$\endgroup\$
4
\$\begingroup\$

Haskell, 72 bytes

l=length
h i w s|l s<l w= -1|and$zipWith(/=)w s=i|1<2=h(i+1)w$tail s
h 0

Usage: h 0 "DEUTSCHLAND" "XEEFSLBSELDJMADNADKDPSSPRNEBWIENPF" -> 11.

Simple recursive approach: if the word wcan be placed at the beginning of the string s, return the index counter i, else repeat with i incremented and the tail of s. Stop and return -1 if the length of s is less than the length of w.

\$\endgroup\$
4
\$\begingroup\$

Python 2.7, 111 characters

Tries all starting positions (a) and checks of any of the letters match (using the list comprehension). It returns "None" (Python's "NULL") if nothing is found (the for loop end and nothing is returned, which defaults to "None".

def d(c,s):
 for a in range(len(c)):
  if a not in [((c+s)[a+i:]).index(l)+a for i,l in enumerate(s)]:
   return a

Testsuite:

cases = {
         ("BHGEFXWFTIUPITHHLPETTTCLOEWOELM","WETTERBERICHT"):13,
         ("ABCDEFGHIJKL","HELLO"):0,
         ("EEEEEEEEEEEE","HELLO"):-1,
         ("XEEFSLBSELDJMADNADKDPSSPRNEBWIENPF","DEUTSCHLAND"):11
        }

for idx,(code,string) in enumerate(cases):
    output=d(code,string)
    print "Case: {}: d({:<35},{:<16}) gives: {}. Correct answer is: {}.".format(idx+1,code,string,output,cases[(code,string)])
\$\endgroup\$
1
  • \$\begingroup\$ You actually have 114 bytes, not 111. Here is a 106-byte version: def d(c,s): for a in range(len(c)): if a not in[a+(c+s)[a+i:].index(l)for i,l in enumerate(s)]:return a \$\endgroup\$
    – movatica
    Apr 28, 2019 at 9:29
4
\$\begingroup\$

Brachylog, 48 bytes

[S:W]hlL,WlM,L-M=:0reI,'(0:MeJ+I=:SrmA,W:JmA),I.

This is a direct translation of my Prolog answer. The brachylog_main/2 generated predicate expects a list of two character codes strings with the coded string first as input, and returns the index as output, e.g. brachylog_main([`ABCDEFGHIJKL`,`HELLO`],R)..

Explanation

[S:W]                                            § Unify the input with the list [S,W]

     hlL,WlM,                                    § L and M are the length of S and W

             L-M=:0reI,                          § Enumerate integers between 0 and the 
                                                 § last possible index

                       '(                   ),I. § Unify the output with the current 
                                                 § enumerated integer if what's inside the 
                                                 § parenthesis cannot be proven to be true

                         0:MeJ                   § Enumerate integers between 0 and the
                                                 § length of the word desired

                              +I=:SrmA,W:JmA     § Check if both strings contain at matching
                                                 § indexes the same letter (unified with A)
\$\endgroup\$
3
\$\begingroup\$

JavaScript, 129 121 118 119* 118 bytes

(w,t){for(j=0;(x=t.length)<(y=w.length);t=' '+t,j++){for(a=i=0;++i<y;)w[i]==t[i]?a=1:a;if(!a)break}return x==y?-1:j}

w is the coded message, t is the test string. This doesn't use regexes, but just compares letter by letter, shifting the test string (i.e. "WETTERBERICHT") by appending space before it. Easy and boring.


* test case with no match didn't work, now it does

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

Japt, 12 bytes (non-competitive)

UàVr'."[^$&]

I'm gonna need some help with this one.

\$\endgroup\$
5
  • \$\begingroup\$ Uhhh... Japt doesn't have .search? facepalm \$\endgroup\$ Jan 1, 2016 at 20:25
  • \$\begingroup\$ This can now be done with UàVr'."[^$&] for 12. \$\endgroup\$ Jan 12, 2016 at 4:06
  • \$\begingroup\$ Cool, we're winning now! \$\endgroup\$ Jan 12, 2016 at 4:12
  • \$\begingroup\$ Since the latest revision of this answer uses functionality that postdates the question, I'm marking it as non-competitive. \$\endgroup\$
    – user45941
    Jan 12, 2016 at 4:55
  • \$\begingroup\$ Oh forgot about that :P Thanks! \$\endgroup\$ Jan 12, 2016 at 5:00
3
\$\begingroup\$

05AB1E, 14 13 11 bytes

ŒIgùÅΔø€Ëà≠

-1 byte thanks to @ovs.

Try it online or verify all test cases.

Explanation:

Œ            # Get all substrings of the first (implicit) input
 Ig          # Get the length of the second input
   ù         # Only leave the substrings of that length
    ÅΔ       # Find the first (0-based) index which is truthy for:
             # (which results in -1 if none are truthy)
      ø      #  Zip/transpose; create pairs of the characters in the current substring
             #  and the second (implicit) input
       €Ë    #  Check for each if both characters are equal (1 if truthy; 0 if falsey)
         à   #  Get the maximum (basically equal to an `any` builtin)
          ≠  #  And invert the boolean (!= 1)
             # (after which the result is output implicitly)
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Dude, this was totally supposed to be @Emigna's answer ;). I wanted to come here and make a joke about him answering an adnan-question with almost-his-name in it. +1 (Noticed you answered 4 years after-the-fact after I posted this after-the-fact comment). \$\endgroup\$ Apr 29, 2019 at 21:31
  • \$\begingroup\$ @MagicOctopusUrn When I saw the challenge I thought the same thing, but @Emigna usually answers new answers and doesn't look that often at existing answers. So since this one didn't had any 05AB1E answers I figured I'd add one. You're indeed right that @Emigna would have been best suited to answer this challenge. ;p \$\endgroup\$ Apr 30, 2019 at 6:12
  • 1
    \$\begingroup\$ 13 bytes by using ε instead of ʒ to get rid of D. \$\endgroup\$
    – ovs
    Nov 26, 2020 at 11:10
  • \$\begingroup\$ @ovs Thanks, that actually opens up 2 more bytes to save with ÅΔ! :) \$\endgroup\$ Nov 26, 2020 at 14:57
2
\$\begingroup\$

PHP – 155 bytes

<?php for($p=$argv[1],$q=$argv[2],$l=strlen($q),$i=0,$r=-1;$i<strlen($p)-$l;$i++)if(levenshtein($q,substr($p,$i,$l),2,1,2)==$l){$r=$i;break;}echo$r."\n";

Save as crack.php and run with the arguments in the command line. E.g.:

$ php crack.php BHGEFXWFTIUPITHHLPETTTCLOEWOELM WETTERBERICHT
13
\$\endgroup\$
2
  • \$\begingroup\$ You can save 25 bytes and golf it down to 130 bytes: for($r=-1;$i<strlen($p=$argv[1])-$l=strlen($q=$argv[2]);$i++)if(levenshtein($q,substr($p,$i,$l),2,1,2)==$l&&$r=$i)break;echo"$r↵"; \$\endgroup\$ Dec 30, 2015 at 19:03
  • \$\begingroup\$ @insertusernamehere - Wow, that's impressive! So much so that I wouldn't feel right using it! I thought I was being clever using levenshtein, but probably a straightforward iteration within an iteration could do it in fewer bytes. \$\endgroup\$
    – user15259
    Jan 1, 2016 at 20:30
2
\$\begingroup\$

𝔼𝕊𝕄𝕚𝕟, 14 chars / 25 bytes

îĊⱮ(í,↪`⁅⦃$}]`

Try it here (Firefox only).

Kudos to @apsillers for the idea.

Explanation

               // implicit: î = input1, í = input2
îĊ             // search for first occurrence of:
  Ɱ(í,↪`⁅⦃$}]` // regex created by wrapping each word in [^ and ] (negation matches)
\$\endgroup\$
1
  • \$\begingroup\$ Whoever downvoted this, is there a reason why? \$\endgroup\$ Dec 31, 2015 at 18:32
2
\$\begingroup\$

Ruby, 43 36 bytes

edit: String interpolation inside string interpolation inside a regex, yikes.

The lazy approach: translates the word to a "negative" regex -- The =~ operator does the rest.

->m,w{m=~/#{"[^#{w.chars*'][^'}]"}/}

Test:

f=->m,w{m=~/#{"[^#{w.chars*'][^'}]"}/}

require "minitest/autorun"

describe :f do
  it "works for the given test cases" do
    assert_equal 13, f["BHGEFXWFTIUPITHHLPETTTCLOEWOELM", "WETTERBERICHT"]
    assert_equal 0, f["ABCDEFGHIJKL", "HELLO"]
    assert_equal nil, f["EEEEEEEEEEEE", "HELLO"]
    assert_equal 11, f["XEEFSLBSELDJMADNADKDPSSPRNEBWIENPF", "DEUTSCHLAND"]
    assert_equal nil, f["HKKH", "JJJJJ"]
  end
end
\$\endgroup\$
2
\$\begingroup\$

Python 3, 79 bytes

lambda x,y:[sum(map(str.__eq__,x[i:],y))for i in range(len(x)-len(y))].index(0)

Try it online!

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

Husk, 14 13 bytes

Or 12 bytes using 1-based indexing and returning 0 for no-occurrence.

←VoΠz≠⁰↓_L⁰ṫ²

Try it online!

←                   # subtract 1 to get 0-based indexing
 V                  # index of first element of
            ṫ²      # all suffixes of arg 2,
        ↓_          # with n elements removed from the end, 
          L⁰        # where n is the length of arg 1,
                    # that satisfies
  ȯ¬                # NOT
    Σ               # any
     z=⁰            # elements are equal when zipped with arg 1
\$\endgroup\$
2
\$\begingroup\$

K (ngn/k), 19 bytes

{**&(#y)(~|/y=)':x}

Try it online!

Takes the encoded message as x and the word as y. Returns 0N (the integer null) if no possible occurrence was found.

  • (#y)(~|/y=)':x use i f':x stencil to apply (~|/y=) to each (#y)-length window of the input x
    • (#y) get the length of the input word
    • (~|/y=) check if any letters are in the same position in the word and the slice of the encoded message; then negate the resulting bitmask
  • **& return the index of the first possible occurrence of the word in the encoded message
\$\endgroup\$
2
\$\begingroup\$

Vyxal, 20 bytes

:ǎ'⁰l;ƛ⁰Zƛ≈;aßn;~ḃhḟ

Try it Online!

I wrote this so long ago, waiting for to work on strings, that I forgot how this even works

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

Jelly, 9 7 bytes

t"ƑÐƤi1

Try it online!

   ÐƤ      For each suffix,
  Ƒ        is it the same after
t          trimming off
 "         the corresponding letter of the word from each of its letters?
     i1    Find the first index of 1.

Wait, what?

This beats the original, W€ḟ"ƑÐƤi1, by completely dropping the step of wrapping each letter into a singleton list. As for how:

A Jelly string is a list of characters, which is to say it's a Python list of length-1 Python strings. For example, “this” is really ["t","h","i","s"].

Most list builtins are built to handle lists whether that's what they got or not, by passing all arguments through iterable, and in the case of a single character this wraps it in a singleton list to obtain a length-1 Jelly string. does this, and as a result its output is also always a list--so ḟ", mapped over corresponding pairs, gives a list of lists, and for it to ever not change a suffix of the ciphertext each of its characters has to be pre-wrapped to match.

However, t does not call iterable on its left argument, so here t" operates on the Python string characters themselves of the ciphertext suffix, and either leaves them alone or trims them to ''.

Finally, Ƒ performs a strict, non-vectorizing equality check, and " only maps its given link over pairs of corresponding elements up to the length of the shorter argument, placing the remainder of the longer argument into the result verbatim. If the ciphertext suffix is longer, the remainder automatically matches itself leaving only the prefix of length equal to the word to be considered, but if the word is longer, the result cannot be equal to the suffix because it is itself longer than the suffix.

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

TeaScript, 14 bytes 20

xc(yl#`[^${l}]

Similar to @aspillers clever JavaScript solution.

Explanation

             // Implicit: x = 1st input, y = 2nd input
x            // First input
 c           // returns index of regex match
 yl#         // Loop through every char in `y`
    `[^${l}] // Replace template, ${l} because current char in `y`
\$\endgroup\$
2
  • \$\begingroup\$ Does $& not work in place of ${l}? \$\endgroup\$ Jan 1, 2016 at 20:30
  • \$\begingroup\$ @ETHproductions not in this case because I'm using a loop rather than a replace \$\endgroup\$
    – Downgoat
    Jan 1, 2016 at 20:55
1
\$\begingroup\$

Jolf, 14 bytes

Try it here!

 siρI".'[^$&]
_s            search
  i            input 1 for
    I          input 2
   ρ            replacing (2 byte rho character)
     ".'         all characters
        [^$&]    with that
\$\endgroup\$
1
\$\begingroup\$

Perl, 38 + 1 = 39 bytes

perl -E "$r=<>=~s!.![^$&]!gr;say@-if<>=~/$r/x" < input

where input looks like:

WETTERBERICHT
BHGEFXWFTIUPITHHLPETTTCLOEWOELMRXXPAKAXMAMTXXUDLTWTNHKELEPPLHPRQ

This is the same idea as the javascript one.

\$\endgroup\$
1
  • \$\begingroup\$ The 'x' is unnecessary \$\endgroup\$
    – Zaid
    Jan 2, 2016 at 8:37
1
\$\begingroup\$

Java, 136 Characters

Regex-based solution inspired by apsillers JavaScript version.

class L{public static void main(String[]a){a=a[0].split(a[1].replaceAll("(.)","[^$1]"));System.out.print(a.length>1?a[0].length():-1);}}
\$\endgroup\$
1
\$\begingroup\$

Perl 5, 46 bytes

Uses @apsillers' regex idea.

$a=<>=~s/./[^$&]/gr;/$a/g;$_=(length$a)/-4+pos

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Jelly, 10 9 bytes

ṡ⁹L¤=S€i0

Try it online!

Uses 1-indexing, which is Jelly's default. 10 bytes to use 0-indexing. This returns \$0\$ if no occurrence is found (\$-1\$ for the 0-indexed version)

How it works

ṡ⁹L¤=S€i0 - Main link. Takes M on the left and W on the right
   ¤      - Create a nilad:
 ⁹        -   W
  L       -   Length
ṡ         - Overlapping slices of length W of M
    =     - Compare for equality with W
     S€   - Count the number of 1s in each
       i0 - First index of 0, else 0 if not found
\$\endgroup\$
1
  • \$\begingroup\$ Took me a solid 5 minutes to figure out why the S€ can't be §... if there aren't any slices, = gives W, and § tries to sum the string, but the S of each character leaves them unchanged since they're treated as scalars the same way as integers would be. \$\endgroup\$ Mar 9, 2022 at 4:15
1
\$\begingroup\$

R, 56 bytes

\(x,y)match(T,Map(\(i)all(x[i+seq(y)]!=y),seq(x)-1),0)-1

Attempt This Online!

Counterintuitively (at least to me), match(TRUE,NA,nomatch=0) returns 0, rather than NA, but this is actually helpful here.
We could save 2 bytes (delete -1) by using R's native 1-based indexing; and a further 1 or 2 bytes by returning nothing (using which()[1]) or NA (delete ,0) to indicate no occurrence.

\$\endgroup\$
1
\$\begingroup\$

Brachylog (v2), 16 13 bytes

{sʰz₂}ᶠ∋↙.≠ᵐ∧

Try it online!

Takes input as a list [message, word]. The header prints it all very prettily but the output of the actual predicate is just a 0-index if it succeeds and declarative failure if it doesn't.

{    }ᶠ          Find every possible
   z             zip of the word with
    ₂            an equal-length
 sʰ              contiguous substring of the ciphertext.
       ∋         One of those
          ≠ᵐ     contains no pair the elements of which are equal,
        ↙.  ∧    and its index is the output.
\$\endgroup\$
1
\$\begingroup\$

SM83/Z80, 30 bytes

First input (encrypted) in hl, second (unencrypted) in de. Output in bc. Bytes with second nybble underlined should be incremented by 2 for Z80.

01 00 00 E5 D5 09 7E A7
28 11̱ 1A A7 28 0A̱ BE 23
13 20 F3̱ 03 D1 E1 18 EḆ
02 FF FF D1 E1 C9
ecr:
 ld bc,0                // 01 00 00 setup bc
oloop:
 push hl                // E5       store originals
 push de                // D5
 add hl,bc              // 09       handle offset
iloop:
 ld a,(hl)              // 7E
 and a                  // A7       test if at end of arg 2
 jr z,succ              // 28 11/13 if so succeed
 ld a,(de)              // 1A       load encrypted char
 and a                  // A7       if at end
 jr z,fail              // 28 0A/0C fail
 cp (hl)                // BE       compare to other side
 inc hl                 // 23
 inc de                 // 13       next char
 jr nz,iloop            // 20 F3/F5 if unequal, loop
 inc bc                 // 03       else inc offset
 pop de                 // D1
 pop hl                 // E1       reload originals
 jr oloop               // 18 EB/ED and jump back
fail:
 ld bc,-1               // 02 FF FF insert failure
succ:
 pop de                 // D1
 pop hl                 // E1       reload original args
 ret                    // C9       return
\$\endgroup\$

Your Answer

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

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