My first attempt at one of these coding challenge things!
I'm not great with maths, but I'm guessing that all walks must have an even length, otherwise you can't end up back at your starting location, you'd always be one away...
If that assumption is true, then I think this works:
Basically, for each "pair" of blocks you want to walk, either add ["n", "s"] or ["e", "w"] to an array, then flatten and shuffle! Because you're always adding both a movement and it's inverse, you'll always end up where you started!
Ruby's proc / block thing still confuses me a little so I'm not sure if this is the most elegant one-liner (excluding checking for even walk length), but ayy it works!
defgenWalklengthraise"Walk length must be even!"iflength%2!=0(length/2).times.collect(&Proc.new{[%w(n s),%w(e w)].sample}).flatten.shuffleendgenWalk10# -> ["n", "w", "n", "e", "w", "s", "e", "w", "e", "s"]
Full stack web dev.
Studying FP web development approaches, while helping Mission Bit create paths to programming for underserved public school kids.
Previously @ Gradescope.
Experienced Microsoft 365 pro and Microsoft MVP. Skilled in pre-sales, team management, and global projects. Passionate about innovative solutions. Newsletter author.
Location
Spain
Work
Digital Workplace Architect (EMEA) — IT Consultant
functiongetWalkSteps(walkTime){if(walkTime%2>0){thrownewError('You cannot come back');}constdistance=walkTime/2;constx=Math.floor(Math.random(distance)*distance);consty=distance-x;returnnewArray(walkTime).fill('e',0,x).fill('n',x,x+y).fill('w',x+y,x+y+x).fill('s',x+y+x,x+y+x+y);}
def get_walk(minutes):
if minutes % 2 != 0:
# Only even minute times are possible, as you always need to walk the same distance east as west,
# andnortha s sound.
raise ValueError("Only walks with an even number of minutes are possible")
half = minutes / 2
return half * ['n'] + half * ['s']
If you add the requirement that you can't walk the same street twice...
def get_walk(minutes):
if minutes % 2 != 0:
# Only even minute times are possible, as you always need to walk the same distance east as west,
# andnortha s sound.
raise ValueError("Only walks with an even number of minutes are possible")
# We'll return a rectangle with width 1, so the two short sides combined take 2 minutes
# We'll divide the remaining minutes by 2 to know how long the other sides should be.
length = (minutes - 2) / 2
return ['n'] + length * ['e'] + ['s'] + length * ['w']
constcreateRandomPath=minutes=>{letpath=[];// if the minutes are even, calculate pathif(minutes%2===0){// populate the array from opposite ends with complementary valuesfor(letx=0;x<minutes/2;x++){constletter=Math.floor(Math.random()*4);path[x]="nsew".charAt(letter);path[minutes-x-1]="snwe".charAt(letter);}// randomize pathpath.sort((a,b)=>Math.floor(Math.random()*2)?1:-1);}// return the generated array or an empty array if steps are oddreturnpath;}
And a one-liner but not really randomized, just going north-then-south:
functiongo_for_a_walk(int$distance){if($distance%2==1){thrownewException("There's no place like home. Unfortunately, you won't return home with an odd number of steps.");}$steps=[];$directions=['n','e','s','w'];while($distance>0){$index=array_rand($directions);$steps[]=$directions[$index];$steps[]=$directions[($index+2)%4];$distance-=2;}shuffle($steps);return$steps;}echoimplode(', ',go_for_a_walk(10)).PHP_EOL;
#!/bin/bashdeclare gps=(n s e w);if[[$((${1}%2))= 0 ]];then
for(( i =${1}; i >= 0; i-=2 ));do
echo${gps[$(($RANDOM%3))]};done;else
echo"Sorry, you cannot generate way";fi
// in general we will create a sequence which just retraces itself after a certain time.functiongenerateWalkSequence(time){if(time%2!=0)thrownewError('Time must be even');letwalkSequence=[];letoppositeDirections=[];letnextDirection='n';constdirections=[...'nswe'];for(leti=0;i<time/2;i++){// loop selection after index 3walkSequence[i]=(nextDirection=directions[i%4]);oppositeDirections[i]=(getComplement(nextDirection));}return[...walkSequence,...oppositeDirections.reverse()];}functiongetComplement(direction){switch(direction){case'n':return's';case's':return'n';case'e':return'w';case'w':return'e';}}
During my reflexion about this challenge, I figured out that if input is an odd number, you will never be able to go back at your start position.
Here my JS implementation:
functiondirection(time){if(time%2>0){throw'You will never go back!!';}constahead=Math.ceil(time/4),turn=Math.floor(time/4);return('n'.repeat(ahead)+'w'.repeat(turn)+'s'.repeat(ahead)+'e'.repeat(turn)).split('');}// let's test ittry{console.log(direction(4));// print ["n", "w", "s", "e"]}catch(e){console.log(e);}try{console.log(direction(1));}catch(e){console.log(e);// You will never go back!!}try{console.log(direction(3));}catch(e){console.log(e);// You will never go back!!}
Full stack web dev.
Studying FP web development approaches, while helping Mission Bit create paths to programming for underserved public school kids.
Previously @ Gradescope.
I took a bit of a different route! @spaciecat killed the simple algorithm answer so I wanted to do something different!
I decided to make a program that lets the user build the path they want to take! Cause why not let the User choose where to explore! I might clean this up and turn it into a full post sometime soon!
Here is a really quick demo GIF
usestd::fmt;usestd::io;usestd::io::prelude::*;fnparse_time_of_walk(user_input:&str)->Result<u32,&'staticstr>{letparsed_input_result:Result<u32,_>=user_input.parse();matchparsed_input_result{Ok(i)=>{ifi%2==0{Ok(i)}else{Err("Walk time must be an even number or we will not be able to get back to where we started")}}Err(_)=>Err("Could not parse the walk time"),}}#[derive(Debug,PartialEq,Clone)]enumDirection{North,South,East,West,}implDirection{fnwill_take_me_home(&self,current_position:(i32,i32))->bool{matchself{Direction::North=>current_position.1<0,Direction::South=>current_position.1>0,Direction::East=>current_position.0<0,Direction::West=>current_position.0>0,}}fnto_str(&self)->&'staticstr{matchself{Direction::North=>"North",Direction::South=>"South",Direction::East=>"East",Direction::West=>"West",}}fndirection_diff(&self)->(i32,i32){matchself{Direction::North=>(0,1),Direction::South=>(0,-1),Direction::East=>(1,0),Direction::West=>(-1,0),}}}implfmt::DisplayforDirection{fnfmt(&self,f:&mutfmt::Formatter)->fmt::Result{matchself{Direction::North=>write!(f,"North"),Direction::South=>write!(f,"South"),Direction::East=>write!(f,"East"),Direction::West=>write!(f,"West"),}}}fnoptions_availible(current_position:(i32,i32),minutes_left:u32)->Option<Vec<Direction>>{ifcurrent_position==(0,0)&&minutes_left==0{returnSome(vec![]);}letdistance_from_origin=current_position.0.abs()+current_position.1.abs();ifdistance_from_origin>minutes_leftasi32{None}else{letall_options:Vec<Direction>=vec![Direction::North,Direction::South,Direction::East,Direction::West,];letcan_take_detour=distance_from_origin<minutes_leftasi32;letoptions=all_options.iter().filter(|direction|direction.will_take_me_home(current_position)||can_take_detour).cloned().collect();Some(options)}}fnchosen_direction(input:&str)->Option<Direction>{letlower=input.to_ascii_lowercase();iflower.starts_with("n"){Some(Direction::North)}elseiflower.starts_with("e"){Some(Direction::East)}elseiflower.starts_with("w"){Some(Direction::West)}elseiflower.starts_with("s"){Some(Direction::South)}else{None}}fndirections_to_string(path:&Vec<Direction>)->String{path.iter().map(Direction::to_str).collect::<Vec<_>>().join(", ")}fnmain()->Result<(),&'staticstr>{println!("Hey I heard you want to take a walk!");println!("How long (in minutes) should we walk for?");letstdin=io::stdin();letmutstdin_lines=stdin.lock().lines();letuser_input_minutes=stdin_lines.next().unwrap().unwrap();letmutminutes_left=parse_time_of_walk(&user_input_minutes)?;letmutcurrent_position=(0,0);letmutpath:Vec<Direction>=vec![];letmutoptions=options_availible(current_position,minutes_left);whileminutes_left>0&&options.is_some(){letunwrapped_options=options.unwrap();println!("\nYou have {} minutes left",minutes_left);println!("Which direction would you like to go?");println!("So far you'r path has been: {}",directions_to_string(&path));println!("Your current options are: {}",directions_to_string(&unwrapped_options));letmutchosen_direction_option=chosen_direction(&stdin_lines.next().unwrap().unwrap());whilechosen_direction_option.is_none(){chosen_direction_option=chosen_direction(&stdin_lines.next().unwrap().unwrap());}letchosen_direction=chosen_direction_option.unwrap();println!("You chose: {}",chosen_direction);current_position.0+=chosen_direction.direction_diff().0;current_position.1+=chosen_direction.direction_diff().1;path.push(chosen_direction);minutes_left-=1;options=options_availible(current_position,minutes_left);}ifminutes_left==0{println!("YAY we made it! Here is the path we took: {}",directions_to_string(&path));}elseifoptions.is_none(){println!("OH NO! We won't be able to make it back in time! Try another path.");println!("Here is what you tried this time: {}",directions_to_string(&path));}Ok(())}#[cfg(test)]modtests{usecrate::*;#[test]fnparse_time_of_walk_test(){assert_eq!(parse_time_of_walk("3"),Err("Walk time must be an even number or we will not be able to get back to where we started"));assert_eq!(parse_time_of_walk("five"),Err("Could not parse the walk time"));assert_eq!(parse_time_of_walk("4"),Ok(4));}#[test]fntest_all_options_availible(){letoutput=options_availible((0,0),10);letall_options=vec![Direction::North,Direction::South,Direction::East,Direction::West,];assert_eq!(output,Some(all_options));}#[test]fntest_impossible_options(){assert_eq!(options_availible((0,-10),1),None);assert_eq!(options_availible((1,10),10),None);assert_eq!(options_availible((-1,10),10),None);}#[test]fntest_already_at_origin_and_no_minutes_left(){assert_eq!(options_availible((0,0),0),Some(vec![]));}#[test]fntest_north_only_option(){letoutput=options_availible((0,-1),1);assert_eq!(output,Some(vec![Direction::North]));}}
I'm a software engineer working as a full-stack developer using JavaScript, Node.js, and React. I write about my experiences in tech, tutorials, and share helpful hints.
My approach was to depart in some random direction, duplicate that initial set of directions, reverse each individual direction within that copy (north goes to south, etc.), then reverse that entire copy to return to the starting point.
/**
* Generate directions for a walk on a grid that returns to its origin point where one block takes one minute.
*/functiongenerateWalk(timeInMinutes){constmidpoint=Math.trunc(timeInMinutes/2)constcompass=['n','e','s','w']letdepartureDirections=[]letreturnDirections=[]for(leti=0;i<midpoint;i++){// For the first half of the walk, generate random directions.departureDirections[i]=compass[Math.floor(Math.random()*Math.floor(compass.length))]// If the direction's index is less than 2 (north, east), shift forward two directions to its reverse direction. Otherwise if it is greater than 2 (south, west), shift it backward two directions to its reverse direction.if(compass.indexOf(departureDirections[i])<2){returnDirections[i]=compass[compass.indexOf(departureDirections[i])+2]}else{returnDirections[i]=compass[compass.indexOf(departureDirections[i])-2]}}// Reverse the return directions in order to return to the starting point.returnDirections.reverse()// Concatenate the departure array with the return array to get the full directions.returndepartureDirections.concat(returnDirections)}
The part I had trouble with was swapping each individual direction. I stored my directions in an array that follows a compass because I figured that the reverse direction is always two away: north's array position + 2 = south, east + 2 = west. I ran into some trouble shifting the directions because I could not add two in all cases because it would go outside of the array bounds, so I put in the if-statement. I'm not sure if there is a way to "wrap" an array in JavaScript without going out of the array bounds. I believe in Python this can be done with the slice notation (double colon syntax). If anyone has a tip for JavaScript, feel free to share.
Full stack web dev.
Studying FP web development approaches, while helping Mission Bit create paths to programming for underserved public school kids.
Previously @ Gradescope.
funcgenerateMinutesWalk(minutes:Int)->[String]?{guardminutes%2==0else{print("Minutes is odd")returnnil}letcoordinates=["N","O","S","E"]vartravel=[String]()for_in0..<minutes/2{travel.append(coordinates[Int.random(in:0..<coordinates.count)])}travel.forEach{valueinifletindex=coordinates.firstIndex(of:value){travel.append(coordinates[(index+2)%coordinates.count])}}returntravel}
typePersonPositionstruct{xAxisintyAxisint}funcGenerateWalk(minutesint)([]string,error){personPosition:=PersonPosition{0,0}varwalkingRoute[]stringifminutes%2!=0{returnwalkingRoute,errors.New("Minutes must be even number, otherwise you can't end on starting point")}rand.Seed(time.Now().UnixNano())directions:=[]string{"n","s","e","w"}fori:=0;i<minutes;i++{personYAxis:=personPosition.yAxispersonXAxis:=personPosition.xAxisdistanceFromHome:=abs(personYAxis)+abs(personXAxis)timeToGoHome:=minutes-iifpersonYAxis>=0&&timeToGoHome==distanceFromHome{directions=removeItemFromArray(directions,"n")}ifpersonYAxis<=0&&timeToGoHome==distanceFromHome{directions=removeItemFromArray(directions,"s")}ifpersonXAxis>=0&&timeToGoHome==distanceFromHome{directions=removeItemFromArray(directions,"e")}ifpersonXAxis<=0&&timeToGoHome==distanceFromHome{directions=removeItemFromArray(directions,"w")}direction:=rand.Intn(len(directions))route:=directions[direction]walkingRoute=append(walkingRoute,route)switchroute{case"n":personPosition.yAxis+=1case"s":personPosition.yAxis-=1case"e":personPosition.xAxis+=1case"w":personPosition.xAxis-=1}}returnwalkingRoute,nil}funcremoveItemFromArray(array[]string,itemstring)[]string{fori,v:=rangearray{ifv==item{returnappend(array[:i],array[i+1:]...)}}returnarray}funcabs(xint)int{ifx<0{return-x}returnx}
I went the voluntary choice route with a voluntary initial route, and reversing it to get back.
functionNew-WalkPattern{[cmdletbinding()]param([parameter(ValueFromPipelineByPropertyName)][ValidateRange(4,30)][int]$WalkTime=14)if($WalkTime%2-gt0){$WalkTime--}$WalkTimeArray=[char[]]::new($WalkTime)$LastDirection='x'#picking an invalid direction on purpose$UserSteps=$WalkTime/2$ReverseStepTracker=-1$North=[System.Management.Automation.Host.ChoiceDescription]::New('&North','Walk North')$East=[System.Management.Automation.Host.ChoiceDescription]::New('&East','Walk East')$South=[System.Management.Automation.Host.ChoiceDescription]::New('&South','Walk South')$West=[System.Management.Automation.Host.ChoiceDescription]::New('&West','Walk West')$Options=[System.Management.Automation.Host.ChoiceDescription[]]($North,$East,$South,$West)$Title='Which Direction'$Message='Pick a direction to walk'functionTest-IfWalkDirectionIsRepeated{param([string]$ThisDirection)if($LastDirection-eq$ThisDirection){Write-Warning-Message'You cannot travel the same direction twice in a row!'$Result=$true}else{$LastDirection=$ThisDirection$Result=$false}return$Result}for($i=0;$i-lt$UserSteps;$i++){$Result=$host.ui.PromptForChoice($Title,$Message,$Options,0)switch($Result){'0'{if(Test-IfWalkDirectionIsRepeated-ThisDirection'N'){$i++$ReverseStepTracker++}else{$WalkTimeArray[$i]='N'$WalkTimeArray[$ReverseStepTracker]='S'$ReverseStepTracker--}break}'1'{if(Test-IfWalkDirectionIsRepeated-ThisDirection'E'){$i++$ReverseStepTracker++}else{$WalkTimeArray[$i]='E'$WalkTimeArray[$ReverseStepTracker]='W'$ReverseStepTracker--}break}'2'{if(Test-IfWalkDirectionIsRepeated-ThisDirection'S'){$i++$ReverseStepTracker++}else{$WalkTimeArray[$i]='S'$WalkTimeArray[$ReverseStepTracker]='N'$ReverseStepTracker--}break}'3'{if(Test-IfWalkDirectionIsRepeated-ThisDirection'W'){$i++$ReverseStepTracker++}else{$WalkTimeArray[$i]='W'$WalkTimeArray[$ReverseStepTracker]='E'$ReverseStepTracker--}break}}}Write-Output$('Your walk path is: {0}'-f($WalkTimeArray-join','))}
functiontake_a_walk(int$distance){if($distance%2==1){thrownewException("take an even number of steps or no return home! <br>");}$steps=[];$directions=['n','e','s','w'];for($i=1;$i<=$distance;$i+=2){$index=array_rand($directions);$steps[]=$directions[$index];$steps[]=$directions[($index+2)%4];}shuffle($steps);$steps=implode(', ',$steps).PHP_EOL;return$steps;}echo"Steps to take : ".take_a_walk(58);
My first attempt at one of these coding challenge things!
I'm not great with maths, but I'm guessing that all walks must have an even length, otherwise you can't end up back at your starting location, you'd always be one away...
If that assumption is true, then I think this works:
Basically, for each "pair" of blocks you want to walk, either add
["n", "s"]or["e", "w"]to an array, then flatten and shuffle! Because you're always adding both a movement and it's inverse, you'll always end up where you started!Ruby's proc / block thing still confuses me a little so I'm not sure if this is the most elegant one-liner (excluding checking for even walk length), but ayy it works!
Great solution! I believe your assumption holds up and makes this solution nice and elegant!
Great job on your first challenge too!!
nice 🤩
Here my contribution with javascript language:
Here's a trivial solution in Python
If you add the requirement that you can't walk the same street twice...
JS
Not a great solution, but a solution.
And a one-liner but not really randomized, just going north-then-south:
And the link to a demo on CodePen
Just make sure the number of s's and n's is the same, and the same for w's and e's.
Perl solution:
PHP
BASH
During my reflexion about this challenge, I figured out that if input is an odd number, you will never be able to go back at your start position.
Here my JS implementation:
Spacie's algo, in Clojure:
Barely in before/at midnight!
But here is my Rust version!
I took a bit of a different route! @spaciecat killed the simple algorithm answer so I wanted to do something different!
I decided to make a program that lets the user build the path they want to take! Cause why not let the User choose where to explore! I might clean this up and turn it into a full post sometime soon!
Here is a really quick demo GIF

Here is my JavaScript solution.
My approach was to depart in some random direction, duplicate that initial set of directions, reverse each individual direction within that copy (north goes to south, etc.), then reverse that entire copy to return to the starting point.
The part I had trouble with was swapping each individual direction. I stored my directions in an array that follows a compass because I figured that the reverse direction is always two away: north's array position + 2 = south, east + 2 = west. I ran into some trouble shifting the directions because I could not add two in all cases because it would go outside of the array bounds, so I put in the if-statement. I'm not sure if there is a way to "wrap" an array in JavaScript without going out of the array bounds. I believe in Python this can be done with the slice notation (double colon syntax). If anyone has a tip for JavaScript, feel free to share.
For wrapping some sum
x + yinside of a rangen, you can use(x + y) % n(and of course bounds-checking withifworks too).N.B. different languages treat negative mod differently. For JS, in the negative case you'd want something like
((x % n) + n) % ninstead of plain%.My solution in Swift language :
Powershell
I went the voluntary choice route with a voluntary initial route, and reversing it to get back.
PHP