Proportion of self-avoiding walks on a square lattice
Haskell, 153 149 144 140 126 118 92 bytes
Here we represent the 2d coordinates as a single integer: We start at 0
, and the directions N,E,S,W
correspond to adding +n,+1,-n,-1
where n
is the input (we could also use any larger number). Using this we generate all possible paths, and then just check for duplicate numbers in those paths.
Thanks @H.PWiz for -26 bytes!
g n|a<-scanl(+)0<$>mapM(\_->[1,-1,n,-n])[1..n]=sum[1|x<-a,[b|b<-x,c<-x,b==c]==x]/sum[1|x<-a]
Try it online!
Explanation
--generate all possible paths
a<-scanl(+)0<$>mapM(\_->[1,-1,n,-n])[1..n]
--count the non-self intersecting paths, compute the ratio to the total
g n|a<- ... =sum[1|x<-a,[b|b<-x,c<-x,b==c]==x]/sum[1|x<-a]
Python 2, 89 bytes
f=lambda n,S=[0]:n>=len(S)and sum(f(n,S+[S[-1]+d])for d in[-n,-1,1,n])/4.or len(set(S))>n
Try it online!
A recursive approach inspired by flawr's lovely Haskell answer. Outputs a float.
Jelly, 15 12 bytes
‘ı×Ƭ¤ṗÄQƑ€Æm
Try it online!
A monadic link taking N
as its argument and returning a float representing the proportion of non-self-intersecting walks of length N
. Generates all walks of that length and then checks for intersections, using complex numbers to represent the 2D coordinates.
Thanks to @LuisMendo for saving a byte, and @Mr.XCoder for saving 2 more!
Explanation
‘ | Increment by 1
¤ | Following as a nilad
ı | - 1i
×Ƭ | - Multiply (by 1i) until no new values, returning all intermediate values
ṗ | Cartesian power (with N+1)
Ä | Cumulative sums of innermost lists
QƑ€ | Check whether each list is invariant when uniquified
Æm | Arithmetic mean