2010-08-21 4 views
6

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

हाय सब,

के अनुसार मैं सिर्फ एफ # में मेरी सी # 2 डी पथ खोजने कोड के कुछ पोर्टिंग की कोशिश की है। लेकिन मैं वर्तमान में सी # ओओ डेवलपर होने के 'लिम्बो' में हूं और शायद, मेरे एफ # के साथ पूरी तरह से कार्यात्मक होने के लिए बहुत कठिन प्रयास कर रहा हूं।

तो कोड का यह टुकड़ा लेना, शायद अब तक कम से कम छोटा एफ # मैंने लिखा है, मुझे इसे एफ # कोड का एक अच्छा टुकड़ा बनाने पर कुछ सलाह चाहिए। (क्षमा करें अगर यह थोड़ा है "मेरे लिए मेरा होमवर्क करें", लेकिन मुझे संदर्भ के लिए F # ए * पथ-खोज का अच्छा नमूना नहीं मिल रहा है।)।

एक बात जो तुरंत दिमाग में फैलती है वह है: क्या मेरा अत्यधिक उपयोग अगर/else/elseif "कार्यात्मक" पर्याप्त है?

कुछ नोट:

1) "निकालें" एक सरल उपयोगिता समारोह है कि एक सूची

2) "nodeToPathNode" बस एक बिंदु अंतरिक्ष में ले जाता है से तत्व निकाल देता है और एक पथ नोड बाहर बनाता है इसके बारे में


संपादित करें ((* ठेठ एक के अनुसार) एक माता पिता के संदर्भ, और एक ज, छ & च जोड़ने) (# 1): मैं (बिना दिए गए सुझावों के साथ कोड को नवीनीकृत किया है इसे सामान्य बनाने के बारे में, मैं उस पर बाद में प्राप्त करूंगा) ... बस कुछ लोग Google के माध्यम से यहां आते हैं और मेरे कोड को खराब स्वरूपण और तर्क त्रुटियों के साथ कॉपी करना चाहते थे।
एक पूर्ण, 2 डी टाइल विशिष्ट, कार्यान्वयन यहां पाया जा सकता: http://jdoig.net/blog/?p=81

संपादित करें (# 2) या जेनेरिक वर्जन यहां पाया जा सकता: http://jdoig.net/blog/?p=127


let rec pathFind (area:Map) goal start (openNodes:PathingNode list) (closedNodes:PathingNode list) = 
let pointToPathNode = pointToPathNode openNodes.Head goal //localy specific version of nTPN 

let rec checkNeighbours neighbours openNodeAcc= //Loop over list of neighbours accumalating a list of open nodes 
    match neighbours with 
    |[] -> openNodeAcc //When list of neighbours is exhausted return the open nodes. 
    |hd::tl -> 
     let checkNeighbours = checkNeighbours tl       //localy specific version of cn 
     let node = {hd with parent = Some(openNodes.Head)} 
     if (List.exists (isShorter hd) openNodeAcc) then  //if a higher costingnode is in open... 
      let shorterPath = remove openNodeAcc (nodePointEquals hd.point)   //... remove it.. 
      checkNeighbours (node::shorterPath) 
     elif not(List.exists (nodePointEquals hd.point) closedNodes) && not (List.exists (nodePointEquals hd.point) openNodeAcc) then //If path is not open or closed... 
      checkNeighbours (node::openNodeAcc) 
     else checkNeighbours openNodeAcc //Else carry on. 

let neighbours = 
     area.GetNeighboursOf openNodes.Head.point //Get the neighbours of our current node (openNodes.Head) ... 
     |> List.filter isClear      //...filter out collidable tiles... 
     |> List.map pointToPathNode     //...for each neighbour we can walk to: generate a pathing node     

let pathToGoal = List.tryFind (nodePointEquals goal) neighbours //Try and find the goal node in the walkable neighbours of this tile. 
if pathToGoal.IsSome then pathToGoal      //If we found our goal return it... 
else 
    let nextSet = 
     checkNeighbours neighbours openNodes.Tail 
     |> List.sortBy(fun x -> x.f) 
    if nextSet.Length > 0 then 
     pathFind area goal start nextSet (nextSet.Head::closedNodes) //...Else carry on 
    else None 

धन्यवाद,

जेडी

उत्तर

3

आई एच aven't एल्गोरिथ्म/तर्क को बारीकी से देखा, लेकिन यहाँ मैं इसे कैसे स्पर्श अप होता है:

let rec pathFind (area:map,start, goal, openNodes:PathingNode list, closedNodes:PathingNode list)=   
    let rec checkNeighbours (opn, neighbours) = 
     match neighbours with 
     | [] -> opn 
     | hd::tl -> 
      if List.exists (fun x -> x.point = hd.point && x.f > hd.f) opn then 
       checkNeighbours(remove opn (fun x -> x.point = hd.point), tl) 
      elif not(List.exists (fun x -> x.point = hd.point) closedNodes) 
       && not(List.exists (fun x -> x.point = hd.point) opn) then 
       checkNeighbours({hd with parent = Some(openNodes.Head)}::opn, tl) 
      else  
       checkNeighbours(opn, tl) 

    let neighbours = 
     area.GetNeighboursOf(openNodes.Head.point) 
     |> List.map (fun mp -> nodeToPathNode(mp, openNodes.Head, goal)) 
     |> List.filter (fun pnd ->pnd.point.value = 0) 

    let openLocalNodes = checkNeighbours(openNodes.Tail, neighbours)  

    if List.exists (fun x -> x.point = goal) openLocalNodes then 
     {point=goal; h=0; g=goal.Distance(start); parent=Some(openNodes.Head)} 
    else 
     pathFind(area, start, goal, openLocalNodes, openNodes.Head::closedNodes)  

PathingNode - प्रकार बड़े अक्षरों (list/option/array/ref केवल अपवाद हैं) के साथ शुरू करते हैं।

प्रत्येक कॉमा, अर्धविराम, या लंबवत बार के बाद व्हाइटस्पेस।

hd::tl लाइन के बाद इंडेंट कम करें, और else if के बजाय elif का उपयोग करें।

अनावश्यक कोष्ठकों के बहुत से छुटकारा (f x नहीं f(x), if cond then नहीं if(cond) then)।

पाइपलाइनिंग शैली थोड़ा और (let neighbours=...)।

अन्यथा, एक नज़र में यह अच्छा लग रहा है।

+0

धन्यवाद ब्रायन, यह सिर्फ वही सामान है जो मैं बाद में था: ¬) – jdoig

1

यहां कुछ विचार हैं:

कुछ टिप्पणियां जोड़ें! क्या चल रहा है इसका पालन करना थोड़ा मुश्किल है।

आम तौर पर, अपने tupled रूपों के लिए करीबी कार्यों पसंद करते हैं। इससे आंशिक अनुप्रयोग का उपयोग करना संभव हो जाता है, जिसे अक्सर पढ़ने में आसान हो सकता है। उदाहरण के लिए, यदि आप पैरामीटर को पुन: व्यवस्थित करने के लिए nodeToPathNode फ़ंक्शन को फिर से लिखते हैं, तो आप mp अस्थायी चर को पेश करने के बजाय List.map (nodeToPathNode openNodes.Head goal) कर सकते हैं।

सूचियों का उपयोग करने के बजाय आप F # के सेट प्रकार का उपयोग करने पर विचार कर सकते हैं क्योंकि इससे न्यूनतम तत्व शामिल होने वाले अधिक कुशल संचालन की अनुमति मिलती है।

मेरे लिए, आपके कोड के साथ सबसे बड़ी समस्या यह है कि यह बहुत विशिष्ट है; ए * एक सामान्य एल्गोरिदम है; अवधारणात्मक रूप से, यह g और h, प्रारंभ नोड, एक लक्ष्य, और एक फ़ंक्शन जो उसके पड़ोसियों को नोड को मानचित्रित करता है, द्वारा पैरामीटर द्वारा पैरामीटर किया गया है। इस प्रकार मैं आपके एल्गोरिदम के हस्ताक्षर pathfind (g:'a -> float) (h:'a -> float) (start : 'a) (goal : 'a) (neighbors : 'a -> 'a list) : 'a list option की तरह होने की अपेक्षा करता हूं। फिर भी आप अपने वर्तमान नोड प्रकारों के साथ इस एल्गोरिदम का उपयोग कर सकते हैं, लेकिन चूंकि दूरी और पड़ोसी कार्यों को हार्डकोड नहीं किया जाता है, इसलिए आप इसे किसी अन्य पथदर्शी समस्याओं को हल करने के लिए भी उपयोग कर सकते हैं।

+0

धन्यवाद केवीबी, मैंने अपनी पोस्ट से टिप्पणियों को छोड़ दिया क्योंकि यह एसओ की सीमित क्षैतिज चौड़ाई को देखते हुए थोड़ा व्यस्त दिखता था। लेकिन मुझे आपके बाकी सुझावों को लागू करने में झगड़ा होगा। फिर से धन्यवाद। – jdoig

+0

हाय केवीबी। मैंने आपके सामान्य ए * विचार को लागू किया है लेकिन ऐसा लगता है कि यह थोड़ा धीमा चल रहा है। किसी भी मौके पर आप कोड पर एक नज़र डाल सकते हैं और मुझे दो पॉइंटर्स दे सकते हैं? फिर से धन्यवाद। – jdoig

0

@ केवीबी।

जेनेरिक ए * एल्गोरिदम बनाने की सलाह के लिए धन्यवाद। यह कार्यान्वित करने और एक महान सीखने के उपकरण के लिए मजेदार था।

मेरे समस्या मेरी सामान्य कार्यान्वयन 5 और 8 के बीच एमएस धीमी है कि, शायद मैं जेनरिक की लागत गलत है, लेकिन मैं इसे कम मूल्य वाले :(की कल्पना की।

यहाँ मेरी कोड है कि अगर आप बहुत दयालु होगा के रूप में यह कुछ भी है कि मुझे इतना समय की लागत जा सकता है की जांच करने के (यह मानते हुए यह गलती मेरी कोड और नहीं जेनरिक की भूमि के ऊपर है):

let rec aStar value g h neighbours goal start (openNodes: 'a list) (closedNodes: 'alist) = 
    let f x:float = (g x)+(h x) //f will be the value we sort open nodes by. 
    let isShorter nodeA nodeB = nodeA = nodeB && f nodeA < f nodeB 

let rec checkNeighbours neighbours openNodeAcc = 
    match neighbours with 
    | [] -> openNodeAcc 
    | currentNode::rest -> 
     let likeCurrent = fun n -> (value n) = (value currentNode) //vale of n == value of current 
     let containsCurrent = List.exists likeCurrent    //list contains likeCurrent 
     let checkNeighbours = checkNeighbours rest 

     if openNodeAcc |> List.exists (isShorter currentNode) then //The current node is a shorter path than than one we already have. 
      let shorterPath = remove openNodeAcc likeCurrent //So remove the old one... 
      checkNeighbours (currentNode::shorterPath) //...and arry on with the new one. 
     elif not(containsCurrent closedNodes) && not(containsCurrent openNodeAcc) then //The current node has not been queried 
      checkNeighbours (currentNode::openNodeAcc) //So add it to the open set 
     else checkNeighbours openNodeAcc // else carry on 

let nodes = neighbours openNodes.Head //The next set of nodes to work on 

let pathToGoal = nodes |> List.tryFind (fun x -> (value x) = goal) 
if pathToGoal.IsSome then pathToGoal //Found the goal! 
else 
    let nextSet = 
     checkNeighbours nodes openNodes.Tail 
     |> List.sortBy f //sort open set by node.f 
    if nextSet.Length > 0 then //Carry on pathfinding 
     aStar value g h neighbours goal start nextSet (nextSet.Head::closedNodes) 
    else None //if there are no open nodes pathing has failed 

धन्यवाद,

जद

संबंधित मुद्दे