g | x | w | all
Bytes Lang Time Link
044Uiua241229T175801Zlolad
074Wolfram Language Mathematica241220T092939Zatt
176Wolfram Language Mathematica241219T151623ZIntroduc
1926Jelly241206T074200ZJonathan
nanPython241205T090829Z138 Aspe
101Ruby241205T101649ZDoorknob
106Python 3241205T100906Ztsh
089JavaScript V8241205T081953Zl4m2
03305AB1E241205T080054ZKevin Cr
100APL+WIN241205T085408ZGraham
046Charcoal241204T234459ZNeil

Uiua, 45 44 bytes

▽⤚≡⌟(××>₀⊣:/×⊸≥₀\+:=₀/+∩-°⊟₄≡=¤)⊸⧅⋅⋅1:"WESN"

Pad

Edit: shaved off a byte using experimental sided subscripts.

Explanation

Take all k-permutations of the directions, then test if they are valid: they should have equal numbers of W and E; at any time have >= counts of N to S as well as > counts at the end.

▽⤚≡⌟(××>₀⊣:/×⊸≥₀\+:=₀/+∩-°⊟₄≡=¤)⊸⧅⋅⋅1:"WESN"
                                 ⧅⋅⋅1:"WESN"   # generate all k-perms
▽⤚≡⌟(                           )              # filter by
                            ≡=¤                # compare string to each direction
                       ∩-°⊟₄                   # for each char, E-W and N-S
     ××                                        # valid iff:
                   =₀/+                        # - overall E-W = 0
           /×⊸≥₀\+:                            # - at each step, N-S >= 0
       >₀⊣:                                    # - at last step, N-S > 0
    

Wolfram Language (Mathematica), 74 bytes

{E,S,W,N}[[#]]&/@Select[Range@4~Tuples~#,Tr[I^#]>0Re@Accumulate[I^#]&]&

Try it online!

Returns a list of lists containing {E,S,W,N}. For output without delimiters, prepend Print@@ (+7 bytes): Try it online!.

is \[VectorLessEqual].

       Range@4~Tuples~#                                 paths of given length
Select[                ,                            &]  filter by:
                                0Re@Accumulate[I^#]      path stays in the right half-plane
                        Tr[I^#]>0                         path ends directly right of start
{E,S,W,N}[[#]]&/@ %                                     translate to letters

x>0 is only True if x is a noncomplex, positive value, and remains unevaluated otherwise (non-True values are falsy).

Wolfram Language (Mathematica), 176 bytes

f[n_]:=(s={"N","S","E","W"}~Tuples~n;StringJoin/@Pick[s,#[[-1]][[1]]==0&&#[[-1]][[2]]>0&&Min[#[[All,2]]]>=0&/@Accumulate/@(s/.{"N"->{0,1},"S"->{0,-1},"E"->{1,0},"W"->{-1,0}})])

Try it online!

Explanation

Create all possible paths with Tuples then convert them into a coordinate system. Use Pick with the three restricitons imposed (finish vertically above,finish above the starting point, do not ever go below the starting point) to select the allowed paths. Finally convert into a concatenated string.

Jelly, (19?) 26 bytes

19 bytes using the integers \$[1,4]\$ as the directions WSEN, respectively.

4ṗµı*ÄḞAƑa$aĊ¬$ƲṪµƇị“WSEN”

A monadic Link that accepts an integer and yields a list of lists of characters.

Try it online! Or see the test-suite.

How?

4ṗµı*ÄḞAƑa$aĊ¬$ƲṪµƇị“WSEN” - Link: integer, Steps
4ṗ                         - [1..4] Cartesian power {Steps}
                             -> all lists of [1..4] of length Steps
  µ              µƇ        - keep those Potentials for which:
   ı*                      -   -1 exponentiate {Potential} (vectorises)
     Ä                     -   cumulative sums -> "Stops" (Gaussian integers)
               Ʋ           -   last four links as a monad - f(Stops):
      Ḟ                    -     Real parts {Stops} -> "Heights"
          $                -     last two links as a monad - f(Heights):
        Ƒ                  -       is invariant under?:
       A                   -         absolute values
         a                 -       logical AND {Heights} (vectorises)
                                   -> "HeightsOrZeros" (Zeros if went below start)
              $            -     last two links as a monad - f(Stops):
            Ċ              -       imaginary parts {Stops} -> "Laterals"
             ¬             -       logical NOT (vectorises) -> isCentredForEach
           a               -     {HeightsOrZeros} logical AND {isCentredForEach} (vectorises)
                Ṫ          -   tail
                   ị“WSEN” - index into "WSEN" (vectorises)

Python, 259 96 bytes

Python port of @l4m2's JavaScript answer.

Saved 163 bytes thanks to @Unrelated String


Golfed version. Attempt This Online!

def g(z,v=1,h=0,c='',d=2):
 for x in'ENWS'*(z>(1>h==z!=print(c))):d-=1;g(z-1,v+d%2,h+~d%2,c+x,d)

Ungolfed version. Attempt This Online!

# Counter for tracking printed paths
cnt = 0

# Function to print path and increment counter
def print_path(path):
    global cnt
    cnt += 1
    print(path, cnt)

# Main recursive function to find valid paths
def find_paths(length, vertical_pos=1, horizontal_pos=0, current_path='', direction=2):
    global cnt
    # Base case: if we've used all steps
    if vertical_pos * length == 0:
        # Only print if we're at position (2, 0)
        if vertical_pos > 1 and horizontal_pos == 0:
            print_path(current_path)
        return

    # Try all four directions: East, North, West, South
    for dir in ['E', 'N', 'W', 'S']:
        # Calculate new positions based on direction
        new_direction = direction - 1
        direction-=1
        new_vertical_move = 1 if new_direction % 2 else 0  # 1 for N/S
        new_horizontal_move = 0 if new_direction % 2 else 1  # 1 for E/W

        # Recursive call with updated positions
        find_paths(
            length - 1,                         # Decrease remaining steps
            new_vertical_move + vertical_pos,   # New vertical position
            new_horizontal_move + horizontal_pos,  # New horizontal position
            current_path + dir,                 # Add direction to path
            new_direction                       # Update direction counter
        )

# Start the path finding with length 4
find_paths(4)

Ruby, 101 bytes

->n{((a=?E*-~n)..?E+a).map{|x|x[0,n]if/^((N\g<1>S?|E*W*)+)(?<=S)$/=~x&&x.count(?W)==x.count(?E)}-[p]}

This is very slow, but it manages to finish for n=4 eventually on my machine. Try it for n=3 (it times out for n=4, lol)

Whoever said regex can't find matching parentheses? :D

Explanation:

A bonus solution, which I think is super slick but is sadly much longer:

->n{(i=4**n).upto(2*i){puts$&.chop.tr'0-3','NSEW'if/^((0\g<1>1?|2*3*)+)$/=~_1.digits(4)*''&&$&.count(?2)==$&.count(?3)}}

Python 3, 106 bytes

f=lambda n,N=0,E=0,*p:sum([f(n-1,i%2*i+N,~i%2*~-i+E,*p,'WNES'[i])for i in[-1,0,1,2]if~N*n],(1>E==n<N)*[p])

Try it online!

JavaScript (V8), 89 bytes

f=(n,y=1,x=0,s='',i=2)=>y*n--?[...'ENWS'].map(c=>f(n,i--%2+y,i%2+x,s+c)):y>1&!x&&print(s)

Try it online!

From my Nice

88 by returning

05AB1E, 35 33 bytes

'€Ã©Iãʒ®À2ôδÃÇ`È·<ηO¤0›sd`r6b-O_P

Based on my answer for the Walks in Nice (Nizza) challenge. The difference is that the _ (==0, aka no vertical change) is replaced with 0› (>0, aka climbed), and a horizontal filter is added (6b-O_, aka not wondered east/west, but went straight up).

Try it online.

Explanation:

'€Ã                  '# Push dictionary string "news"
   ©                  # Store it in variable `®` (without popping)
    Iã                # Cartesian product with the input
      ʒ               # Filter this list by:
       ®À2ôδà         #  Split the "ew" and "sn" in loose groups:
       ®À             #   Push "news" from `®`, and rotate it once: "ewsn"
         2ô           #   Split into pairs: ["ew","sn"]
           δ          #   Using the current string and this pair as arguments:
            Ã         #    Keep only those characters
       Ç              #  Convert it to a pair of codepoint-integer lists
        `             #  Pop and push both lists separately to the stack
         È·<          #  IsEven *2 -1 (North is now 1; South is -1)
            η         #  Get the prefixes
             O        #  Sum each prefix
              ¤       #  Get the last sum (without popping the list)
               0›     #  Check whether it's positive (>0)
                      #  (aka, there are more "n" than "s" and we've climbed)
                 s    #  Swap to get the list of cumulative sums again
                  d   #  Check for each whether it's non-negative (>=0)
                      #  (aka for every "s" there should have been at least one
                      #  preceding "n")
                   `  #  Dump all those >=0 checks to the stack
        r             #  Reverse the stack
         6b           #  Push 6, and convert it to binary: 110
           -          #  Subtract (East is now -9; West is 9)
            O         #  Sum them together
             _        #  Check that this sum is 0
                      #  (aka, an equal amount of "e" and "w")
        P             #  Check if everything on the stack is truthy
                      # (after which the filtered list is output implicitly)

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why '€Ã is "news".

APL+WIN, 100 bytes

Prompts for n

(0=↑¨m='s')/m←((+/¨m='s')<+/¨m='n')/m←((+/¨m='e')=+/¨m='w')/m←,⍎∊((¯1+⎕)⍴⊂'''nsew''∘.,'),⊂'''nsew'''

Try it online! Thanks to Dyalog Classic

Charcoal, 46 bytes

Nθ⊞υωFυ«≔⁼№ιN№ιSη¿‹LιθF✂SNWEη⊞υ⁺ικ¿›⁼№ιW№ιEη⟦ι

Try it online! Link to verbose version of code. Explanation: Based on my answer to Walks in Nice (Nizza) but instead of printing walks whose vertical distance is zero prints walks whose vertical distance is not zero but whose horizontal distance is zero.