2011-03-22 3 views
7

안녕하세요 여러분, 저는 C++의 다음 코드를 가지고 있습니다.C++에서 F # 부드러운 번역

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 #으로 직접 변환 할 수 있습니다.

물론 이것은 아마도 F #이 사용되는 방식이 아니기 때문에 대부분 당신을 겁나게 만듭니다. 이 코드에는 do-while 루프 및 변경 가능한 데이터와 같은 F #에 대한 "unkosher"개념이 있습니다.

하지만 내가보기에 관심이있는 부분은 불변의 데이터를 가진 "적절한"F # 변환과 일종의 do-while 동등한 것입니다.

답변

4

내 시도이다. Tomas 솔루션과 마찬가지로 무한한 위치 순서를 생성합니다. 그런 다음 잘못된 위치와 중복 된 위치를 제거합니다. 마지막으로 nObstacles 첫 번째 요소로 보드를 업데이트합니다.

5

첫 번째 단계에서는 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을 제거 할 수 있습니다 그러나, 재귀 및 세트를 보여주는 좋은 운동 ... 여기

+0

첫 번째 해결책은 흥미로운 것 같습니다. 어쨌든 보드 종류의 HAS가 어쨌든 변경 될 수 있기 때문에 여기서는 100 % 불변성에 대한 필요성이 없을 것입니다. 나는 (x, y) 변수의 변경 가능성을 피하기를 바랬습니다. – user627943