| Bytes | Lang | Time | Link |
|---|---|---|---|
| 148 | Python 3.8 prerelease | 241216T034255Z | V_R |
| 014 | Jelly | 241129T135823Z | Jonathan |
| 092 | R | 241204T015329Z | Eonema |
| 022 | 05AB1E | 241128T101604Z | Kevin Cr |
| 016 | Nekomata | 241205T034859Z | alephalp |
| 116 | R | 241204T023158Z | Eonema |
| 156 | Python3 | 241128T153833Z | Ajax1234 |
| 038 | Charcoal | 241128T064452Z | Neil |
| 086 | JavaScript V8 | 241127T213129Z | Arnauld |
| 076 | JavaScript V8 | 241128T053927Z | l4m2 |
Python 3.8 (pre-release), 148 bytes
If we accept a comma-separated list of tuples as output, and not only a comma-separated list of strings:
import itertools as i
f=lambda n:[s for s in i.product(*["nsew"]*n)if not(-1 in(l:=[s[:x].count("n")-s[:x].count("s")for x in range(n+1)])or l[-1])]
Explanation
We first generate every possible tuple of length n consisting of one-character strings from "nsew":
[s for s in i.product(*["nsew"]*n)]
We check the number of "n" characters minus the number of "s" characters in each of s[:1], s[:2], ... , s[:n]:
l:=[s[:x].count("n")-s[:x].count("s")for x in range(n+1)]
l contains -1 at the first point where the number of south steps is greater than the number of north steps, if that ever happens. The final item in l is not 0 (i.e. it is True) if the number of north and south steps is unbalanced in the whole tuple. We check that neither of these conditions occurs:
(-1 not in l) and (not l[-1])
which is golfed slightly as:
not(-1 in l or l[-1])
Jelly, 16 15 14 bytes
4ṗµı*ÄḞoṂṪƊµÐḟ
A monadic Link that accepts a non-negative integer and yields a list of the walks as a list of lists of integers:
E 1
N 2
W 3
S 4
Try it online! Or see the test-suite (runs for [0..input]; reformats using ENWS and sorts walks).
How?
4ṗµı*ÄḞoṂṪƊµÐḟ - Link: WalkLength
4ṗ - four Cartesian power {WalkLength} -> PotentialWalks
µ µÐḟ - discard those PotentialWalks for which:
ı - i (square root of -1)
* - exponentiate {PotentialWalk} (vectorises) -> Directions
Ä - cumulative sums {Directions} -> Locations
Ɗ - last three links as a monad - f(Locations):
Ḟ - real part -> DistancesNorth
Ṃ - minimum {DistancesNorth} -> MinDistanceNorth
o - {DistancesNorth} logical OR {MinDistanceNorth} (vectorises)
Ṫ - tail
R, 121 116 92 bytes
-5 thanks to @pajonk:
- -3:
lapply->Map - -1:
\n-> literal newline - -1:
sum(w=="N")-sum(w=="S")->sum((w=="N")-(w=="S"))
Additional -24 thanks to @pajonk by using 0123 for NESW
f=\(n,w={}){q=sum(Re(1i^w))
if(!n&!q)cat(w,"
",sep="")
if(n&q>=0)Map(\(d)f(n-1,c(w,d)),0:3)}
Expanded:
# recursive function
f <- function(n, w=integer()) {
# calculate net N-S position: 1i^w converts to complex, Re takes
# N-S component
q <- sum(Re(1i^w))
# if at end of walk and at 0 N-S position
if(!n & !q)
# then print out the walk
cat(w,"\n",sep="")
# if not at end of walk and not in the ocean
if(n&q>=0)
# try walking in each direction (recursive case)
Map(
function(d) {
f(n - 1, c(w, d))
},
0:3
)
}
# recursive function:
f <- function(n, w={}) {
# net N-S position
q <- sum(w=="N")-sum(w=="S")
# if at end of walk and at 0 N-S position
if(!n & !q)
# then print out the walk
cat(w, "\n", sep="")
# if not at end of walk and not in the ocean
if(n & q >= 0)
# then for each direction
lapply(c("E","N","S","W"),
# try walking that way
function(d) f(n - 1, c(w, d))
)
}
05AB1E, 25 22 bytes
'€ÃIãʒ„ewмÇÈ·<ηO¤_sd`P
Outputs in lowercase.
Explanation:
'€Ã '# Push dictionary string "news"
Iã # Cartesian product with the input
ʒ # Filter this list by:
„ewм # Remove all "e"s and "w"
Ç # Convert the characters to codepoint-integers
È·< # 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)
_ # Check whether it equals 0
# (aka there are an equal amount of "n" and "s")
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
P # Take the product of the stack to verify all are 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".
Nekomata, 16 bytes
ᵐįŋᵖ{∫ŤlƆž≥}→ᵐɗH
Use ←, ∙, ÷, ¢ (characters code 12, 21, 10, 1 in Nekomata's custom encoding) to represent N, W, S, E respectively.
ᵐįŋᵖ{∫ŤlƆž≥}→ᵐɗH Take n=4 as an example
ᵐį Find an n-tuple of [0,1] and [1,0]
One possible result: [[0,1],[1,0],[1,0],[0,1]]
ŋ Optionally negate some elements
One possible result: [[0,1],[1,0],[-1,0],[0,-1]]
ᵖ{ } Check that:
∫ Cumulative sum
[[0,1],[1,0],[-1,0],[0,-1]] -> [[0,1],[1,1],[0,1],[0,0]]
Ť Transpose
[[0,1],[1,1],[0,1],[0,0]] -> [[0,1,0,0],[1,1,1,0]]
l Last element
[[0,1,0,0],[1,1,1,0]] -> [1,1,1,0]
Ɔ Split into the last element and the rest
[1,1,1,0] -> [1,1,1],0
ž Check that the last element is 0
[1,1,1],0 passes the check
≥ Check that every element in the rest is not less than the last element
[1,1,1],0 passes the check
So [[0,1],[1,0],[-1,0],[0,-1]] passes the check
→ Increment each element
[[0,1],[1,0],[-1,0],[0,-1]] -> [[1,2],[2,1],[0,1],[1,0]]
ᵐɗ Convert each element from decimal digits to a number
[[1,2],[2,1],[0,1],[1,0]] -> [12,21,1,10]
H Convert to characters
[12,21,1,10] -> "←∙¢÷"
By default, Nekomata outputs all valid solutions.
Or 11 bytes if we can output a list of [0,1],[0,-1],[1,0],[-1,0] instead of a string:
ᵐįŋᵖ{∫ŤlƆž≥
Another interesting approach is to find all strings of matching parentheses with length 2n+2, remove the first and last parentheses, and replace each pair of parentheses with a direction. I can't find a short way to do this in Nekomata, but this may be helpful for some other languages.
R, 121 116 bytes
-5 thanks to @pajonk:
- -3:
lapply->Map - -1:
\n-> literal newline - -1:
all(s>=0)&!s[n]->!any(s<0,s[n])
Without recursion this time. Funnily enough, it also ended up as 121 bytes.
\(n)Map(\(i,w=i%/%4^(1:n-1)%%4,s=cumsum(Re(1i^w)))if(!any(s<0,s[n]))cat(c("N","E","S","W")[w+1],"
",sep=""),1:4^n-1)
Try it online! (Note- TIO doesn't yet support \ for function.)
Expanded (before edits):
function(n) {
lapply(
# for all numbers 1 to 4^n
1:4^n-1,
function(
i,
# convert to base 4, as a numeric vector
w=i%/%4^(1:n-1)%%4,
# calculate the north-south position at each step
s=cumsum(Re(1i^w))
) {
# if always on land and ends up at the same point
if (all(s >= 0) & !s[n])
# lookup the letters for the directions, concatenate and print
cat(c("N","E","S","W")[w+1], "\n", sep="")
}
)
}
Python3, 156 bytes
C=str.count
def f(n):
q=['']
for i in q:
if len(i)==n:
if C(i,'N')==C(i,'S'):yield i
else:
for j in'NSEW':
if C(U:=i+j,'N')>=C(U,'S'):q+=[U]
Charcoal, 38 bytes
Nθ⊞υωFυ«≔⁼№ιN№ιSη¿‹LιθF✂SNWEη⊞υ⁺ικ¿η⟦ι
Try it online! Link is to verbose version of code. Explanation:
Nθ
Input n.
⊞υωFυ«
Start a breadth-first search for walks of length n.
≔⁼№ιN№ιSη
See if this walk ends at the seaside.
¿‹Lιθ
If this walk is not long enough, then...
F✂SNWEη
... for each valid next step...
⊞υ⁺ικ
... add that step to the walk and add that walk to the search list.
¿η⟦ι
Otherwise if the walk ends at the seaside then output that walk.
By comparison, generating all walks of length n and filtering out those that step into the sea or do not end up at the seaside takes 39 bytes even on ATO and technically does not generate the correct output for n=0 (it outputs nothing instead of a single empty string but you can't tell that the cursor is in the wrong place).
JavaScript (V8), 86 bytes
-4 thanks to @l4m2
n=>{for(i=4**n;i--;t||print(s))for(s=t="",j=n;j--;t-=t<0||~-q%2)s+="NESW"[q=i>>j*2&3]}
Commented
n => { // n = input
for( // outer loop:
i = 4 ** n; // start with i = 4 ** n
i--; // stop when i = 0
t || print(s) // if t = 0, print s
) //
for( // inner loop:
s = // s = Nice-walk string
t = "", // t = north/south counter
j = n; // start with j = n
j--; // stop when j = 0
t -= // update t:
t < 0 || // -1 if it's already negative
~-q % 2 // otherwise: +1 for north, -1 for south,
// unchanged for east and west
) //
s += "NESW"[ // update s:
q = i >> j * 2 // the character index q is obtained by
& 3 // extracting the next 2 bits from i
] // according to j
} //
JavaScript (V8), 76 bytes
f=(n,y=1,s='',i=2)=>y*n--?[...'ENWS'].map(c=>f(n,i--%2+y,s+c)):--y||print(s)