As a first step, you can see how to simplify the while inside the for loop. One option is to use Seq.initInfinite to generate a sequence that will give you any number of random X, Y coordinates. Then you can use Seq.find to find the first one that refers to an empty field field.
I also changed isEmpty to take a tuple (so you can pass as an argument to Seq.find using a partial function application), and I changed some names to follow the more standard F # styles (usually you wonโt use the Hungarian naming convention) :
let isEmpty (x, y) = board.[x,y] = -1 let rnd = new System.Random() for i = 0 to obstacleCount do let x, y =
I think this is a pretty elegant functional solution. This may be a little slower than an imperative solution, but the fact is that the functional style simplifies writing and changing the implementation after studying it (you can always use the imperative style as an optimization).
To avoid any volatile state, you must first create places for obstacles, and then initialize the array. For example, you can recursively add new coordinates to a set until it has the required length. Then you can generate the array using Array2D.init :
let rec generateObstacles obstacles = if Set.count obstacles = obstacleCount then obstacles else // Try generating new coordinate and add it to the set // (if it is already included, this doesn't do anything) obstacles |> Set.add (rnd.Next(width), rnd.Next(height)) |> generateObstacles let obstacles = generateObstacles Set.empty Array2D.init width height (fun xy -> if obstacles.Contains(x, y) then Obstacle else Empty)
This is not very shorter, and it will be a little slower, so I will stick to the first solution. However, this is a good exercise showing recursion and a lot ...
Tomas petricek
source share