;*************************** OBSERVER PROCEDURES ****************************** globals [aa East-Free West-Free Total-Free List-Ready?] patches-own [EastSide? xcoord ycoord number] breeds [living working visiting1 visiting2] set aa [[]] ; create a list called "aa"for vacant parking spaces set bb [[]] ; create a list called "aa"for vacant parking spaces to track-vacant loop[ set Total-Free (count-patches-with [pc = white and count-turtles-here = 0 ] ) output Total-Free] end to track-vacant-all ; here we generate a list called "aa" which tracks the vacant spots on the east sides of roads ; we need to keep them separate so that when a car estimates its driving distance, it knows if it needs to go around the block or not setList-Ready? false let [:a (count-patches-with [pc = white and count-turtles-here = 0] )] setTotal-Free (:a) ask-patches [if pc = white and count-turtles-here = 0 [ repeat Total-Free [ if (number? xcor) [let [:xpos xcor]] if (number? ycor) [let [:ypos ycor]] let [:bb (list xcor ycor)] set aa make-list 0 (East-Free) set aa insert 1 aa :bb ]]] setList-Ready? true ;show aa ; for debugging only to see if "aa" works end to setup ct crt number-of-cars ask-turtles [setCounter 0 setshape cross setc red setspeed 1 setSpeedLimit 1 if (who <= (number-of-cars / 5)) [setbreed living] if (who > (number-of-cars / 5) and who <= (number-of-cars / 2)) [setbreed working] if (who > (number-of-cars / 2) and who <= (number-of-cars / 1.25)) [setbreed visiting1] if (who > (number-of-cars / 1.25)) [setbreed visiting2] if breed = living [setParkTime 48] if breed = working [setParkTime 32] if breed = visiting1 [setParkTime 2] if breed = visiting2 [setParkTime 8] loop [ifelse ((pc-at 0 0) = black and count-turtles-here = 1 ) [stop] [ ifelse (random 2) = 0 [seth 0] [ifelse (random 2) = 0 [seth 90][ifelse (random 2) = 0 [seth 180] [seth 270]]] fd (int random 25) ifelse (random 2) = 0 [seth 0] [ifelse (random 2) = 0 [seth 90][ifelse (random 2) = 0 [seth 180] [seth 270]]] fd (int random 25) ]]] ask-patches-with [pc = white] [ let [:x xcor] set xcoord :x let [:y ycor] set ycoord :y set number (:x * :y); assign each patch an x and y coordinate valeu and a unique number. ] starttrackingall startcountaverage end to clear-cars ct end to count-steps-to-find-parking output (average-of-turtles-with [color = yellow] [steps-to-find-parking]) end to stop-it stoptrackingall stopcountaverage stopDrive&Park end to count-average ; this is for statistical analysis: paste these number into excel and calculate the mean, median and standard deviation show (round average-of-turtles-with [color = yellow] [steps-to-find-parking]) wait 1 end ;*************************** TURTLE PROCEDURES ****************************** turtles-own [speed SpeedLimit ParkTime Parked? steps-to-find-parking Direction CoordX CoordY Counter MyDist] to check-patches-after-park if (pc-ahead = 7) or (pc-ahead = 9) [ rt 90 check-patches-after-park ] end to check-side ask-patch-at CoordX CoordY [output EastSide?] end to choose-nearest-spot ; here extract the itam in the aa list, then extract ech item's x and y and check the patche's distance from the turtle (for all patches) ; create a new variable named :dist which indicates the distance to the nearest free spot and a variable named "item-find" indicating the number of the element in the aa list ; the aa list signifies place on the east side of roads, the bb contains spots from the west side of the road. wait-until [List-Ready? = true] let [:nullcheck (length aa)] ifelse (:nullcheck > 0) [ setMyDist 2000 ; initialize a distance that is bigger than any on screen dist, so that a new dist will always be smaller let [:CoordX 0] let [:CoordY 0] let [:Dir 90] let [:k 1] ; loop through every elemnt in the "number" list starts with 1 let [:aacopy (copy-list aa)] ; make a copy of the "aa", so if the real aa changes in length, their's remain the same until end of counting let [:aasize (length :aacopy)] repeat :aasize [ ;check only for free spots, don't waste RAM let [:item-number (item :k :aacopy)] ; extract the first (eventually each) element from the aa list let [:item-numberX (item 1 :item-number)] ; extract the X value of aa item let [:item-numberY (item 2 :item-number)] ; extract the Y value of the aa item let [:a (round(:item-numberX - xcor))] let [:b (round(:item-numberY - ycor))] ifelse (heading = 0 and :item-numberY < ycor) or (heading = 90 and :item-numberX < xcor) or (heading = 180 and :item-numberY > ycor) or (heading = 270 and :item-numberX > xcor)[ let [:distnew ((abs :a) + (abs :b) + 45)]] ; if the destination spot is in the opposite direction, the add 1/2 (average) block loop (22 + 8) to the dist [let [:distnew ((abs :a) + (abs :b))]] if (:distnew < MyDist ) [let[:kchosen :k] setMyDist :distnew] ; CoordX and CoordY are turtle-own variables, which remember which parking spot the turtles zoomed onto, and will keep that until a turtles goes to that spot. if :k <= :aasize [set :k (:k + 1)] ] set :item-number (item :kchosen :aacopy) ; extract the memorized smallest distance element from the :aacopy list set :item-numberX (item 1 :item-number) ; extract the X value set :item-numberY (item 2 :item-number) ; extract the Y value set :a (round (:item-numberX - xcor)) set :b (round (:item-numberY - ycor)) ifelse (heading = 0 and :item-numberY < ycor) or (heading = 90 and :item-numberX < xcor) or (heading = 180 and :item-numberY > ycor) or (heading = 270 and :item-numberX > xcor)[ setMyDist ( (abs :a) + (abs :b) + 45)] ; if the destination spot is in the opposite direction, the add 1/2 (average) block loop (22 + 8) to the dist [setMyDist ((abs :a) + (abs :b))] set CoordX (:item-numberX) set CoordY (:item-numberY) setDirection (towards-nowrap CoordX CoordY) ] [setCoordX 0 setCoordY 0 setMyDist 1000] end to park ; has to be done so that agent will look for parking until found if (Parked? = false)[ setc yellow ;ask-patch-at CoordX CoordY [setpc green] ;ask-patch-at CoordX CoordY [setpc white] loop[ choose-nearest-spot ; here set the car to break or accelerate according to other cars ifelse (count-turtles-towards heading 1) > 0 ;if there is a turtle 1 space ahead, decelerate [setspeed speed-of one-of-turtles-towards heading 1 decelerate] [ifelse lookahead = 2 ;if lookahead=2, check 2 spaces ahead also [ifelse (count-turtles-at heading 1) > 0 [setspeed speed-of one-of-turtles-towards heading 2 decelerate] [accelerate]] ;else accelerate [accelerate]] if speed < 0.01 [setspeed 0.01] ;also adjust speed based on SpeedLimit and radar if speed > SpeedLimit [setspeed SpeedLimit] ; here is how the actual parking move happens ; first, parking at your own side of the road and then parking at the opposite side of the road, parking on horisontal streets is also allowed. ; augment the counter, which counts the program iterations during which a car parks (instead of real time) ifelse ((pc-at 0 0) = 0 and (pc-at 1 0) = 9 and (count-turtles-at 1 0) = 0) or ((pc-at 0 0) = 0 and (pc-at (-1) 0) = 9 and (count-turtles-at (-1) 0) = 0) or ((pc-at 0 0) = 0 and (pc-at -2 0) = 9 and (count-turtles-at -2 0) = 0) or ((pc-at 0 0) = 0 and (pc-at 2 0) = 9 and (count-turtles-at 2 0) = 0) or ((pc-at 0 0) = 0 and (pc-at 0 1) = 9 and (count-turtles-at 0 1) = 0) or ((pc-at 0 0) = 0 and (pc-at 0 (-1)) = 9 and (count-turtles-at 0 (-1)) = 0) or ((pc-at 0 0) = 0 and (pc-at 0 -2) = 9 and (count-turtles-at 0 -2) = 0) or ((pc-at 0 0) = 0 and (pc-at 0 2) = 9 and (count-turtles-at 0 2) = 0) or ((pc-at 0 0) = 9) [ ; here we augment the parking counter and check if the counter is full, in which case a car leaves if ((pc-at 0 0) = 9 and (pc-at (-1) 0) = 0) [ setCounter Counter + 1 if Counter > ParkTime [setCounter 0 seth 270 fd 1 seth 0 setParked? true stop]] if ((pc-at 0 0) = 9 and (pc-at 1 0) = 0) [ setCounter Counter + 1 if Counter > ParkTime [setCounter 0 seth 90 fd 1 seth 180 setParked? true stop]] if ((pc-at 0 0) = 9 and (pc-at 0 (-1)) = 0) [setCounter Counter + 1 if Counter > ParkTime [setCounter 0 seth 180 fd 1 seth 270 setParked? true stop]] if ((pc-at 0 0) = 9 and (pc-at 0 1) = 0) [setCounter Counter + 1 if Counter > ParkTime [setCounter 0 seth 0 fd 1 seth 90 setParked? true stop]] if ((pc-at 0 0) = 0 and (pc-at 1 0) = 9 and (count-turtles-at 1 0) = 0) [seth 90 fd 1 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at (-1) 0) = 9 and (count-turtles-at (-1) 0) = 0) [seth 270 fd 1 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at -2 0) = 9 and (count-turtles-at -2 0) = 0)[seth 270 fd 2 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at 2 0) = 9 and (count-turtles-at 2 0) = 0) [seth 90 fd 2 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at 0 1) = 9 and (count-turtles-at 0 1) = 0) [seth 0 fd 1 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at 0 (-1)) = 9 and (count-turtles-at 0 (-1)) = 0) [seth 180 fd 1 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at 0 -2) = 9 and (count-turtles-at 0 -2) = 0)[seth 180 fd 2 set steps-to-find-parking 0 setMyDist 0 setc red ] if ((pc-at 0 0) = 0 and (pc-at 0 2) = 9 and (count-turtles-at 0 2) = 0) [seth 0 fd 2 set steps-to-find-parking 0 setMyDist 0 setc red ]] [if (pc-at 0 0) not= white [ ifelse (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3 set steps-to-find-parking (steps-to-find-parking + 3)] [ifelse (random 2) = 0 [rt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 2)][fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)]]] [check-patches-after-park fd speed set steps-to-find-parking (steps-to-find-parking + speed)] if (CoordX = 0 and CoordY = 0)[choose-nearest-spot]]] ; here are the rules to guide a car towards a chosen spot, assuming it can also park on the opposite side of the road. ifelse (CoordX not= 0 and CoordY not= 0 and MyDist not= 1000) [ ;only if you are closest in the competition for a given spot, drive there, else roam randomly and try again next step ;in reality you should try the second best option here and then third best and so on! ; for heading = 0, supposing that you can also park on the opposite side of the road if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and ((heading = 0) and (xcor < CoordX and ycor < CoordY))[ ifelse (CoordX < (xcor + 3))[fd 2 set steps-to-find-parking (steps-to-find-parking + 2)] [rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and ((heading = 0) and (xcor < CoordX and ycor > CoordY))[ rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and ((heading = 0) and (xcor > CoordX and ycor > CoordY))[ fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and ((heading = 0) and (xcor > CoordX and ycor < CoordY))[ ifelse (CoordX > (xcor - 3)) [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)][fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)]] ; for heading = 90, supposing that you can also park on the opposite side of the road if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 90 and (xcor < CoordX and ycor < CoordY))[ ifelse (CoordX < (xcor + 3)) [fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)][fd 2 set steps-to-find-parking (steps-to-find-parking + 2)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 90 and (xcor < CoordX and ycor > CoordY))[ ifelse (CoordX < (xcor + 3)) [rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 90 and (xcor > CoordX and ycor > CoordY))[ rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 90 and (xcor > CoordX and ycor < CoordY))[ fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)] ; for heading = 180, supposing that you can also park on the opposite side of the road if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 180 and (xcor < CoordX and ycor < CoordY))[ fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 180 and (xcor < CoordX and ycor > CoordY))[ ifelse (CoordX < (xcor + 3)) [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)] [fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 180 and (xcor > CoordX and ycor > CoordY))[ ifelse (CoordX > (xcor - 3)) [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)] [rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 180 and (xcor > CoordX and ycor < CoordY))[ rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] ; for heading = 270, supposing that you can also park on the opposite side of the road if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 270 and (xcor < CoordX and ycor < CoordY))[ rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 270 and (xcor < CoordX and ycor > CoordY))[ fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 270 and (xcor > CoordX and ycor > CoordY))[ ifelse (CoordX > (xcor - 3)) [fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)] [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)]] if ((pc-at 0 0) = 2 and (pc-ahead)= 2) and (heading = 270 and (xcor > CoordX and ycor < CoordY))[ ifelse (CoordX > (xcor - 3)) [rt 90 fd 1 set steps-to-find-parking (steps-to-find-parking + 1)] [fd 2 set steps-to-find-parking (steps-to-find-parking + 2)]] ][if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3 set steps-to-find-parking (steps-to-find-parking + 3)] [ifelse (random 2) = 0 [rt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 2)][fd 1 lt 90 fd 2 set steps-to-find-parking (steps-to-find-parking + 3)]]]] ]] end to drive ; each egnt will park and then drive for a certain time if (pc-at 1 0) = 7 or (pc-at 1 0) = 9 [ seth 0 setParked? false park repeat (parking-interval * 10) [ ; these are turtles driving up if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3] [ifelse (random 2) = 0 [rt 90 fd 2][fd 1 lt 90 fd 2]]] check-patches-after-park ifelse (count-turtles-at 0 1) > 0 ;if there is a turtle 1 space ahead, decelerate [setspeed speed-of one-of-turtles-at 0 1 decelerate] [ifelse lookahead = 2 ;if lookahead=2, check 2 spaces ahead also [ifelse (count-turtles-at 0 1) > 0 [setspeed speed-of one-of-turtles-at 0 2 decelerate] [accelerate]] ;else accelerate [accelerate]] if speed < 0.01 [setspeed 0.01] ;also adjust speed based on SpeedLimit and radar if speed > SpeedLimit [setspeed SpeedLimit] fd speed ] ] if (pc-at (-1) 0) = 7 or (pc-at (-1) 0) = 9 [ seth 180 setParked? false park repeat (parking-interval * 10) [ ; these are turtles driving up if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3] [ifelse (random 2) = 0 [rt 90 fd 2][fd 1 lt 90 fd 2]]] check-patches-after-park ifelse (count-turtles-at 0 (-1)) > 0 ;if there is a turtle 1 space ahead, decelerate [setspeed speed-of one-of-turtles-at 0 (-1) decelerate] [ifelse lookahead = 2 ;if lookahead=2, check 2 spaces ahead also [ifelse (count-turtles-at 0 (-1)) > 0 [setspeed speed-of one-of-turtles-at 0 (-2) decelerate] [accelerate]] ;else accelerate [accelerate]] if speed < 0.01 [setspeed 0.01] ;also adjust speed based on SpeedLimit and radar if speed > SpeedLimit [setspeed SpeedLimit] fd speed ] ] if (pc-at 0 1) = 7 or (pc-at 0 1) = 9 [ seth 270 setParked? false park repeat (parking-interval * 10) [ ; these are turtles driving up if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3] [ifelse (random 2) = 0 [rt 90 fd 2][fd 1 lt 90 fd 2]]] check-patches-after-park ifelse (count-turtles-at (-1) 0) > 0 ;if there is a turtle 1 space ahead, decelerate [setspeed speed-of one-of-turtles-at (-1) 0 decelerate] [ifelse lookahead = 2 ;if lookahead=2, check 2 spaces ahead also [ifelse (count-turtles-at (-1) 0) > 0 [setspeed speed-of one-of-turtles-at (-2) 0 decelerate] [accelerate]] ;else accelerate [accelerate]] if speed < 0.01 [setspeed 0.01] ;also adjust speed based on SpeedLimit and radar if speed > SpeedLimit [setspeed SpeedLimit] fd speed ] ] if (pc-at 0 (-1)) = 7 or (pc-at 0 (-1)) = 9 [ seth 90 setParked? false park repeat (parking-interval * 10) [ ; these are turtles driving up if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3] [ifelse (random 2) = 0 [rt 90 fd 2][fd 1 lt 90 fd 2]]] check-patches-after-park ifelse (count-turtles-at 1 0) > 0 ;if there is a turtle 1 space ahead, decelerate [setspeed speed-of one-of-turtles-at 1 0 decelerate] [ifelse lookahead = 2 ;if lookahead=2, check 2 spaces ahead also [ifelse (count-turtles-at 2 0) > 0 [setspeed speed-of one-of-turtles-at 2 0 decelerate] [accelerate]] ;else accelerate [accelerate]] if speed < 0.01 [setspeed 0.01] ;also adjust speed based on SpeedLimit and radar if speed > SpeedLimit [setspeed SpeedLimit] fd speed ] ] if (pc-ahead = 2 and (pc-at 0 0) = 2) [ifelse (random 2) = 0 [leap 3] [ifelse (random 2) = 0 [rt 90 fd 2][fd 1 lt 90 fd 2]]] check-patches-after-park if (pc-at 0 0 )= 2 [fd 1] end to accelerate setspeed (speed + (speedup / 1000)) end to decelerate setspeed speed - (slowdown / 1000) end