g | x | w | all
Bytes Lang Time Link
036Uiua241020T180854Znyxbird
02005AB1E191030T162107ZGrimmy
048Charcoal191025T231418ZNeil
135C gcc191025T203312ZG. Sliep
041J191026T050137ZJonah
126Python 3191025T214548ZKateba
020Jelly191025T194433ZNick Ken
032K ngn/k191025T142155Zngn
102JavaScript Node.js191025T143811ZArnauld

Uiua, 36 bytes

/◇⊂⍚(⊂:4▽:⍜⊣+₂⊃>₀⌵)-⊸⬚0↻¯1⌊⍉⊟⊃÷◿:-@a

Try it!

/◇⊂⍚(⊂:4▽:⍜⊣+₂⊃>₀⌵)-⊸⬚0↻¯1⌊⍉⊟⊃÷◿:-@a
                                      -@a # convert a-z -> 0-25
                              ⌊⍉⊟⊃÷◿:    # get the floored divmod
                      -⊸⬚0↻¯1            # get the pairwise deltas (starting at (0, 0))
    ⍚(              )                    # for each delta
                ⊃>₀⌵                     # get the direction (>0:1/<=0:0) and the absolute value
            ⍜⊣+₂                         # add two to the x coordinate's direction (U/D->L/R)
          ▽:                              # replicate the direction by the absolute value
      ⊂:4                                # append 4
/◇⊂                                      # conjoin each row

Outputs as an array with 0-4 for , , , , and !, respectively.

05AB1E, 20 bytes

AIk0šI‰ü-εεdDNOyÄ×]»

Try it online!

Uses 0 for D, 1 for R, 2 for U, 3 for L, and newline for !. Space is used as an optional separator.

Charcoal, 52 48 bytes

Nθ≔⁰δFES⌕βι«≔⁻﹪ιθ﹪δθη≔⁻÷ιθ÷δθζF±ηLF±ζUFηRFζD≔ιδ!

Try it online! Link is to verbose version of code. Edit: Saved 4 bytes by only tracking the alphabet index rather than the row and column separately. Takes input as X first, then the word. Explanation:

Nθ

Input X.

≔⁰δ

Start the path at the a with index 0.

FES⌕βι«

Input the word, convert its letters to their alphabet index and loop over them.

≔⁻﹪ιθ﹪δθη

Calculate the horizontal difference.

≔⁻÷ιθ÷δθζ

Calculate the vertical difference.

F±ηLF±ζUFηRFζD

Turn those differences into a path.

≔ιδ

Update the current index.

!

Select the current letter.

The reverse program is only 23 bytes:

NθP⪫⪪βθ¶FS≡ι!⊞υKKM✳ι⎚↑υ

Try it online! Link is to verbose version of code. Explanation:

Nθ

Input X.

P⪫⪪βθ¶

Split the lowercase alphabet into substrings of length X and print them on separate lines without moving the cursor.

FS

Loop over the command characters.

≡ι!

If the next character is a !...

⊞υKK

... then save the letter under the cursor in a list...

M✳ι

... otherwise move in the direction given by that character.

⎚↑υ

Remove the alphabet and output the saved letters.

C (gcc), 165 164 140 138 137 135 bytes

#define W(b,c);for(;X b;putchar(c))
x,y,X;f(s,w)char*s;{x=y=0 W(=*s++,33){X-=97 W(%w<x,76)x--W(%w>x,82)x++W(/w<y,85)y--W(/w>y,68)y++;}}

Try it online!

1 25 27 28 byte shaved off thanks to ceilingcat! Ungolfed:

int x, y, X, Y;

f(char *s, int w) {
   x = 0;                                 // Starting position is (0, 0)
   y = 0;

    while (*s) {                          // For each character
        X = (*s - 'a') % w;               // Get its x coordinate
        Y = (*s - 'a') / w;               // Get its y coordinate
        s++;

        while (X > x) putchar('R'), x++;  // Print R for each step we need to move right
        while (X < x) putchar('L'), x--;  // ...et cetera...
        while (Y > y) putchar('D'), y++;
        while (Y < y) putchar('U'), y--;

        putchar('!');                     // We are there, print !
    }
}

J, 44 41 bytes

;@(2<@(_,~[:I.0>.-,-~)/\0,]#:~_,[)97|3&u:

Try it online!

All credit to ngn for the best part: the self-append of the negative delta and max with 0, as a way of creating unique markers for each direction.

Separately, -3 bytes thanks to ngn for some line edits

2 = D, 3 = R, 0 = U, 1 = L, _ = select

Python 3, 126 bytes

lambda s,n:[abs(x//n-y//n)*'UD'[y>x]+abs(x%n-y%n)*'LR'[y%n>x%n]+'!'for x,y in zip(map(O,'a'+s),map(O,s))]
O=lambda c:ord(c)-97

Try it online!

Jelly, 24 20 bytes

O_97ŻdZIb1Ḥ2¦Z;€3Fḟ0

Try it online!

A dyadic link taking the word as the left argument and the width as the right. Returns a list of integers where:

-2 = L
-1 = U
 1 = R
 2 = D
 3 = Select

K (ngn/k), 41 32 bytes

{,/(|4,&0|,/-:\)'-':+(0,y)\x-97}

Try it online!

output: 0=D 1=R 2=U 3=L 4=!

{ } function with arguments x and y

x-97 convert "a".."z" to 0..25

(0,y)\ divmod by y, returns a pair of lists - one with the quotients and one with the remainders

+ flip - make it a list of pairs

-': deltas - subtract each pair from the previous one; use 0 0 as an implicit pair before the first

( )' for each pair (let's call it (Δi;Δj)) do:

,/ concatenate

JavaScript (Node.js),  112 ... 104  102 bytes

Takes input as (width)(word), where word is expected in lowercase. Returns 01234 for RLDU!.

n=>w=>Buffer(w).map(g=c=>v-(c%=97)?g(c,v-=[-1,1,-n,n][d=(v-c)%n?v%n>c%n&1:v>c|2],o+=d):o+=4,o=v='')&&o

Try it online!