# AoCG2021 Day 7: Bathroom security goes wild

Part of Advent of Code Golf 2021 event. See the linked meta post for details.

The story continues from AoC2016 Day 2, Part 2.

You finally figure out the bathroom code (on the weird diamond-shaped keypad) and open the bathroom door. And then you see another door behind it, with yet another keypad design:

For those who can't see the image above:

+-----+-----+
|\    |    /|
| \ 1 | 2 / |
|  \  |  /  |
| 0 \ | / 3 |
|    \|/    |
+-----+-----+
|    /|\    |
| 7 / | \ 4 |
|  /  |  \  |
| / 6 | 5 \ |
|/    |    \|
+-----+-----+


You're given a list of UDLR strings. Each string corresponds to one button. You start at the previous button (or button 0 at the beginning) and move to the adjacent button for each instruction, and press whatever button you're on at the end of each string. U means to go up, D down, L left, and R right, respectively. If there's no adjacent button at the given direction, you simply don't move.

Additional clarifications for some diagonal edges: For example, if you're at button 0, both U (up) and R (right) correspond to moving to button 1. The full set of rules are:

0, U or R -> 1  |  1, L or D -> 0
2, D or R -> 3  |  3, L or U -> 2
5, U or R -> 4  |  4, L or D -> 5
7, D or R -> 6  |  6, L or U -> 7

1, R -> 2  |  2, L -> 1
3, D -> 4  |  4, U -> 3
5, L -> 6  |  6, R -> 5
7, U -> 0  |  0, D -> 7


Any combination that does not appear in the table above results in no movement, e.g. 1, U results in 1.

If the instructions read as ["ULL", "RRDDD", "LURDL", "UUUUD"], the code is as follows:

Start at 0, U: 1, L: 0, L: 0 (nowhere to move) -> 0
Start at 0, R: 1, R: 2, D: 3, D: 4, D: 5 -> 5
Start at 5, L: 6, U: 7, R: 6, D: 6, L: 7 -> 7
Start at 7, U: 0, U: 1, U: 1, U: 1, D: 0 -> 0


So the code is [0, 5, 7, 0].

Standard rules apply. The shortest code in bytes wins.

## Test cases

["ULL", "RRDDD", "LURDL", "UUUUD"] -> [0, 5, 7, 0]
["RRRR", "DLLUURR", "LDDRRUU"] -> [3, 2, 3]

• Could you consider include the description to the picture in plain text or simply include all possible instructions in the text? Pictures may be unavailable to some people. (For example, someone using device without proxy in certain country like me?)
– tsh
Commented Dec 7, 2021 at 1:39
• @tsh Ascii art version and all movement combinations added. Commented Dec 7, 2021 at 1:53
– tsh
Commented Dec 7, 2021 at 2:30
• Are we allowed to output the result with additional leading 0 for the starting position, as long as it's consistent for all outputs? Commented Dec 7, 2021 at 9:04
• @KevinCruijssen No. Commented Dec 7, 2021 at 9:08

# JavaScript (Node.js), 66 bytes

a=>a.map(c=>c.map(c=>n+=9-((n-'RDL'.search(c)*2)%8*.4|0))|n%8,n=8)


Try it online!

# Ruby, 91 76 74 bytes

->l{a=0;l.map{|x|x.bytes{|b|a+=321555525[z=a%8*4+b%5]-0xC45132A8[z]};a%8}}


Try it online!

### Notes:

• ASCII code of U L D R mod 5 is "0 1 3 2"
• 0x132A8C45 (or 321555525) is a bitmask: if the element in a*4+b%5 is 1, then the button number must be increased by 1. If we shift the bitmap 12 bits to the right, a matching bit means button number decreased by 1 (and then wrap around with mod 8)

# Charcoal, 38373634 33 bytes

≔⁰ηＦθ«Ｆι≧⁺⊖÷⊕×³﹪⁻⊕⊗﹪℅κ¹⁵η⁸¦⁸ηＩ﹪η⁸


Try it online! Link is to verbose version of code. Explanation: Now inspired by @alephalpha's answer.

≔⁰η


Start on button 0.

Ｆθ«


Loop through each string.

Ｆι


Loop through each character.

≧⁺⊖÷⊕×³﹪⁻⊕⊗﹪℅κ¹⁵η⁸¦⁸η


The ordinals of the characters DLUR modulo 15 are 8, 1, 10, 7. If you double this, add 1, subtract the button number, and reduce modulo 8, this results in a number which is less than 3 if the button should be decremented and greater than 4 if it should be incremented. The range 0..7 is converted into the range -1..1 by tripling it, incrementing it, integer dividing by 8, then decrementing it.

Ｉ﹪η⁸


Output the digit modulo 8. (This doesn't need to happen at the end of the previous step as there is already a modulo 8 operation in effect on its next use.)

# Pari/GP, 69 bytes

a->t=0;[[t=((t-i+=2)%8+3)*3\5+i|i<-Vec(Vecsmall(s))%15*2][#s]%8|s<-a]


Try it online!

Two observations:

• The ASCII code of DLUR is [68, 76, 85, 82], which becomes [8, 1, 10, 7] when modulus 15, which in turn becomes [0, 1, 2, 3] when modulus 4.
• Going to the right, [0, 1, 2, 3, 4, 5, 6, 7] becomes [1, 2, 3, 3, 4, 4, 5, 6], which is a part of OEIS sequence A057355: a(n) = floor(3*n/5). There are many other sequences on OEIS, but this one seems to be the simplest. If your language has a one-byte built-in for the golden ratio, you may also use the sequence A060143: a(n) = floor(n/φ).
• Nice. Which part of the code handles DLU mappings? Are you using separate formulas like the 3/5 one or somehow mapping the others to that based on the symmetries? Commented Dec 7, 2021 at 11:38
• @Jonah Based on symmetries. R is n -> floor(3*(n+3)/5), D is n -> (floor(3*((n-2)%8+3)/5)+2)%8, L is n -> (floor(3*((n-4)%8+3)/5)+4)%8, U is n -> (floor(3*((n-6)%8+3)/5)+6)%8. Commented Dec 7, 2021 at 11:49

# C, 126 bytes

f(s,n,c,l,z)char**s,*l;{z=48;for(c=0;c<n;){for(l=s[c++];*l;)z="10171020213322343545464577560766"[z*4-192+*l++%5];putchar(z);}}


Try it online!

Character ascii value modulo 5 yields:

U - 85%5 = 0
L - 76%5 = 1
R - 82%5 = 2
D - 68%5 = 3


In the string "10171020213322343545464577560766", each group of 4 characters corresponds to a key, and within such a group, the above numbers can index a specific character indicating the next key

Un-golfed:

//s: strings
//n: num strings
//c: string counter
//l: string character counter
//z: key number (as char)
f(s,n,c,l,z)
char**s,*l;
{
z=48;
for(c=0;c<n;){
for(l=s[c++];*l;)
z="10171020213322343545464577560766"[z*4-192+*l++%5];
putchar(z);
}
}

• Nice answer, you can get to 107 with a few golfs Commented Dec 7, 2021 at 14:58
• I've come up with a formula inspired by @alephalpha's answer for 86 bytes: Try it online!
– Neil
Commented Dec 7, 2021 at 15:09
• Nice one @Neil , if allowed it can drop another 3 Commented Dec 7, 2021 at 15:41

# Python 3.8 (pre-release), 115 bytes

Not even close to what tsh and alephalpha have created, but a nice straightforward python solution. I can save 5 bytes if I feed it bytes instead of str.

lambda l,y=0:[[[y:=[b'70345566',b'00125677',b'12334456',b'11233470'][ord(c)//7-9][y]-48for c in x],y][1]for x in l]


Try it online!

# 05AB1E, 32 30 bytes

ÎvyÇv•”^'ζ–$!ǝá₃º8˜•8ôy5%èsè}=  -2 bytes by using the modulo-5 trick from @GB's Ruby answer. Outputs newline delimited. (Could have been 1 byte less if we would have been allowed to output the results with additional leading 0 for the starting position by using a cumulative left-reduce.) Explanation: Î # Push 0 and the input-list vy # Pop and loop over each string of the input-list: Ç # Convert the current string to a list of codepoint-integers v # Loop over each of these integers y: •”^'ζ–$!ǝá₃º8˜•
'#   Push compressed integer 11223470001256771233445670345566
8ô       #   Split it into parts of size 8:
#    [11223470,"00125677",12334456,70345566]
y      #   Push the current codepoint y
5%    #   Modulo-5 ([0,1,2,3] for "ULRD")
è   #   Use it to 0-based index into the list
s  #   Swap to get the current value
è #   Use it to index into the integer, resulting in a digit
}           #  After the inner loop:
=          #  Print the intermediate result with newline (without popping)


See this 05AB1E tip of mine (How to compress large integers?) to understand why •”^'ζ–$!ǝá₃º8˜• is 11223470001256771233445670345566. • @GB points out that you can use mod 5 to save a byte. – Neil Commented Dec 7, 2021 at 9:53 • @Neil I had indeed noticed his answer and was working on it, but thanks for the notification. :) Commented Dec 7, 2021 at 10:06 # J, 69 61 bytes ([:+/\#&>){0(],((8|]+]{(3 2 3#-i:1)|.~2*[){:))/@|.@,'RULD'i.;  Try it online! • (3 2 3#-i:1) Generates the offsets for 'R': 1 1 1 0 0 _1 _1 _1  • |.~2*[ Rotate the required amount for ULD. • 0...@|.@,'RULD'i.; Prepare the boxed input for a single fold to calculate what we need: Flatten, append 0, reverse. • For the fold, we get the offset list based on step 1 above, index into that list using the current value (which starts at 0), add the result to the current value, and append the this new value to the running list. The current value is thus always the last item of the accumulator. • ([:+/\#&>){ All the above gives us one long list of every intermediate value. So we take the lengths of each instruction block, scan sum them, and use that to index into the master list. This returns the final answer. # Rust, 140 bytes |i:&[&str]|{let(mut o,mut n)=(vec![],0);for s in i{for c in s.bytes(){let k=|n|321555525>>n%8*4+c as i32%5&1;n+=k(n)-k(n+3)+8}o.push(n%8)}o}  Try it online! 321555525 encodes movement information in its bits, both for increasing and decreasing the number: + DRLU - 0 0101 5 1 0100 6 2 1100 7 3 1000 0 4 1010 1 5 0010 2 6 0011 3 7 0001 4  # Whitespace, 179 bytes [S S S N _Push_n=0][N S S N _Create_Label_OUTER_LOOP][N S S S N _Create_Label_INNER_LOOP][S N S _Duplicate_n][S N S _Duplicate_n][S N S _Duplicate_n][S N S _Duplicate_n][T N T S _Read_STDIN_as_char][T T T _Retrieve_input_char][S N S _Duplicate_input_char][S S S T S T S N _Push_10][T S S T _Subtract][N T S T N _If_0_Jump_to_Label_PRINT][S S S T T T T N _Push_15][T S T T _Modulo][S S S T S N _Push_2][T S S N _Multiply][S N T _Swap_top_two][T S S T _Subtract][S S S T N _Push_1][T S S S _Add][S S S T S S S N _Push_8][T S T T _Modulo][S S S T T N _Push_3][T S S N _Multiply][S S S T N _Push_1][T S S S _Add][S S S T S S S N _Push_8][T S T S _Integer_divide][S S S T N _Push_1][T S S T _Subtract][T S S S _Add][S S S T S S S N _Push_8][T S T T _Modulo][N S N S N _Jump_to_Label_INNER_LOOP][N S S T N _Create_Label_PRINT][S N N _Discard_duplicated_newline][T N S T _Print_n_as_integer_to_STDOUT][N S N N _Jump_to_Label_OUTER_LOOP]  Letters S (space), T (tab), and N (new-line) added as highlighting only. [..._some_action] added as explanation only. Whitespace doesn't have lists, so input-strings are newline delimiter, with additional trailing newline so we know we're done. Outputs the digits without delimiter. Try it online (with raw spaces, tabs and new-lines only). ### Explanation in pseudo-code: Just like my Java answer, this uses the formula of @Neil's Charcoal answer: $$a(n,c) = \left(n + \left\lfloor\frac{(((c\bmod{15})\times2-n+1)\bmod8)\times 3+1}{8}\right\rfloor-1\right)\bmod8$$ where $$\n\$$ is the previous digit, and $$\c\$$ is the codepoint of the current character. Integer n=0 OUTER_LOOP: INNER_LOOP: Integer c = STDIN as character If(n == '\n'): Jump to PRINT c = c modulo-15 c = c * 2 c = c - n c = c + 1 c = c modulo-8 c = c * 3 c = c + 1 c = c integer-divided by 8 c = c - 1 n = n + c n = n modulo-8 Jump to INNER_LOOP PRINT: Discard newline c Print n as integer to STDOUT Jump to OUTER_LOOP  # Python 3.8 (pre-release), 83 bytes lambda L,s=0:[[(s:=s-((2*"DRU".find(i)-~s&7)//3-1)%3+1&7)for i in l][-1]for l in L]  Try it online! To determine the effect (forward/backward/no movement) of an instruction, this uses a lookup on the instructions L,R,U,D to rotate the keys such that the three keys which allow backward movement come first, the three forwards next and the two no-movement keys last. The key index is then floor divided by 3 and the three possible outcomes 0,1,2 mapped to -1,1,0 # Java 10, 115 89 bytes m->{int n=0;for(var a:m){for(var c:a)n+=((c%15*2-n+9)%8*3+1)/8-1;System.out.print(n%8);}}  Input as an array of character-arrays; output to STDOUT without delimiter. -26 bytes porting @Neil's Charcoal formula: $$a(n,c) = \left(n + \left\lfloor\frac{(((c\bmod{15})\times2-n+9)\bmod8)\times 3+1}{8}\right\rfloor-1\right)\bmod8^{^{†}}$$ where $$\n\$$ is the previous digit, and $$\c\$$ is the codepoint of the current character. † The final modulo-8 could optionally be done later, which is what I do to save 2 bytes on parentheses. Try it online. Explanation: m->{ // Method with character-array parameter and no return int n=0; // Integer, starting at 0 for(var a:m){ // Loop over the character-arrays of the input: for(var c:a) // Inner-loop over the characters: n+= // Increase the integer by: ((c // The codepoint of the character %15 // modulo-15 *2 // doubled -n // minus the current value of the integer +9) // plus 9 %8 // modulo-8 *3 // tripled +1) // plus 1 /8 // integer-divided by 8 -1 // minus 1 System.out.print(n%8);}}// After the inner loop, output the integer modulo-8  # Perl 5, 84 bytes $p=($p+(UR,R,RD,D,DL,L,LU,U)[$p]=~/$_/-(D,LD,L,UL,U,RU,R,RD)[$p]=~/$_/)%8for@F;say$p


Try it online!

# TypeScript Types, 215 bytes

//@ts-ignore
type M<T,P=0,A=[]>=T extends${infer C}${infer T}?C extends" "?M<T,P,[...A,P]>:M<T,[[1,1,7,0],[1,2,0,0],[2,3,3,1],[2,3,4,2],[3,4,5,5],[4,4,5,6],[7,5,6,7],[0,6,6,7]][P][{U:0,R:1,D:2,L:3}[C]],A>:[...A,P]


Try It Online!

## Ungolfed / Explanation

// Lookup table; first index is original position, second is 0123 or URDL, and value is final position
type Lookup = [[1,1,7,0],[1,2,0,0],[2,3,3,1],[2,3,4,2],[3,4,5,5],[4,4,5,6],[7,5,6,7],[0,6,6,7]];

type Main<Input, Pos=0, Code=[]> =
// Get the first char of Input
Input extends ${infer Char}${infer Rest}
? Char extends " "
// If Char is a space, add this position to the code
? Main<Rest, Pos, [...Code, Pos]>
// Otherwise, consult the lookup table and continue
: Main<Rest, Lookup[Pos][{U:0,R:1,D:2,L:3}[Char]], Code>
// Input is empty return the code
: [...Code, Pos]


# Wolfram Language (Mathematica), 76 bytes

Map[t=0;((t=⌊.6Mod[t-#,8]+1.8⌋+#)&/@Mod[2LetterNumber@#+2,22];t~Mod~8)&]


Try it online!

A port of my PARI/GP answer.