2011-12-09 12 views
9

इसलिए प्रत्येक घटक 4 प्रभाव http://www.uesp.net/wiki/Skyrim:Ingredientsskyrim (पीसी गेम) औषधि के सभी संभावित संयोजन उत्पन्न करने का सबसे प्रभावी तरीका क्या है?

अगर मैं दो तत्व गठबंधन है। औषधि के बोनस प्रभाव होंगे जहां दो सेट छेड़छाड़ करेंगे। मैं दो बार एक ही घटक का उपयोग नहीं कर सकता। सभी 2 घटक संभावनाओं को उत्पन्न करने के लिए मैंने अभी जोड़ों को प्रभावी करने के लिए घटक की एक सूची बनाई है। मैं सूची का मुखिया लेता हूं और प्रत्येक पुनरावृत्ति के सिर को हटाने वाली सूची में प्रत्येक तत्व के लिए सूची की बाकी सूची में इसकी तुलना करता हूं। यह डुप्लिकेट से बचाता है।

हालांकि मैं अटक गया हूं। मुझे नहीं पता कि डुप्ले के बिना 3 घटक संयोजन कैसे उत्पन्न करें। कोई सुझाव?

उत्तर

14

सभी की पसंदीदा प्रोग्रामिंग भाषा, R के लिए नौकरी की तरह लगता है!

library(XML) 
tables <- readHTMLTable('http://www.uesp.net/wiki/Skyrim:Ingredients', 
    stringsAsFactors=FALSE) 
potions <- tables[[1]] 
twoway <- data.frame(t(combn(potions$Name,2))) 
threeway <- data.frame(t(combn(potions$Name,3))) 

बीएएम!

> head(twoway) 
       X1     X2 
1 Abecean Longfin   Bear Claws 
2 Abecean Longfin     Bee 
3 Abecean Longfin  Beehive Husk 
4 Abecean Longfin  Bleeding Crown 
5 Abecean Longfin   Blisterwort 
6 Abecean Longfin Blue Butterfly Wing 
> head(threeway) 
       X1   X2     X3 
1 Abecean Longfin Bear Claws     Bee 
2 Abecean Longfin Bear Claws  Beehive Husk 
3 Abecean Longfin Bear Claws  Bleeding Crown 
4 Abecean Longfin Bear Claws   Blisterwort 
5 Abecean Longfin Bear Claws Blue Butterfly Wing 
6 Abecean Longfin Bear Claws  Blue Dartwing 

csv फ़ाइलें के रूप में टेबल को बचाने के लिए write.csv आदेश का उपयोग करें।

/संपादित करें: यह समझाने के लिए कि मैं क्या कर रहा हूं: XML पैकेज में readHTMLTable फ़ंक्शन शामिल है, जो किसी भी वेबसाइट से सभी HTML टेबल को डेटा.फ्रेम के रूप में खींचता है और उन्हें एक सूची के रूप में सहेजता है। इस सूची में पहली तालिका वह है जिसे हम चाहते हैं। combn फ़ंक्शन पोशन नामों के सभी 2-तरफा, 3-तरफा, और एन रास्ता combinations पाता है, और परिणाम को मैट्रिक्स के रूप में देता है। मैं इस मैट्रिक्स को स्थानांतरित करने के लिए टी फ़ंक्शन का उपयोग करता हूं, इसलिए प्रत्येक संयोजन एक पंक्ति है, और उसके बाद इसे डेटा फ्रेम में परिवर्तित करें। यह आसानी से एन अवयवों के संयोजन तक फैलता है।

/संपादित 2: मैंने एन-वे टेबल को उपयोगकर्ता द्वारा निर्दिष्ट सीएसवी फ़ाइल में सहेजने के लिए एक फ़ंक्शन लिखा था। मैंने इसे थोड़ा सा भी काम किया, क्योंकि विशाल मैट्रिक्स का स्थानांतरण कम्प्यूटेशनल रूप से महंगा है। इस संस्करण को आपको 4-तरफा तालिका की गणना करने की अनुमति देनी चाहिए, हालांकि इसमें काफी समय लगता है और मुझे नहीं पता कि यह गेम के लिए प्रासंगिक है या नहीं।

nway <- function(n, filepath, data=potions) { 
    nway <- combn(data$Name, n, simplify = FALSE) 
    nway <- do.call(rbind,nway) 
    write.csv(nway,filepath, row.names=FALSE) 
} 
nway(4,'~/Desktop/4way.csv') 

/संपादित करें 3: वास्तविक काम करने वाले औषधि खोजने के लिए यहां कुछ कोड दिया गया है। यह बहुत ही कुशल नहीं है और शायद इसमें काफी सुधार किया जा सकता है:

#Given an ingredient, lookup effects 
findEffects <- function(Name) { #Given a name, lookup effects 
    potions[potions$Name==Name,3:6] 
} 

#2-way potions 
intersectTwoEffects <- function(x) { 
    Effects1 <- findEffects(x[1]) 
    Effects2 <- findEffects(x[2]) 
    Effects <- unlist(intersect(Effects1,Effects2)) 
    Effects <- c(x[1],x[2],Effects) 
    length(Effects) <- 6 
    names(Effects) <- NULL 
    c(Effects,sum(is.na(Effects))) 

} 
twoway <- lapply(twoway,intersectTwoEffects) 
twoway <- do.call(rbind,twoway) 
twoway <- twoway[twoway[,7]<4,-7] #remove combos with no effect 
write.csv(twoway,'~/Desktop/twoway.csv',row.names=FALSE) 

#3-way potions 
intersectThreeEffects <- function(x) { 
    Effects1 <- findEffects(x[1]) 
    Effects2 <- findEffects(x[2]) 
    Effects3 <- findEffects(x[3]) 
    Effects <- c(intersect(Effects1,Effects2),intersect(Effects1,Effects3),intersect(Effects2,Effects3)) 
    Effects <- unlist(unique(Effects)) 
    Effects <- c(x[1],x[2],x[3],Effects) 
    length(Effects) <- 8 
    names(Effects) <- NULL 
    c(Effects,sum(is.na(Effects))) 

} 
threeway <- lapply(threeway,intersectThreeEffects) 
threeway <- do.call(rbind,threeway) 
threeway <- threeway[threeway[,9]<5,-9] #remove combos with no effect 
write.csv(threeway,'~/Desktop/threeway.csv',row.names=FALSE) 
+1

(+1) अच्छा प्रतिक्रिया। एक उपयोगी उत्तर के लिए – chl

+0

+1, लेकिन प्रत्येक संयोजन वास्तव में काम करने वाले औषधि व्यंजनों को खोजने का एक प्रभावी तरीका उत्पन्न कर रहा है? –

+0

@ डेविड बी: आपको क्या लगता है कि एक और अधिक कुशल दृष्टिकोण होगा? – Zach

4

यहां कुछ सी # है।

यह संभावित प्रभावों के नाम से घटक का एक दृश्य बनाता है। फिर यह उस नुस्खा का उपयोग यह निर्धारित करने के लिए करता है कि कौन से तत्व वर्तमान नुस्खा से मेल खाते हैं। अंत में, यह व्यंजनों को उत्पन्न करता है और डुप्लिकेट को त्याग देता है क्योंकि यह उन्हें हैशसेट का उपयोग करके उत्पन्न करता है।

पूरा कोड (अधूरा संघटक सूची)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Combinations 
{ 

    public class Ingredient 
    { 
     public List<string> Effects { get; set; } 
     public string Name { get; set; } 
     public Ingredient(string name, params string[] effects) 
     { Name = name; Effects = new List<string>(effects); } 
    } 

    public class Recipe 
    { 
     public List<Ingredient> Ingredients {get;set;} 
     public Recipe(IEnumerable<Ingredient> ingredients) 
     { Ingredients = ingredients.OrderBy(x => x.Name).ToList(); } 
     public override string ToString() 
     { return string.Join("|", Ingredients.Select(x => x.Name).ToArray()); } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Ingredient> source = GetIngredients(); 

      ILookup<string, Ingredient> byEffect = (
       from i in source 
       from e in i.Effects 
       select new { i, e } 
       ).ToLookup(x => x.e, x => x.i); 

      List<Recipe> oneIng = source.Select(x => new Recipe(new Ingredient[] { x })).ToList(); 
      List<Recipe> twoIng = oneIng.SelectMany(r => GenerateRecipes(r, byEffect)).ToList(); 
      List<Recipe> threeIng = twoIng.SelectMany(r => GenerateRecipes(r, byEffect)).ToList(); 

      Console.WriteLine(twoIng.Count); 
      foreach(Recipe r in twoIng) { Console.WriteLine(r); } 
      Console.WriteLine(threeIng.Count); 
      foreach(Recipe r in threeIng) { Console.WriteLine(r); } 
      Console.ReadLine(); 
     } 

     static IEnumerable<Recipe> GenerateRecipes(Recipe recipe, ILookup<string, Ingredient> byEffect) 
     { 
      IEnumerable<string> knownEffects = recipe.Ingredients 
       .SelectMany(i => i.Effects) 
       .Distinct(); 

      IEnumerable<Ingredient> matchingIngredients = knownEffects 
       .SelectMany(e => byEffect[e]) 
       .Distinct() 
       .Where(i => !recipe.Ingredients.Contains(i)); 

      foreach(Ingredient i in matchingIngredients) 
      { 
       List<Ingredient> newRecipeIngredients = recipe.Ingredients.ToList(); 
       newRecipeIngredients.Add(i); 
       Recipe result = new Recipe(newRecipeIngredients); 
       string key = result.ToString(); 
       if (!_observedRecipes.Contains(key)) 
       { 
        _observedRecipes.Add(key); 
        yield return result; 
       } 
      } 
     } 

     static HashSet<string> _observedRecipes = new HashSet<string>(); 

     static List<Ingredient> GetIngredients() 
     { 
      List<Ingredient> result = new List<Ingredient>() 
      { 
       new Ingredient("Abecean Longfin", "Weakness to Frost", "Fortify Sneak", "Weakness to Poison", "Fortify Restoration"), 
       new Ingredient("Bear Claws", "Restore Stamina", "Fortify Health", "Fortify One-handed", "Damage Magicka Regen"), 
       new Ingredient("Bee", "Restore Stamina", "Ravage Stamina", "Regenerate Stamina", "Weakness to Shock"), 
       new Ingredient("Beehive Husk", "Resist Poison", "Fortify Light Armor", "Fortify Sneak", "Fortify Destruction"), 
       new Ingredient("Bleeding Crown", "Weakness to Fire", "Fortify Block", "Weakness to Poison", "Resist Magic"), 
       new Ingredient("Blisterwort", "Damage Stamina", "Frenzy", "Restore Health", "Fortify Smithing"), 
       new Ingredient("Blue Butterfly Wing", "Damage Stamina", "Fortify Conjuration", "Damage Magicka Regen", "Fortify Enchanting"), 
       new Ingredient("Blue Dartwing", "Resist Shock", "Fortify Pickpocket", "Restore Health", "Damage Magicka Regen"), 
       new Ingredient("Blue Mountain Flower", "Restore Health", "Fortify Conjuration", "Fortify Health", "Damage Magicka Regen"), 
       new Ingredient("Bone Meal", "Damage Stamina", "Resist Fire", "Fortify Conjuration", "Ravage Stamina"), 
      }; 

      return result; 
     } 
    } 
} 
1

इसलिए मैंने सोचा कि, था "क्या सबसे अधिक लागत प्रभावी तरीका सभी घटक ज्ञान हासिल करने है?" यानी मैं चाहता हूं कि सभी अवयवों के प्रभाव खेल में ज्ञात हों, लेकिन मैं बारह दादरा दिल को ऐसा करने के लिए नहीं बिताना चाहता हूं।

यदि आप पारंपरिक खोज समाधान (ए *, आदि) का उपयोग करते हैं तो शाखाकरण कारक भयानक है (22000ish संभावित प्रभावी औषधि हैं)। मैंने एक एनीलिंग दृष्टिकोण की कोशिश की लेकिन अच्छे नतीजे नहीं मिल रहे थे। मैं अंत में एक सूचित खोज के साथ चला गया; यह उपनिवेश है लेकिन यह काम पूरा हो जाएगा।

यहाँ आयात और combinatorize कोड है: कहते हैं "सामग्री आयात कर रहा है ..."

fd = File::open('ingr_weighted.txt', 'r') 
dbtext = fd.read 
fd.close 
ingredients = [] 
cvg = [] 
id = 0 
dbtext.each_line { |line| 
    infos = line.split("\t") 
    ingredients << {:id => id, :name => infos[0], :effects => [infos[2],infos[3],infos[4],infos[5]], 
        :eff1 => infos[2], :eff2 => infos[3], :eff3 => infos[4], :eff4 => infos[5], 
        :weight => infos[6], :cost => infos[7].to_i+1} 
    id += 1 
    cvg << [false, false, false, false] 
} 


puts "Building potions..." 
potions = [] 
id = 0 
for a in 0..ingredients.length-2 
    for b in a+1..ingredients.length-1 
     # First try two-ingredient potions 
     uses = ingredients[a][:effects] & ingredients[b][:effects] 
     cost = ingredients[a][:cost] + ingredients[b][:cost] 
     if (uses.length > 0) 
      coverage = [ingredients[a][:effects].map{|x| uses.include? x}, 
         ingredients[b][:effects].map{|x| uses.include? x}] 
      potions << {:id => id, :effects => uses, :coverage => coverage, :ingredients => [a, b], :cost => cost} 
      id = id + 1 
     end 
     # Next create three-ingredient potions 
     for c in b+1..ingredients.length-1 
      uses = ingredients[a][:effects] & ingredients[b][:effects] | 
        ingredients[a][:effects] & ingredients[c][:effects] | 
        ingredients[b][:effects] & ingredients[c][:effects] 
      cost = ingredients[a][:cost] + ingredients[b][:cost] + ingredients[c][:cost] 
      if (uses.length > 0) 
       coverage = [ingredients[a][:effects].map{|x| uses.include? x}, 
          ingredients[b][:effects].map{|x| uses.include? x}, 
          ingredients[c][:effects].map{|x| uses.include? x}] 
       # Prune potions that contain a superfluous ingredient 
       if (coverage.inject(true) { |cum, cvgn| 
              cum = cum && cvgn.inject { |cum2,ef| cum2 = cum2 || ef} 
              }) 
        potions << {:id => id, :effects => uses, :coverage => coverage, :ingredients => [a,b,c], :cost => cost} 
        id = id + 1 
       end 
      end 
     end 
    end 
end 
# 22451 
puts "#{potions.count} potions generated!" 
puts "Searching..." 

इनपुट फ़ाइल कॉपी-pasta'd विकिज़ में से एक से है, तो आप उपयोग कर रहे हैं एक मोड या कुछ जो आप सीधे छोड़ सकते हैं। यहां से आपके पास सभी डेटा आयात किए गए हैं और प्रभावी औषधि उत्पन्न हुई हैं, इसलिए आप जो चाहते हैं वह करें!

मेरे मूल उद्देश्य (कुशल "सीखने") के लिए, मैंने निम्नलिखित कोड का उपयोग किया। असल में यह सबसे महंगा शेष घटक के साथ शुरू होता है, जितना संभव हो उतना सस्ता प्रभाव पड़ता है, फिर नीचे चला जाता है। कुछ दुर्लभ तत्व सस्ते होते हैं (विदेशी मुद्रा। मानव मांस), इसलिए मैंने अपनी डेटा फ़ाइल कृत्रिम रूप से उनके मूल्य को बढ़ाने के लिए "बंद" की। सभी से कहा इस कार्यक्रम अपने लैपटॉप पर 45 मिनट में चलता है, लेकिन यह एक व्याख्या की भाषा है ...

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