2011-03-22 21 views
7

अरे दोस्तों, मेरे पास सी ++ से कोड का निम्न भाग है।सी ++ से एफ # चिकनी अनुवाद

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);  
} 

मैं इसे बिना किसी समस्या के सीधे एफ # में अनुवाद कर सकता हूं।

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; 

बेशक यह संभवतः आप में से अधिकांश को क्रिंग करता है, क्योंकि एफ # का उपयोग करने का मतलब नहीं था। इस कोड में एफ # के लिए कुछ "अनोखेर" अवधारणाएं हैं, जैसे डू-लूप लूप और म्यूटेबल डेटा।

लेकिन मुझे जो देखने में दिलचस्पी होगी वह अपरिवर्तनीय डेटा के साथ "उचित" एफ # अनुवाद है, और कुछ प्रकार के समकक्ष समकक्ष है।

उत्तर

4

यहाँ है मेरी कोशिश है। टॉमस समाधान की तरह, यह पदों का एक अनंत अनुक्रम उत्पन्न करता है। फिर, यह खराब और डुप्लिकेट पदों को हटा देता है। अंत में, यह बोर्ड को nobstacles पहले तत्वों के साथ अद्यतन करता है।

5

पहले चरण के रूप में, आप लूप के अंदर while पाश को सरल बनाने के तरीके को देख सकते हैं। एक विकल्प है कि अनुक्रम उत्पन्न करने के लिए Seq.initInfinite का उपयोग करना है जो आपको यादृच्छिक एक्स, वाई निर्देशांक की संख्या प्रदान करेगा। फिर आप रिक्त बोर्ड फ़ील्ड को संदर्भित करने वाले पहले व्यक्ति को खोजने के लिए Seq.find का उपयोग कर सकते हैं।

मैं भी isEmpty बदल एक टपल लेने के लिए (ताकि आप आंशिक समारोह अनुप्रयोग का उपयोग Seq.find को तर्क के रूप में पारित कर सकते हैं) और मैं कुछ नाम बदल अधिक मानक एफ # शैली (आप आमतौर हंगेरी नामकरण संकेतन का उपयोग नहीं होता) का पालन करने के लिए:

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) 

यह वास्तव में कम नहीं है और यह थोड़ा धीमा हो जाएगा, तो मैं पहले समाधान के लिए छड़ी होगी।

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

मुझे लगता है कि आपका पहला समाधान दिलचस्प है। मुझे लगता है कि "बॉक्स से बाहर" यहां शायद 100% अपरिवर्तनीयता की कोई ज़रूरत नहीं है, क्योंकि बोर्ड की तरह वैसे भी उत्परिवर्तनीय हो सकता है, मैं बस (x, y) की व्यवहार्यता से बचने की उम्मीद कर रहा था। – user627943