26
\$\begingroup\$

In this challenge, you are passed two words: Your job is to determine if they are adjacent.

Two letters are adjacent if:

  1. They are the same letter, or
  2. They are lexicographically adjacent.

For example, J is adjacent to I,J, and K only. Z is not adjacent to A

Two words are adjacent if:

  1. They are the same length, and
  2. Each letter is adjacent to a unique letter in the other word.

For example, CAT is adjacent to SAD, as C>D, A>A, T>S.
FREE is not adjacent to GRRD (each E needs a letter to pair with)
.

Input/Output

You are passed two strings, and you need to return a truthy value if they are adjacent, otherwise a falsy value. You should return within a minute for all test cases below.

You can assume that the strings will only contain uppercase, alphabetic letters.

The two strings can be passed as a list, or concatenated, with or without quotes.

Test Cases

Truthy:

A A
A B
C B
DD CE
DE FC
ABCD BCDE
AACC DBBB
DJENSKE FDJCLMT
DEFGHIJKL HJLEHMCHE
IKLIJJLIJKKL LJLJLJLJLJHI
ACEGIKMOQSUWY BLNPRDFTVHXJZ
QQSQQRRQSTTUQQRRRS PQTTPPTTQTPQPPQRTP
ELKNSDUUUELSKJFESD DKJELKNSUELSDUFEUS

Falsy:

A C
A Z
B J
JK J
CC BA
CE D
DJENSKE GDJCLMT
DEFGHIJKL HJLHMCHE
IJKLIJKLKIJL LIJLLHJLJLLL 
AWSUKMEGICOQY RSHXBLJLNQDFZ
QQSQQRRQSTTUQQQRRS PQTTPPTTQTPQPPQRTT
ELKNSDUVWELSKJFESD DKJELKNSUELSDUFEUS

This is , so the shortest valid answer wins!

\$\endgroup\$
5
  • \$\begingroup\$ Can the input have quotes around them, like "A A"? \$\endgroup\$
    – TanMath
    Jan 25, 2016 at 3:04
  • \$\begingroup\$ Fixed test cases. Quotes are fine. \$\endgroup\$ Jan 25, 2016 at 3:06
  • \$\begingroup\$ Will the be input only be uppercase? \$\endgroup\$
    – TanMath
    Jan 25, 2016 at 3:24
  • \$\begingroup\$ You can assume that, yes. \$\endgroup\$ Jan 25, 2016 at 3:24
  • \$\begingroup\$ I think you should mention in the challenge text that you allow defining the input strings with quotes. Would a single array of the form {'string1' 'string2'} be acceptable as well? \$\endgroup\$
    – Luis Mendo
    Jan 25, 2016 at 21:57

15 Answers 15

11
\$\begingroup\$

CJam, 14 13 12 bytes

r$r$.-:)3,-!

Try it online! or verify all test cases at once.

Algorithm

Let s and t be two sorted words of the same length. For s and t to be lexicographically adjacent (LA), it is necessary and sufficient that all pairs of its corresponding characters are also LA.

The condition is clearly sufficient for all words, and necessary for words of length 1.

Now, assume s and t have length n > 1, and let a and b be the first characters, resp., of s and t.

Since s and t are LA, there is some bijective mapping φ between the characters of s and the characters of t such that x and φ(x) are LA for all x in s, meaning that |x - φ(x)| ≤ 1 for all x in s.

Let c = φ(a) and d = φ-1(b). Because of a's and b's minimality, a ≤ d (1) and b ≤ c (2).

Furthermore, since b and d, and a and c, and LA, d ≤ b + 1 (3) and c ≤ a + 1 (4).

By combining (1) and (3), and (2) and (4), we get that a ≤ d ≤ b + 1 and b ≤ c ≤ a + 1, from which we deduce that a - 1 ≤ b ≤ a + 1 and, therefore, that a and b are LA.

Now, by combining (1) and (4), and (2) and (3), we get that c - 1 ≤ a ≤ d and d - 1 ≤ b ≤ c, from which we deduce that c - 1 ≤ d ≤ c + 1 and, therefore that c and d are LA.

Thus, if we redefine φ by φ(a) = b and φ(d) = c, |x - φ(x)| ≤ 1 will still hold for all x in s and, in particular, for all x in s[1:].

This way, s[0] = a and t[0] = b, and s[1:] and t[1:], are LA.

Since s[1:] has length n - 1, this proves the necessity by induction.

Code

r               e# Read the first word from STDIN.
 $              e# Sort its characters.
  r             e# Read the second word from STDIN.
   $            e# Sort its characters.
    .-          e# Perform vectorized subtraction.
                e# This pushes either the difference of char codes of two
                e# corresponding characters or a character that has no does not
                e# correspond to a character in the other, shorter word.
      :)        e# Increment all results.
                e# In particular, this maps [-1 0 1] to [0 1 2].
        3,      e# Push the range [0 1 2].
          -     e# Perform set difference, i.e., remove all occurrences of 0, 1 and
                e# 2 from the array of incremented differences.
           !    e# Apply logical NOT. This gives 1 iff the array was empty iff
                e# all differences gave -1, 0 or 1.
\$\endgroup\$
2
  • \$\begingroup\$ I think there's a simpler argument -- the only places the matching can violate the sorted order is when two things cross like C->Y, D->X, and those can just be uncrossed. \$\endgroup\$
    – xnor
    Jan 25, 2016 at 5:18
  • \$\begingroup\$ @xnor That's basically what I wrote. Just with a lot more words. :P \$\endgroup\$
    – Dennis
    Jan 25, 2016 at 5:21
4
\$\begingroup\$

MATL, 10 12 17 bytes

c!S!odXl2<

This uses Dennis' approach: sort first and compare characters in matching positions.

Input is an array of strings, with the format {'CAT 'SAD'}.

Output is an array of zeros and ones. A result is truthy iff it contains all ones (this is agreed to be truthy).

Uses current release (10.2.1), which is earlier than this challenge.

EDIT: Function Xl has been renamed to | in newer versions of the language (and o is no longer necessary). The link below includes those modifications.

Try it online!

Explanation:

c         % implicitly cell array of strings and convert to 2D char array. 
          % This pads with spaces if needed
!S!       % sort each row
o         % convert array from char to double
d         % difference between elements in the same column
Xl        % absolute value of each entry
2         % number literal
<         % each entry becomes 1 if smaller than 2 (adjacent letters), and 0 otherwise

Old approach, which accepts the strings as separate inputs: 12 bytes:

SiSXhcodXl2<

EDIT: the code in the link has been modified acording the changes in the language; see comment above.

Try it online!

Explanation:

S         % implicitly input first string and sort
iS        % input second string and sort
Xh        % build cell array with these two strings
c         % convert to 2D char array. This pads with spaces if needed
o         % convert array from char to double
d         % difference between elements in the same column
Xl        % absolute value of each entry
2         % number literal
<         % each entry becomes 1 if smaller than 2 (adjacent letters), and 0 otherwise
\$\endgroup\$
5
  • 1
    \$\begingroup\$ So the array [1 0 1] is falsy in MATL. That's useful. \$\endgroup\$
    – Dennis
    Jan 25, 2016 at 19:56
  • \$\begingroup\$ @Dennis Isn't that falsey in other languages as well? In Matlab/Octave it works that way: all elements have to be nonzero \$\endgroup\$
    – Luis Mendo
    Jan 25, 2016 at 21:51
  • 1
    \$\begingroup\$ No. In fact, I don't know another language that behaves this way. In Python and CJam, e.g., arrays are truthy iff they're non-empty. In JavaScript and Ruby, e.g., all arrays are truthy. \$\endgroup\$
    – Dennis
    Jan 26, 2016 at 0:26
  • \$\begingroup\$ @Dennis That's weird to my Matlab way of thinking. So in Python an array [0 0] is truthy? \$\endgroup\$
    – Luis Mendo
    Jan 26, 2016 at 0:27
  • 1
    \$\begingroup\$ Yes, because it has a positive length. That's usually annoying when golfing. \$\endgroup\$
    – Dennis
    Jan 26, 2016 at 0:35
2
\$\begingroup\$

C, 233 bytes

#include <stdlib.h>
#include <string.h>
#define h char
#define r return
int c(void*a,void*b){r*(h*)a-*(h*)b;}int a(h*s,h*t){int l=strlen(s),m=strlen(t);if(l!=m)r 0;qsort(s,l,1,c);qsort(t,m,1,c);while(l--)if(abs(s[l]-t[l])>1)r 0;r 1;}

You can test it by saving that as adj.h and then using this adj.c file:

#include <stdio.h>
#include "adj.h"

int main() {
  char aa[] = "A", A[] = "A";
  char b[] = "A", B[] = "B";
  char cc[] = "C", C[] = "B";
  char d[] = "DD", D[] = "CE";
  char e[] = "DE", E[] = "FC";
  char f[] = "ABCD", F[] = "BCDE";
  char g[] = "AACC", G[] = "DBBB";
  char hh[] = "DJENSKE", H[] = "FDJCLMT";
  char i[] = "DEFGHIJKL", I[] = "HJLEHMCHE";
  char j[] = "IKLIJJLIJKKL", J[] = "LJLJLJLJLJHI";
  char k[] = "ACEGIKMOQSUWY", K[] = "BLNPRDFTVHXJZ";
  char l[] = "QQSQQRRQSTTUQQRRRS", L[] = "PQTTPPTTQTPQPPQRTP";
  char m[] = "ELKNSDUUUELSKJFESD", M[] = "DKJELKNSUELSDUFEUS";
  char n[] = "A", N[] = "C";
  char o[] = "A", O[] = "Z";
  char p[] = "B", P[] = "J";
  char q[] = "JK", Q[] = "J";
  char rr[] = "CC", R[] = "BA";
  char s[] = "CE", S[] = "D";
  char t[] = "DJENSKE", T[] = "GDJCLMT";
  char u[] = "DEFGHIJKL", U[] = "HJLHMCHE";
  char v[] = "IJKLIJKLKIJL", V[] = "LIJLLHJLJLLL";
  char w[] = "AWSUKMEGICOQY", W[] = "RSHXBLJLNQDFZ";
  char x[] = "QQSQQRRQSTTUQQQRRS", X[] = "PQTTPPTTQTPQPPQRTT";
  char y[] = "ELKNSDUVWELSKJFESD", Y[] = "DKJELKNSUELSDUFEUS";
  char *z[] = {aa,b,cc,d,e,f,g,hh,i,j,k,l,m,n,o,p,q,rr,s,t,u,v,w,x,y};
  char *Z[] = {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};

  for(int _=0;_<25;_++) {
    printf("%s %s: %s\r\n", z[_], Z[_], a(z[_], Z[_]) ? "true" : "false");
  }

  return 0;
}

Then compile using gcc adj.c -o adj. The output is:

A A: true
A B: true
C B: true
DD CE: true
DE CF: true
ABCD BCDE: true
AACC BBBD: true
DEEJKNS CDFJLMT: true
DEFGHIJKL CEEHHHJLM: true
IIIJJJKKKLLL HIJJJJJLLLLL: true
ACEGIKMOQSUWY BDFHJLNPRTVXZ: true
QQQQQQQRRRRRSSSTTU PPPPPPPQQQQRTTTTTT: true
DDEEEFJKKLLNSSSUUU DDEEEFJKKLLNSSSUUU: true
A C: false
A Z: false
B J: false
JK J: false
CC AB: false
CE D: false
DEEJKNS CDGJLMT: false
DEFGHIJKL HJLHMCHE: false
IIIJJJKKKLLL HIJJJLLLLLLL: false
ACEGIKMOQSUWY BDFHJLLNQRSXZ: false
QQQQQQQQRRRRSSSTTU PPPPPPQQQQRTTTTTTT: false
DDEEEFJKKLLNSSSUVW DDEEEFJKKLLNSSSUUU: false
\$\endgroup\$
1
2
\$\begingroup\$

Python 2, 90 bytes

lambda A,B:all(ord(b)-2<ord(a)<ord(b)+2for a,b in zip(sorted(A),sorted(B)))*len(A)==len(B)

Simple anonymous function, I have to have a separate check for length because zip will just contatenate. Theres a similar function in itertools (zip_longest) which would pad empty strings, but that would be quite costly.

Testing with

f=lambda A,B:all(ord(b)-2<ord(a)<ord(b)+2for a,b in zip(sorted(A),sorted(B)))*len(A)==len(B)

for case in testCases.split('\n'):
    print case, f(*case.split())

produces:

A A True
A B True
C B True
DD CE True
DE FC True
ABCD BCDE True
AACC DBBB True
DJENSKE FDJCLMT True
DEFGHIJKL HJLEHMCHE True
IKLIJJLIJKKL LJLJLJLJLJHI True
ACEGIKMOQSUWY BLNPRDFTVHXJZ True
QQSQQRRQSTTUQQRRRS PQTTPPTTQTPQPPQRTP True
ELKNSDUUUELSKJFESD DKJELKNSUELSDUFEUS True
A C False
A Z False
B J False
JK J False
CC BA False
CE D False
DJENSKE GDJCLMT False
DEFGHIJKL HJLHMCHE False
IJKLIJKLKIJL LIJLLHJLJLLL  False
AWSUKMEGICOQY RSHXBLJLNQDFZ False
QQSQQRRQSTTUQQQRRS PQTTPPTTQTPQPPQRTT False
ELKNSDUVWELSKJFESD DKJELKNSUELSDUFEUS False
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 86 90 94

Edit 4 bytes saved thx @Neil
Edit 2 4 bytes save thx @Mwr247

(a,b)=>[...[...a].sort(),0].every((x,i)=>parseInt(x+([...b].sort()[i]||0),36)%37%36<2)

Note: adjacency check on a pair of letters. Take the pair as a base 36 number n, if the letters are equal, then n = a*36+a = a*37. If there is a difference of 1 then n = a*36+a+1 = a*37+1 or n = a*36+a-1 = a*37-1. So n % 37 must be 0, 1 or 36. And n%37%36 must be 0 or 1.

Note 2: the added '0' is used to ensure that a and b are the same length. It's shorter then a.length==b.length

F=(a,b)=>[...[...a].sort(),0].every((x,i)=>parseInt(x+([...b].sort()[i]||0),36)%37%36<2)

console.log=x=>O.textContent+=x+'\n';

testOK=[['A','A'],['A','B'],['C','B'],['DD','CE'],['DE','FC'],
['ABCD','BCDE'],['AACC','DBBB'],['DJENSKE','FDJCLMT'],
['DEFGHIJKL','HJLEHMCHE'],['IKLIJJLIJKKL','LJLJLJLJLJHI'],
['ACEGIKMOQSUWY','BLNPRDFTVHXJZ'],
['QQSQQRRQSTTUQQRRRS','PQTTPPTTQTPQPPQRTP'],
['ELKNSDUUUELSKJFESD','DKJELKNSUELSDUFEUS']];
testFail=[['A','C'],['A','Z'],['B','J'],['JK','J'],['CC','BA'],['CE','D'],
['DJENSKE','GDJCLMT'],['DEFGHIJKL','HJLHMCHE'],
['IJKLIJKLKIJL','LIJLLHJLJLLL',''],
['AWSUKMEGICOQY','RSHXBLJLNQDFZ'],
['QQSQQRRQSTTUQQQRRS','PQTTPPTTQTPQPPQRTT'],
['ELKNSDUVWELSKJFESD','DKJELKNSUELSDUFEUS']];

console.log('TRUE')
testOK.forEach(t=>{
  var a=t[0],b=t[1],r=F(a,b)
  console.log(r+' '+a+' '+b)
})  
console.log('FALSE')
testFail.forEach(t=>{
  var a=t[0],b=t[1],r=F(a,b)
  console.log(r+' '+a+' '+b)
})
<pre id=O></pre>

\$\endgroup\$
4
  • \$\begingroup\$ I think you can use '' in place of the first '0' since it doesn't change the value of the parse. \$\endgroup\$
    – Neil
    Jan 25, 2016 at 20:00
  • \$\begingroup\$ @Neil right, and thinking again it's even better. I can use numeric 0 and 0. When adding to a string it become a string anyway, and numeric 0+0 is still 0 mod whatever \$\endgroup\$
    – edc65
    Jan 25, 2016 at 22:32
  • \$\begingroup\$ I believe you can collapse your b sort with the character reference: (a,b)=>[...[...a].sort(),0].every((x,i)=>parseInt(x+([...b].sort()[i]||0),36)%37%36<2) = 86 bytes \$\endgroup\$
    – Mwr247
    Feb 1, 2016 at 23:17
  • \$\begingroup\$ @Mwr247 clever. Thanks \$\endgroup\$
    – edc65
    Feb 2, 2016 at 7:21
1
\$\begingroup\$

JavaScript ES6, 117 bytes 116 bytes 111 bytes 109 bytes

(j,k)=>j.length==k.length&&(f=s=>[...s].sort())(j).every((c,i)=>Math.abs(c[h='charCodeAt']()-f(k)[i][h]())<2)

Test Cases

a=(j,k)=>j.length==k.length&&(f=s=>[...s].sort())(j).every((c,i)=>Math.abs(c[h='charCodeAt']()-f(k)[i][h]())<2);
// true
console.log('A A:', a('A', 'A'));
console.log('A B:', a('A', 'B'));
console.log('C B:', a('C', 'B'));
console.log('DD CE:', a('DD', 'CE'));
console.log('DE FC:', a('DE', 'FC'));
console.log('ABCD BCDE:', a('ABCD', 'BCDE'));
console.log('AACC DBBB:', a('AACC', 'DBBB'));
console.log('DJENSKE FDJCLMT:', a('DJENSKE', 'FDJCLMT'));
console.log('DEFGHIJKL HJLEHMCHE:', a('DEFGHIJKL', 'HJLEHMCHE'));
console.log('IKLIJJLIJKKL LJLJLJLJLJHI:', a('IKLIJJLIJKKL', 'LJLJLJLJLJHI'));
console.log('ACEGIKMOQSUWY BLNPRDFTVHXJZ:', a('ACEGIKMOQSUWY', 'BLNPRDFTVHXJZ'));
console.log('QQSQQRRQSTTUQQRRRS PQTTPPTTQTPQPPQRTP:', a('QQSQQRRQSTTUQQRRRS', 'PQTTPPTTQTPQPPQRTP'));
console.log('ELKNSDUUUELSKJFESD DKJELKNSUELSDUFEUS:', a('ELKNSDUUUELSKJFESD', 'DKJELKNSUELSDUFEUS'));

// false
console.log('A C:', a('A', 'C'));
console.log('A Z:', a('A', 'Z'));
console.log('B J:', a('B', 'J'));
console.log('JK J:', a('JK', 'J'));
console.log('CC BA:', a('CC', 'BA'));
console.log('CE D:', a('CE', 'D'));
console.log('DJENSKE GDJCLMT:', a('DJENSKE', 'GDJCLMT'));
console.log('DEFGHIJKL HJLHMCHE:', a('DEFGHIJKL', 'HJLHMCHE'));
console.log('IJKLIJKLKIJL LIJLLHJLJLLL:', a('IJKLIJKLKIJL', 'LIJLLHJLJLLL'));
console.log('AWSUKMEGICOQY RSHXBLJLNQDFZ:', a('AWSUKMEGICOQY', 'RSHXBLJLNQDFZ'));
console.log('QQSQQRRQSTTUQQQRRS PQTTPPTTQTPQPPQRTT:', a('QQSQQRRQSTTUQQQRRS', 'PQTTPPTTQTPQPPQRTT'));
console.log('ELKNSDUVWELSKJFESD DKJELKNSUELSDUFEUS:', a('ELKNSDUVWELSKJFESD', 'DKJELKNSUELSDUFEUS'));
<!-- results pane console output; see http://meta.stackexchange.com/a/242491 -->
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Credit

  • @rink.attendant.6 shaved off 5 bytes
  • @user81655 shaved off 2 bytes
\$\endgroup\$
2
  • \$\begingroup\$ Can you use [...s] instead of s.split('')? \$\endgroup\$ Jan 25, 2016 at 6:08
  • \$\begingroup\$ @rink.attendant.6, yes, thank you. Still getting used to ES6 and that is one shortcut I need to remember! \$\endgroup\$ Jan 25, 2016 at 6:18
1
\$\begingroup\$

JavaScript (ES6), 87 bytes

(a,b)=>![...a].sort().some((d,i)=>(d[c='charCodeAt']()-([...b].sort()[i]||c)[c]())/2|0)

Uses a zero-centric symmetrical range check by dividing by the max value, then truncating with a bitwise "or" (|). Shorter than having to do two checks, or one with Math.abs().

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

Haskell, 67 63 bytes

import Data.List
f a=any(null.(a\\)).mapM(\x->[pred x..succ x])

Usage example: f "FREE" "GRRD" -> False.

How it works (note: f is partially point-free and the second parameter b does not appear in the definition):

mapM(\x->[pred x..succ x])      -- for each letter of b make a list of the
                                -- predecessor, the letter itself and the successor.
                                -- Make a list of every possible combination
                                -- thereof, e.g "dr" ->
                                -- ["cq","cr","cs","dq","dr","ds","eq","er","es"] 
any(null.(a\\))                 -- see if the difference between any of the
                                -- combinations and the other parameter a is
                                -- empty, i.e. they have the same elements

Edit: @xnor found 4 bytes to save. Thanks!

\$\endgroup\$
2
  • \$\begingroup\$ Is id x not just x? Or how about [pred x..succ x]? \$\endgroup\$
    – xnor
    Jun 4, 2016 at 5:31
  • \$\begingroup\$ @xnor: I started with \x->map($x)[pred,id,succ], so the id was just a leftover. Of course .. beats it all. Thanks! \$\endgroup\$
    – nimi
    Jun 4, 2016 at 9:51
1
\$\begingroup\$

K (oK), 27 bytes

Solution:

2>|/x*x:-/(|/#:'x)$x@'<:'x:

Try it online!

Examples:

2>|/x*x:-/(|/#:'x)$x@'<:'x:("QQSQQRRQSTTUQQRRRS";"PQTTPPTTQTPQPPQRTP")
1
2>|/x*x:-/(|/#:'x)$x@'<:'x:("DEFGHIJKL";"HJLHMCHE")
0
2>|/x*x:-/(|/#:'x)$x@'<:'x:("AAA";"AAA")
1
2>|/x*x:-/(|/#:'x)$x@'<:'x:("AAA";"AA")
0

Explanation:

First sort each string, then pad to be the same length, then take one from the other (ASCII values of chars), square result as there is no built-in abs, take the maximum difference and check whether that is less than 2.

2>|/x*x:-/(|/#:'x)$x@'<:'x: / the solution
                         x: / save input to variable x
                      <:'   / ascending sorted indices (<:) for each (') list
                   x@'      / apply (@) each (') of these indices to the input (x)                             
          (      )$         / pad
             #:'x           / count (#:) each (') list (x)
           |/               / max (|) over (/) to get maximum
        -/                  / subtract (-) over (/) to take 2nd list from 1st
      x:                    / save in variable x
    x*                      / multiply by x (so square)
  |/                        / max over to get maximum distance
2>                          / is 2 greater than (>) to this maximum? returns 1 (true) or 0 (false)
\$\endgroup\$
0
\$\begingroup\$

C, 172 bytes

#define q(x)qsort(x,strlen(x),1,c)
c(x,y)char*x,*y;{return*x-*y;}main(a,v,w)char**v,*w,*a;{for(q(w=v[1]),q(a=v[2]);*w&&*a&&abs(*w-*a)<2;w++,a++);printf("%d",abs(*w-*a)<2);}

Test Cases

$ bash -x test.sh
+ bash -x test.sh
+ ./a.out A A
1+ ./a.out A B
1+ ./a.out C B
1+ ./a.out DD CE
1+ ./a.out DE FC
1+ ./a.out ABCD BCDE
1+ ./a.out AACC DBBB
1+ ./a.out DJENSKE FDJCLMT
1+ ./a.out DEFGHIJKL HJLEHMCHE
1+ ./a.out IKLIJJLIJKKL LJLJLJLJLJHI
1+ ./a.out ACEGIKMOQSUWY BLNPRDFTVHXJZ
1+ ./a.out QQSQQRRQSTTUQQRRRS PQTTPPTTQTPQPPQRTP
1+ ./a.out ELKNSDUUUELSKJFESD DKJELKNSUELSDUFEUS
1+ ./a.out A C
0+ ./a.out A Z
0+ ./a.out B J
0+ ./a.out JK J
0+ ./a.out CC BA
0+ ./a.out CE D
0+ ./a.out DJENSKE GDJCLMT
0+ ./a.out DEFGHIJKL HJLHMCHE
0+ ./a.out IJKLIJKLKIJL LIJLLHJLJLLL
0+ ./a.out AWSUKMEGICOQY RSHXBLJLNQDFZ
0+ ./a.out QQSQQRRQSTTUQQQRRS PQTTPPTTQTPQPPQRTT
0+ ./a.out ELKNSDUVWELSKJFESD DKJELKNSUELSDUFEUS
0++
\$\endgroup\$
0
\$\begingroup\$

PowerShell, 140 bytes

param($a,$b)(($a=[char[]]$a|sort).Count-eq($b=[char[]]$b|sort).Count)-and(($c=0..($a.Count-1)|%{+$a[$_]-$b[$_]}|sort)[0]-ge-1-and$c[-1]-le1)

Might be possible to get this shorter. It's not currently competitive with Python or JavaScript, but it uses a slightly different approach, so I figured I'd post it.

Explanation

This code is really confusing for someone not fluent in PowerShell, so I'll try to break it down into English as best I can...

We start with taking input param($a,$b) as normal.

The whole rest of the code is actually one statement, and can be broken as (...)-and(...) to test two Boolean statements with the -and operator.

The left-hand parens can be broken as (... -eq ...) to test equality of two objects. In this instance, the objects are the .Counts (that is, the length) of two new char-arrays. Each inner paren ($a=[char[]]$a|sort) takes the original input word, re-casts it as a char-array, then sorts it and re-saves back into the same variable. We do that for both $a and $b. The left-hand side thus verifies that the input words are the same length. If they are not the same length, this half of the outer Boolean statement will fail and False will be output.

Moving to the right-hand side, we're again testing two Boolean statements with (... -and ...). The left-hand side tests whether something is greater-than-or-equal-to negative 1 with -ge-1. The something is the zeroth-element of a constructed array $c, which is created by:

  • taking a range of the allowed indices 0..($a.count-1)
  • piped into a loop |%{...}
  • each iteration of the loop, we take the ASCII values of the indexed character in $a and subtract the ASCII value of the indexed character in $b
  • which is then |sorted by numerical value

The other side of the statement takes the maximal value $c[-1] of the array and ensures it's less-than-or-equal to 1 with -le1.

Thus, if the two input strings are indeed adjacent, the $c array will be something like @(-1,-1,-1...0,0,0...1,1,1). So the first element will be -1 and the last element will be 1. If they are not adjacent, the difference in ASCII values for a particular pair will either be < -1 or > 1, so this half of the outer Boolean test will fail, and False will be output.

Only if both sides pass will True be output, and the strings are therefore LA.

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

Pyth, 37 31 bytes

&qZ-FmldK.zqY-m.a-FdCmmCkSdK[Z1

Try it online with all test cases!

Shaved off 6 bytes by using the shortened reduce notation (-F instead of .U-bZ)

Solution inspired by Dennis

First submission to codegolf!

Explanation

We can split the expression in two parts, which are compared with & to output the result. I'll try to explain by writing some pseudo-Python

First we check that the length of the two words are the same

mldK.z         lengths = map(lambda d: len(d), K=all_input())
.U-bZmldK.z    diff = reduce(lambda b, Z: b - Z, lengths)
qZ.U-bZmldK.z  diff == 0

Then, we apply Dennis' method:

       K                                                      # ['CAT', 'SAD']
 m   SdK           sort = map(lambda d: sorted(d), K)         # ['ACT', 'ADS']
 mmCkSdK           ascii = map(lambda d: sorted(d), map(lambda k: ord(k), K))
                                                              # [[65, 67, 84], [65, 68, 83]]
CmmCkSdK           zipped = zip(*ascii)                       # [[65, 65], [67, 68], [84, 83]]
m.U-bZd CmmCkSdK   map(lambda d: d[0] - d[1], zipped)         # [0, -1, 1]
m.a.U-bZd CmmCkSdK map(lambda d: abs(d[0] - d[1]), zipped)    # [0, 1, 1] 

We then use the - operator to filter all elements of that list that are not in [Z1 ([0, 1]), and check that the result is an empty list with qY

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

Rust, 269 264 bytes

fn a(w:&str,x:&str)->bool{if w.len()==x.len(){return{let mut c:Vec<char>=w.chars().collect();let mut d:Vec<char>=x.chars().collect();c.sort();d.sort();for(e,f)in c.iter().zip(d.iter()){if(((*e as u8)as f64)-((*f as u8)as f64)).abs()>1f64{return false}}true}}false}

Expanded:

fn are_adjacent(w: &str, x: &str)->bool{

    if w.len() == x.len(){

        return {

            let mut c : Vec<char> = w.chars().collect();
            let mut d : Vec<char> = x.chars().collect();

            c.sort();
            d.sort();

            for (e,f) in c.iter().zip(d.iter()){
                if (((*e as u8) as f64) - ((*f as u8) as f64)).abs() > 1f64{
                    return false
                } 
            }

            true
        }
    }

    false
}

Test Cases:

fn main(){
    assert_eq!(true,are_adjacent("A","B"));
    assert_eq!(true,are_adjacent("A","B"));
    assert_eq!(true,are_adjacent("C","B"));
    assert_eq!(true,are_adjacent("DD","CE"));
    assert_eq!(true,are_adjacent("DE","FC"));
    assert_eq!(true,are_adjacent("ABCD","BCDE"));
    assert_eq!(true,are_adjacent("AACC","DBBB"));
    assert_eq!(true,are_adjacent("DJENSKE","FDJCLMT"));
    assert_eq!(true,are_adjacent("DEFGHIJKL","HJLEHMCHE"));
    assert_eq!(true,are_adjacent("IKLIJJLIJKKL","LJLJLJLJLJHI"));
    assert_eq!(true,are_adjacent("ACEGIKMOQSUWY","BLNPRDFTVHXJZ"));
    assert_eq!(true,are_adjacent("QQSQQRRQSTTUQQRRRS","PQTTPPTTQTPQPPQRTP"));
    assert_eq!(true,are_adjacent("ELKNSDUUUELSKJFESD","DKJELKNSUELSDUFEUS"));

    assert_eq!(false,are_adjacent("A","C"));
    assert_eq!(false,are_adjacent("A","Z"));
    assert_eq!(false,are_adjacent("B","J"));
    assert_eq!(false,are_adjacent("JK","J"));
    assert_eq!(false,are_adjacent("CC","BA"));
    assert_eq!(false,are_adjacent("CE","D"));
    assert_eq!(false,are_adjacent("DJENSKE","GDJCLMT"));
    assert_eq!(false,are_adjacent("DEFGHIJKL","HJLHMCHE"));
    assert_eq!(false,are_adjacent("IJKLIJKLKIJL","LIJLLHJLJLLL"));
    assert_eq!(false,are_adjacent("AWSUKMEGICOQY","RSHXBLJLNQDFZ"));
    assert_eq!(false,are_adjacent("QQSQQRRQSTTUQQQRRS","PQTTPPTTQTPQPPQRTT"));
    assert_eq!(false,are_adjacent("QQSQQRRQSTTUQQQRRS","PQTTPPTTQTPQPPQRTT"));
    assert_eq!(false,are_adjacent("ELKNSDUVWELSKJFESD","DKJELKNSUELSDUFEUS"));
}
\$\endgroup\$
0
\$\begingroup\$

APL, 59 bytes (characters)

(61 if we have to supply the { and }, 63 with f←)

I'm not the greatest APLer, but it's just too much fun.

(0=+/2≤|¨∊-/{⎕av⍳⍵}¨(⍺{⌈/⍴¨⍺⍵}⍵)⍴¨⍺[⍋⍺]⍵[⍋⍵])∧=/⍴¨∊¨⍺⍵

=/⍴¨∊¨⍺⍵ are the inputs equally long?

and all of the below

(⍺{⌈/⍴¨⍺⍵}⍵)⍴¨⍺[⍋⍺]⍵[⍋⍵] sort both inputs and shape them to be as long as the longest of the two (they wrap around if you make them longer than they are)

|¨∊-/{⎕av⍳⍵} convert both char vectors to int vectors of their ascii values, do a vector subtraction and absolute all values

0=+/2≤ sum up values larger than or equal to two and check if the result is equal to 0

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

J, 27 bytes

[:*/@(2>|)[:-/,:&(3&u:@/:~)

ungolfed

[: */@(2 > |) [: -/ ,:&(3&u:@/:~)

explained

  • &(3&u:@/:~) sorts both arguments, and converts to them to ascii numbers
  • ,: creates a 2 x n matrix, where n is the number of chars of the args
  • -/ subtracts one row from the other, giving a list of length n representing the distance of corresponding chars
  • (2>|) returns 1 if the absolute value of the distance is less than 2, 0 otherwise
  • */ multiplies all those 0s and 1s together: hence, the final result is 1 iff all pairs of corresponding chars are adjacent.

Try it online!

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