첫 번째 단계에서는 for
루프 내에서 while
루프를 단순화하는 방법을 살펴볼 수 있습니다. 하나의 옵션은 Seq.initInfinite
을 사용하여 임의의 수의 임의의 X, Y 좌표를 제공하는 시퀀스를 생성하는 것입니다. 그런 다음 Seq.find
을 사용하여 빈 보드 필드를 참조하는 첫 번째 것을 찾을 수 있습니다.
또한 부분 수식 응용 프로그램을 사용하여 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
매우 세련된 기능적인 해결책이라고 생각합니다. 명령형 솔루션보다 약간 느릴 수도 있지만 요점은 기능적 스타일을 사용하면 & 구현을 변경하는 것이 더 쉬워집니다 (항상 명령형 스타일을 최적화로 사용할 수 있음).
모든 가변 상태를 피하려면 먼저 장애물 위치를 생성 한 다음 배열을 초기화해야합니다. 예를 들어, 필요한 길이가 될 때까지 새로운 좌표를 반복적으로 세트에 추가 할 수 있습니다.
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)
이 정말 짧은 아니며, 그것은 조금 느린 것, 그래서 최초의 솔루션에 충실 것 : 그럼 당신은 Array2D.init
를 사용하여 배열을 생성 할 수 있습니다. 보드가 처음에 비어있는 경우
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을 제거 할 수 있습니다 그러나, 재귀 및 세트를 보여주는 좋은 운동 ... 여기
첫 번째 해결책은 흥미로운 것 같습니다. 어쨌든 보드 종류의 HAS가 어쨌든 변경 될 수 있기 때문에 여기서는 100 % 불변성에 대한 필요성이 없을 것입니다. 나는 (x, y) 변수의 변경 가능성을 피하기를 바랬습니다. – user627943