嘿伙计们,我有以下C ++代码。
for (int i=0; i < nObstacles; i++)
{
int x,y;
bool bAlreadyExists;
do {
x = rand() % nGridWidth;
y = rand() % nGridHeight;
} while (HasObstacle(x, y));
SetObstacle(x, y, true);
}
我可以直接将它翻译成F#,没有任何问题。
let R = new System.Random()
for i=0 to nObstacles do
let mutable bGoodToGo = false;
let mutable x =0;
let mutable y = 0
while not bGoodToGo do
x <-R.Next(nWidth)
y <-R.Next(nHeight)
bGoodToGo <- IsEmptyAt x y
board.[x,y]<-Obstacle;
当然这可能会让你们大多数人感到畏缩,因为这不是F#的意思。这段代码为F#提供了一些“unkosher”概念,例如do-while循环和可变数据。
但我有兴趣看到的是一个带有不可变数据的“适当的”F#转换,以及某种等同的做法。
答案 0 :(得分:5)
作为第一步,您可以了解如何简化while
循环内的for
循环。一种选择是使用Seq.initInfinite
生成一个序列,该序列将为您提供任意数量的随机X,Y坐标。然后,您可以使用Seq.find
查找引用空板字段的第一个。
我还更改了isEmpty
以获取元组(以便您可以使用部分函数应用程序将参数作为参数传递给Seq.find
)并且我更改了一些名称以遵循更标准的F#样式(您通常不会'使用匈牙利语命名符号):
let isEmpty (x, y) = board.[x,y] = -1
let rnd = new System.Random()
for i = 0 to obstacleCount do
let x, y =
// Generate infinite sequence of random X Y coordinates
Seq.initInfinite (fun _ -> rnd.Next(width), rnd.Next(height))
// Find first coordinate that refers to empty field
|> Seq.find isEmpty
// We still have mutation here
board.[x,y] <- Obstacle
我认为这是非常优雅的功能解决方案。它可能比命令式解决方案慢一点,但重点是功能风格使编写和解决方案更容易。一旦你学会了它就改变实现(你总是可以使用命令式样式作为优化)。
为避免所有可变状态,您需要先为障碍物生成位置,然后初始化阵列。例如,您可以递归地向集合添加新坐标,直到它具有所需的长度。然后,您可以使用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 x y ->
if obstacles.Contains(x, y) then Obstacle else Empty)
这不是很短,而且会慢一点,所以我坚持第一个解决方案。但是,这是一个很好的练习,显示递归和设置......
答案 1 :(得分:4)
这是我的尝试:
Seq.initInfinite (fun _ -> rnd.Next(width), rnd.Next(height))
|> Seq.filter (fun (x, y) -> IsEmptyAt x y)
|> Seq.distinct
|> Seq.take nObstacles
|> Seq.iter (fun (x, y) -> board.[x,y] <- Obstacle)
如果电路板在开头是空的,您可以删除Seq.filter。就像Tomas解决方案一样,它会产生无限的位置序列。然后,它删除了错误和重复的位置。最后,它使用nObstacles第一个元素更新了电路板。