मानक पाथफाइंडिंग अच्छा पर्याप्त है - आपके राज्य आपके वर्तमान स्थान + आपकी वर्तमान सूची हैं। "मूविंग" या तो कमरे बदल रहा है या इन्वेंट्री बदल रहा है। इस उत्तर में कवर नहीं किया गया है, लेकिन बहुत अधिक अतिरिक्त प्रयास नहीं है, ए * के लिए एक अच्छा अनुमानी लिख रहा है - यह वास्तव में खोज को गति दे सकता है इससे दूर जाने के लिए चीजों को लेने से पहले, लक्ष्य के पास एक दरवाजे को खोलने के लिए प्राथमिकता देना। बहुत देर तक इधर-उधर खोजना, आदि।
इस उत्तर ने पहले से ही बहुत अधिक उत्थान प्राप्त किया है और इसमें एक डेमो है, लेकिन एक बहुत अधिक अनुकूलित और विशेष समाधान के लिए, आपको "इसे पीछे की ओर करना बहुत तेज है" उत्तर /gamedev/ पढ़ना चाहिए / एक / 150155/2624
नीचे अवधारणा का पूरी तरह से संचालन जावास्क्रिप्ट सबूत। एक कोड डंप के रूप में जवाब के लिए खेद है - मैं वास्तव में इसे लागू करने से पहले आश्वस्त था कि यह एक अच्छा जवाब था, लेकिन यह मेरे लिए बहुत लचीला लगता है।
पाथफाइंडिंग के बारे में सोचते समय शुरुआत करने के लिए, याद रखें कि सरल पाथफाइंडिंग एल्गोरिदम की उत्तराधिकारिणी है:
- चौड़ाई पहली खोज के बारे में सरल के रूप में आप प्राप्त कर सकते हैं।
- Djikstra का एल्गोरिथ्म चौड़ाई प्रथम खोज की तरह है, लेकिन राज्यों के बीच अलग-अलग "दूरी" के साथ
- ए * जिरिकैस्टस है जहाँ आपके पास 'सही दिशा का सामान्य ज्ञान' है, जो एक अनुमानी के रूप में उपलब्ध है।
हमारे मामले में, एक "स्थिति + इन्वेंट्री" और "दूरी" के रूप में "आंदोलन या आइटम उपयोग" के रूप में एक "राज्य" को एन्कोडिंग करने से हमें अपनी समस्या को हल करने के लिए Djikstra या A * का उपयोग करने की अनुमति मिलती है।
यहां कुछ वास्तविक कोड आपके उदाहरण स्तर का प्रदर्शन कर रहे हैं। पहला स्निपेट केवल तुलना के लिए है - यदि आप अंतिम समाधान देखना चाहते हैं तो दूसरे भाग पर जाएं। हम एक Djikstra के कार्यान्वयन के साथ शुरुआत करते हैं जो सही रास्ता ढूंढता है, लेकिन हमने सभी बाधाओं और कुंजियों को अनदेखा कर दिया है। (इसे आज़माएं, आप इसे कमरे से 0 -> 2 -> 3-> 4-> 6-> 5) के लिए समाप्त होने के लिए बस beelines देख सकते हैं)
function Transition(cost, state) { this.cost = cost, this.state = state; }
// given a current room, return a room of next rooms we can go to. it costs
// 1 action to move to another room.
function next(n) {
var moves = []
// simulate moving to a room
var move = room => new Transition(1, room)
if (n == 0) moves.push(move(2))
else if ( n == 1) moves.push(move(2))
else if ( n == 2) moves.push(move(0), move(1), move(3))
else if ( n == 3) moves.push(move(2), move(4), move(6))
else if ( n == 4) moves.push(move(3))
else if ( n == 5) moves.push(move(6))
else if ( n == 6) moves.push(move(5), move(3))
return moves
}
// Standard Djikstra's algorithm. keep a list of visited and unvisited nodes
// and iteratively find the "cheapest" next node to visit.
function calc_Djikstra(cost, goal, history, nextStates, visited) {
if (!nextStates.length) return ['did not find goal', history]
var action = nextStates.pop()
cost += action.cost
var cur = action.state
if (cur == goal) return ['found!', history.concat([cur])]
if (history.length > 15) return ['we got lost', history]
var notVisited = (visit) => {
return visited.filter(v => JSON.stringify(v) == JSON.stringify(visit.state)).length === 0;
};
nextStates = nextStates.concat(next(cur).filter(notVisited))
nextStates.sort()
visited.push(cur)
return calc_Djikstra(cost, goal, history.concat([cur]), nextStates, visited)
}
console.log(calc_Djikstra(0, 5, [], [new Transition(0, 0)], []))
तो, हम इस कोड में आइटम और कुंजियाँ कैसे जोड़ते हैं? सरल! हर "राज्य" के बजाय बस कमरा नंबर शुरू करें, यह अब कमरे और हमारे इन्वेंट्री राज्य का एक हिस्सा है:
// Now, each state is a [room, haskey, hasfeather, killedboss] tuple
function State(room, k, f, b) { this.room = room; this.k = k; this.f = f; this.b = b }
अब परिवर्तन एक (लागत, कमरे) से टपल टू (कॉस्ट, अवस्था) में परिवर्तित हो जाते हैं, इसलिए तब "दूसरे कमरे में जाना" और "एक आइटम चुनना" दोनों को एन्कोड कर सकते हैं।
// move(3) keeps inventory but sets the room to 3
var move = room => new Transition(1, new State(room, cur.k, cur.f, cur.b))
// pickup("k") keeps room number but increments the key count
var pickup = (cost, item) => {
var n = Object.assign({}, cur)
n[item]++;
return new Transition(cost, new State(cur.room, n.k, n.f, n.b));
};
अंत में, हम Djikstra फ़ंक्शन के लिए कुछ छोटे प्रकार से संबंधित परिवर्तन करते हैं (उदाहरण के लिए, यह अभी भी पूर्ण राज्य के बजाय लक्ष्य कक्ष संख्या पर मेल खा रहा है), और हमें अपना पूर्ण उत्तर मिलता है! ध्यान दें कि मुद्रित परिणाम पहले कुंजी लेने के लिए कमरा 4 में जाता है, फिर कमरे 1 में जाकर पंख उठाता है, फिर कमरे 6 में जाता है, बॉस को मारता है, फिर कमरे 5 में जाता है)
// Now, each state is a [room, haskey, hasfeather, killedboss] tuple
function State(room, k, f, b) { this.room = room; this.k = k; this.f = f; this.b = b }
function Transition(cost, state, msg) { this.cost = cost, this.state = state; this.msg = msg; }
function next(cur) {
var moves = []
// simulate moving to a room
var n = cur.room
var move = room => new Transition(1, new State(room, cur.k, cur.f, cur.b), "move to " + room)
var pickup = (cost, item) => {
var n = Object.assign({}, cur)
n[item]++;
return new Transition(cost, new State(cur.room, n.k, n.f, n.b), {
"k": "pick up key",
"f": "pick up feather",
"b": "SLAY BOSS!!!!"}[item]);
};
if (n == 0) moves.push(move(2))
else if ( n == 1) { }
else if ( n == 2) moves.push(move(0), move(3))
else if ( n == 3) moves.push(move(2), move(4))
else if ( n == 4) moves.push(move(3))
else if ( n == 5) { }
else if ( n == 6) { }
// if we have a key, then we can move between rooms 1 and 2
if (cur.k && n == 1) moves.push(move(2));
if (cur.k && n == 2) moves.push(move(1));
// if we have a feather, then we can move between rooms 3 and 6
if (cur.f && n == 3) moves.push(move(6));
if (cur.f && n == 6) moves.push(move(3));
// if killed the boss, then we can move between rooms 5 and 6
if (cur.b && n == 5) moves.push(move(6));
if (cur.b && n == 6) moves.push(move(5));
if (n == 4 && !cur.k) moves.push(pickup(0, 'k'))
if (n == 1 && !cur.f) moves.push(pickup(0, 'f'))
if (n == 6 && !cur.b) moves.push(pickup(100, 'b'))
return moves
}
var notVisited = (visitedList) => (visit) => {
return visitedList.filter(v => JSON.stringify(v) == JSON.stringify(visit.state)).length === 0;
};
// Standard Djikstra's algorithm. keep a list of visited and unvisited nodes
// and iteratively find the "cheapest" next node to visit.
function calc_Djikstra(cost, goal, history, nextStates, visited) {
if (!nextStates.length) return ['No path exists', history]
var action = nextStates.pop()
cost += action.cost
var cur = action.state
if (cur.room == goal) return history.concat([action.msg])
if (history.length > 15) return ['we got lost', history]
nextStates = nextStates.concat(next(cur).filter(notVisited(visited)))
nextStates.sort()
visited.push(cur)
return calc_Djikstra(cost, goal, history.concat([action.msg]), nextStates, visited)
o}
console.log(calc_Djikstra(0, 5, [], [new Transition(0, new State(0, 0, 0, 0), 'start')], []))
सिद्धांत रूप में, यह बीएफएस के साथ भी काम करता है और हमें जिक्स्ट्रा के लिए लागत फ़ंक्शन की आवश्यकता नहीं थी, लेकिन लागत होने से हमें यह कहने की अनुमति मिलती है कि "एक कुंजी को उठाना आसान नहीं है, लेकिन एक मालिक से लड़ना वास्तव में कठिन है, और हम बल्कि पीछे रह जाएंगे बॉस से लड़ने के बजाय 100 कदम, अगर हमारे पास विकल्प था ":
if (n == 4 && !cur.k) moves.push(pickup(0, 'k'))
if (n == 1 && !cur.f) moves.push(pickup(0, 'f'))
if (n == 6 && !cur.b) moves.push(pickup(100, 'b'))