Changeset - 71732f305328
[Not reviewed]
default
8 7 0
Jason Maltzen (jmaltzen) - 9 years ago 2015-12-26 03:04:25
jason.maltzen@unsanctioned.net
Pre-allocate a bunch of map entries, given that we know there are a fixed set of colors. Use fixed arrays in places where maps/sets were excessive. Switch away from using Gtk.Application.Invoke, which leaks a bunch of memory.
15 files changed with 262 insertions and 556 deletions:
0 comments (0 inline, 0 general)
DesertPaintLab.csproj
Show inline comments
...
 
@@ -67,17 +67,19 @@
 
    <Compile Include="gtk-gui\DesertPaintLab.SelectProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.NewProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.PaintSwatch.cs" />
 
    <Compile Include="SimulatorWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.SimulatorWindow.cs" />
 
    <Compile Include="ScreenCheckDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ScreenCheckDialog.cs" />
 
    <Compile Include="FileUtils.cs" />
 
    <Compile Include="PaintRecipe.cs" />
 
    <Compile Include="PaintRecipe.cs">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </Compile>
 
    <Compile Include="ReactionRecorder.cs" />
 
    <Compile Include="ReactionStatusWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ReactionStatusWindow.cs" />
 
    <Compile Include="RecipeGeneratorWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.RecipeGeneratorWindow.cs" />
 
    <Compile Include="ReactionSet.cs" />
 
    <Compile Include="RecipeGenerator.cs" />
 
    <Compile Include="ReagentWindow.cs" />
...
 
@@ -90,9 +92,21 @@
 
        <Policies>
 
          <TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
 
          <CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
 
        </Policies>
 
        <GtkDesignInfo generateGettext="False" />
 
      </Properties>
 
    </MonoDevelop>
 
  </ProjectExtensions>
 
  <ItemGroup>
 
    <None Include="data\colors.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\ingredients.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\template\dp_reactions.txt">
 
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 
    </None>
 
    <None Include="data\template\ingredients.txt" />
 
  </ItemGroup>
 
</Project>
...
 
\ No newline at end of file
PaintRecipe.cs
Show inline comments
...
 
@@ -39,16 +39,27 @@ namespace DesertPaintLab
 
            public string name;
 
            public uint quantity;
 

	
 
            public RecipeIngredient(string name, uint quantity)
 
            {
 
                this.name = name;
 
                this.quantity = quantity;
 
            }
 

	
 
            public RecipeIngredient(RecipeIngredient other)
 
            {
 
                this.name = other.name;
 
                this.quantity = other.quantity;
 
            }
 

	
 
            public override string ToString()
 
            {
 
                return String.Format("{0} {1}", name, quantity);
 
            }
 
        };
 

	
 
        private List<RecipeIngredient> recipe = new List<RecipeIngredient>();
 
        private List<string> reagents = new List<string>();
 

	
 
        private bool dirty = false;
 
        private PaintColor reactedColor = new PaintColor();
 
        private PaintColor baseColor = new PaintColor();
...
 
@@ -63,17 +74,34 @@ namespace DesertPaintLab
 
            this.dirty = true;
 
            this.reactions = other.reactions;
 
            foreach (string reagentName in other.reagents)
 
            {
 
                this.reagents.Add(reagentName);
 
            }
 
            foreach (RecipeIngredient copyIngredient in other.recipe)
 
            {
 
                RecipeIngredient ingredient = new RecipeIngredient(copyIngredient.name, copyIngredient.quantity);
 
                RecipeIngredient ingredient = new RecipeIngredient(copyIngredient);
 
                this.recipe.Add(ingredient);
 
            }
 
        }
 

	
 
        public void CopyFrom(PaintRecipe other)
 
        {
 
            this.dirty = true;
 
            this.reactions = other.reactions;
 
            this.reagents.Clear();
 
            foreach (string reagentName in other.reagents)
 
            {
 
                this.reagents.Add(reagentName);
 
            }
 
            this.recipe.Clear();
 
            foreach (RecipeIngredient otherIngredient in other.recipe)
 
            {
 
                RecipeIngredient ingredient = new RecipeIngredient(otherIngredient);
 
                this.recipe.Add(ingredient);
 
            }
 
        }
 

	
 
        public List<RecipeIngredient> Ingredients
 
        {
 
            get {
 
                return recipe;
PlayerProfile.cs
Show inline comments
...
 
@@ -54,16 +54,21 @@ namespace DesertPaintLab
 
        }
 
		
 
		public PlayerProfile(string name, string directory)
 
		{
 
			this.name = name;
 
			this.directory = directory;
 
			this.reactFile = System.IO.Path.Combine(directory, "dp_reactions.txt");
 
            this.reagentFile = System.IO.Path.Combine(directory, "ingredients.txt");
 
            this.recipes = new SortedDictionary<string, PaintRecipe>();
 
            foreach (PaintColor color in Palette.Colors)
 
            {
 
                this.recipes.Add(color.Name, new PaintRecipe());
 
            }
 
		}
 

 
        public string Directory
 
        {
 
            get {
 
                return this.directory;
 
            }
 
        }
...
 
@@ -84,16 +89,31 @@ namespace DesertPaintLab
 

 
        public SortedDictionary<string, PaintRecipe> Recipes
 
        {
 
            get {
 
                return this.recipes;
 
            }
 
        }
 
		
 
        public int RecipeCount
 
        {
 
            get {
 
                int count = 0;
 
                foreach (PaintRecipe recipe in this.recipes.Values)
 
                {
 
                    if (recipe.IsValid)
 
                    {
 
                        ++count;
 
                    }
 
                }
 
                return count;
 
            }
 
        }
 
		
 
		public void Initialize()
 
		{
 
			// Create new directory.
 
			System.IO.Directory.CreateDirectory(directory);
 
				
 
			// Copy template files into new directory.
 
			string templatePath = FileUtils.FindApplicationResourceDirectory("template");
 
			
...
 
@@ -313,55 +333,58 @@ namespace DesertPaintLab
 
    					}
 
    				}
 
    			}
 
            }
 
		}
 

 
        public void LoadRecipes()
 
        {
 
            this.recipes = new SortedDictionary<string, PaintRecipe>();
 
            foreach (PaintRecipe recipe in this.recipes.Values)
 
            {
 
                recipe.Clear();
 
            }
 
            string recipeFile = System.IO.Path.Combine(directory, "dp_recipes.txt");
 
            string line;
 
            Match match;
 
            bool inRecipe = false;
 
            PaintRecipe recipe = null;
 
            PaintRecipe testRecipe = new PaintRecipe();
 
            testRecipe.Reactions = reactions;
 
            string currentRecipeColor = null;
 
            if (File.Exists(recipeFile))
 
            {
 
                using (StreamReader reader = new StreamReader(recipeFile))
 
                {
 
                    while ((line = reader.ReadLine()) != null) 
 
                    {
 
                        match = recipeHeaderRegex.Match(line); 
 
                        if (match.Success)
 
                        {
 
                            if (recipe != null && currentRecipeColor != null)
 
                            if (testRecipe != null && currentRecipeColor != null)
 
                            {
 
                                recipes.Add(currentRecipeColor, recipe);
 
                                recipes[currentRecipeColor].CopyFrom(testRecipe);
 
                            }
 
                            recipe = new PaintRecipe();
 
                            recipe.Reactions = reactions;
 
                            testRecipe.Clear();
 
                            currentRecipeColor = match.Groups["colorname"].Value;
 
                            inRecipe = true;
 
                        }
 
                        else if (inRecipe)
 
                        {
 
                            match = recipeIngredientRegex.Match(line);
 
                            if (match.Success)
 
                            {
 
                                string ingredient = match.Groups["ingredient"].Value;
 
                                uint quantity = uint.Parse(match.Groups["quantity"].Value);
 
                                recipe.AddReagent(ingredient, quantity);
 
                                testRecipe.AddReagent(ingredient, quantity);
 
                            }
 
                        }
 
                    }
 
                    if (inRecipe)
 
                    {
 
                        recipes.Add(currentRecipeColor, recipe);
 
                        recipes[currentRecipeColor].CopyFrom(testRecipe);
 
                    }
 
                }
 
            }
 
        }
 

 
        public void SaveRecipes()
 
        {
 
            if (recipes != null)
...
 
@@ -398,17 +421,17 @@ namespace DesertPaintLab
 
                        // dark color gets light text
 
                        colorLine += " color: #FFFFFF;";
 
                    }
 
                    colorLine += "\" | " + color.Name + " || ";
 
                    if (recipes.TryGetValue(color.Name, out recipe))
 
                    {
 
                        foreach (PaintRecipe.RecipeIngredient ingredient in recipe.Ingredients)
 
                        {
 
                            colorLine += " " + ingredient.name + " " + ingredient.quantity.ToString();
 
                            colorLine += " " + ingredient.ToString();
 
                        }
 
                    } 
 
                    else
 
                    {
 
                        // no recipe
 
                    }
 
                    colorLine += " || ";
 
                    writer.WriteLine(colorLine);
...
 
@@ -425,13 +448,13 @@ namespace DesertPaintLab
 
		public void SetReaction(Reagent reagent1, Reagent reagent2, Reaction reaction)
 
		{
 
            reactions.Set(reagent1, reagent2, reaction);
 
		}
 

 
        public void SetRecipe(PaintRecipe recipe)
 
        {
 
            string colorName = Palette.FindNearest(recipe.ReactedColor);
 
            recipes[colorName] = recipe;
 
            recipes[colorName].CopyFrom(recipe);
 
        }
 
	}
 
}
 

RecipeGenerator.cs
Show inline comments
...
 
@@ -55,26 +55,35 @@ namespace DesertPaintLab
 
        }
 
    }
 

	
 
    public class RecipeGenerator
 
    {
 
        protected class SearchNode
 
        {
 
            //int initialReagentCount;
 
            List<uint> reagents;
 
            public List<uint> Reagents
 
            uint[] reagents;
 
            public uint[] Reagents
 
            {
 
                get
 
                {
 
                    return reagents;
 
                }
 
            }
 
            uint INVALID_REAGENT;
 
            int nextReagentPos;
 
            public int ReagentCount
 
            {
 
                get
 
                {
 
                    return nextReagentPos;
 
                }
 
            }
 

	
 
            HashSet<uint> reagentInUse = new HashSet<uint>();
 
            bool[] reagentInUse;
 
            List<Reagent> costSortedReagents;
 
            PaintRecipe testRecipe = null;
 
            public PaintRecipe TestRecipe
 
            {
 
                get
 
                {
 
                    return testRecipe;
 
                }
...
 
@@ -108,118 +117,163 @@ namespace DesertPaintLab
 
            public uint[] CurrentWeights
 
            {
 
                get
 
                {
 
                    return currentWeights;
 
                }
 
            }
 

	
 
            public SearchNode(List<Reagent> costSortedReagents, List<uint> reagents)
 
            public SearchNode(List<Reagent> costSortedReagents, uint[] reagents)
 
            {
 
                this.costSortedReagents = new List<Reagent>(costSortedReagents);
 
                this.reagents = new List<uint>(reagents);
 
                foreach (uint reagentIdx in reagents)
 
                this.reagents = new uint[costSortedReagents.Count];
 
                INVALID_REAGENT = (uint)costSortedReagents.Count;
 
                nextReagentPos = reagents.Length;
 
                for (int i = this.reagents.Length-1; i >= this.reagents.Length; --i)
 
                {
 
                    reagents[i] = INVALID_REAGENT;
 
                }
 
                for (int i = reagents.Length-1; i >= 0; --i)
 
                {
 
                    this.reagents[i] = reagents[i];
 
                    if (reagents[i] == INVALID_REAGENT)
 
                {
 
                    reagentInUse.Add(reagentIdx);
 
                        nextReagentPos = i;
 
                    }
 
                }
 
                reagentInUse = new bool[costSortedReagents.Count];
 
                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
 
                {
 
                    reagentInUse[reagentIdx] = false;
 
                }
 
                InitialCount = this.reagents.Count;
 
                MaxReagents = (uint)this.reagents.Count; // better set this later!
 
                foreach (uint reagentIdx in this.reagents)
 
                {
 
                    if (reagentIdx != INVALID_REAGENT)
 
                    {
 
                        reagentInUse[reagentIdx] = true;
 
                    }
 
                }
 
                InitialCount = nextReagentPos;
 
                MaxReagents = (uint)nextReagentPos; // better set this later!
 
                UsedQuantity = 0;
 
            }
 

	
 
            // top-level search
 
            public SearchNode(List<Reagent> costSortedReagents, uint startReagent)
 
            {
 
                this.costSortedReagents = new List<Reagent>(costSortedReagents);
 
                this.reagents = new List<uint>();
 
                this.reagents.Add(NextFreeReagent(startReagent));
 
                this.reagents = new uint[costSortedReagents.Count];
 
                INVALID_REAGENT = (uint)costSortedReagents.Count;
 
                nextReagentPos = 0;
 
                for (int i = 0; i < reagents.Length; ++i)
 
                {
 
                    this.reagents[i] = INVALID_REAGENT;
 
                }
 
                reagentInUse = new bool[costSortedReagents.Count];
 
                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
 
                {
 
                    reagentInUse[reagentIdx] = false;
 
                }
 
                this.reagents[nextReagentPos++] = NextFreeReagent(startReagent);
 
                InitialCount = 1; // don't iterate up beyond the start reagent
 
                MaxReagents = 1;
 
                UsedQuantity = 0;
 
            }
 

	
 
            public SearchNode(List<Reagent> costSortedReagents)
 
            {
 
                this.costSortedReagents = costSortedReagents;
 
                this.reagents = new List<uint>();
 
                this.reagents.Add(NextFreeReagent(0));
 
                this.reagents = new uint[costSortedReagents.Count];
 
                INVALID_REAGENT = (uint)costSortedReagents.Count;
 
                nextReagentPos = 0;
 
                for (int i = 0; i < reagents.Length; ++i)
 
                {
 
                    this.reagents[i] = INVALID_REAGENT;
 
                }
 
                reagentInUse = new bool[costSortedReagents.Count];
 
                for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
 
                {
 
                    reagentInUse[reagentIdx] = false;
 
                }
 
                this.reagents[nextReagentPos++] = NextFreeReagent(0);
 
                InitialCount = 0;
 
                MaxReagents = 1;
 
                UsedQuantity = 0;
 
            }
 

	
 
            public Reagent Reagent(int idx)
 
            {
 
                return costSortedReagents[(int)reagents[idx]];
 
            }
 

	
 
            public uint LastReagent
 
            {
 
                get
 
                {
 
                    return reagents[reagents.Count - 1];
 
                    return reagents[nextReagentPos - 1];
 
                }
 
            }
 

	
 
            public void RemoveLastReagent()
 
            {
 
                uint reagentIdx = reagents[reagents.Count-1];
 
                uint reagentIdx = reagents[nextReagentPos-1];
 
                ReleaseReagent(reagentIdx);
 
                if (costSortedReagents[(int)reagentIdx].IsCatalyst)
 
                {
 
                    --CatalystCount;
 
                }
 
                reagents.RemoveAt(reagents.Count-1);
 
                reagents[nextReagentPos-1] = INVALID_REAGENT;
 
                --nextReagentPos;
 
            }
 

	
 
            public void ReplaceLastReagent(uint reagentIdx)
 
            {
 
                uint oldReagentIdx = reagents[reagents.Count-1];
 
                uint oldReagentIdx = reagents[nextReagentPos-1];
 
                ReleaseReagent(oldReagentIdx);
 
                reagents[reagents.Count-1] = reagentIdx;
 
                reagents[nextReagentPos-1] = reagentIdx;
 
                if (costSortedReagents[(int)oldReagentIdx].IsCatalyst)
 
                {
 
                    --CatalystCount;
 
                }
 
                if (costSortedReagents[(int)reagentIdx].IsCatalyst)
 
                {
 
                    ++CatalystCount;
 
                }
 
            }
 

	
 
            public uint NextFreeReagent(uint startIdx)
 
            {
 
                uint idx = startIdx;
 
                for (; idx < costSortedReagents.Count; ++idx)
 
                {
 
                    bool inUse = reagentInUse.Contains(idx);
 
                    bool inUse = reagentInUse[idx];
 
                    if (inUse == false)
 
                    {
 
                        //Console.WriteLine("Found free reagent idx {0}", idx);
 
                        reagentInUse.Add(idx);
 
                        reagentInUse[idx] = true;
 
                        return idx;
 
                    }
 
                }
 
                //Console.WriteLine("Failed to find free reagent.");
 
                return (uint)costSortedReagents.Count;
 
            }
 
    
 
            private void ReleaseReagent(uint reagentIdx)
 
            {
 
                reagentInUse.Remove(reagentIdx);
 
                reagentInUse[reagentIdx] = false;
 
            }
 
    
 
            public bool AddNextReagent()
 
            {
 
                bool ok = (reagents.Count < MaxReagents);
 
                bool ok = (nextReagentPos < MaxReagents);
 
                if (ok)
 
                {
 
                    uint nextReagent = NextFreeReagent(0);
 
                    reagents.Add(nextReagent);
 
                    reagents[nextReagentPos++] = nextReagent;
 
                    if (costSortedReagents[(int)nextReagent].IsCatalyst)
 
                    {
 
                        ++CatalystCount;
 
                    }
 
                    InitForQuantity(CurrentTargetQuantity);
 
                }
 
                return ok;
 
            }
...
 
@@ -228,19 +282,19 @@ namespace DesertPaintLab
 
            {
 
                //System.Console.WriteLine("Target quantity: {0}, reagent count: {1}", quantity, reagents.Count);
 
                CurrentTargetQuantity = quantity;
 
                if (CurrentTargetQuantity < (10 + CatalystCount))
 
                {
 
                    return;
 
                }
 
                UsedQuantity = 0;
 
                uint remainingReagents = ((uint)reagents.Count - CatalystCount);
 
                uint remainingReagents = ((uint)nextReagentPos - CatalystCount);
 
                uint remainingWeight = CurrentTargetQuantity - CatalystCount;
 
                for (int i = 0; i < reagents.Count; ++i)
 
                for (int i = 0; i < nextReagentPos; ++i)
 
                {
 
                    Reagent reagent = Reagent(i);
 
    
 
                    if (reagent.IsCatalyst)
 
                    {
 
                        currentWeights[i] = 1;
 
                        ++UsedQuantity;
 
                    }
...
 
@@ -261,22 +315,22 @@ namespace DesertPaintLab
 
                currentWeights[idx] = quantity;
 
                UsedQuantity += quantity;
 
            }
 

	
 
            public void SaveState(StreamWriter writer)
 
            {
 
                writer.WriteLine("---SearchNode---");
 
                writer.WriteLine("MaxReagents: {0}", MaxReagents);
 
                writer.WriteLine("Reagents: {0}", reagents.Count);
 
                for (int i = 0; i < reagents.Count; ++i)
 
                writer.WriteLine("Reagents: {0}", nextReagentPos);
 
                for (int i = 0; i < nextReagentPos; ++i)
 
                {
 
                    uint idx = reagents[i];
 
                    uint weight = currentWeights[i];
 
                    writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse.Contains(idx) ? 1 : 0, weight);
 
                    writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse[idx] ? 1 : 0, weight);
 
                }
 
                // pulled from parent: List<Reagent> costSortedReagents;
 
                // new on construct: PaintRecipe testRecipe = null;
 
                writer.WriteLine("CurrentTargetQuantity: {0}", CurrentTargetQuantity);
 
                writer.WriteLine("MaxQuantity: {0}", MaxQuantity);
 
                writer.WriteLine("UsedQuantity: {0}", UsedQuantity);
 
                writer.WriteLine("CatalystCount: {0}", CatalystCount);
 
                writer.WriteLine("InitialCount: {0}", InitialCount);
...
 
@@ -291,50 +345,53 @@ namespace DesertPaintLab
 
                string line = reader.ReadLine();
 
                if (!line.Equals("---SearchNode---"))
 
                {
 
                    return false;
 
                }
 

	
 
                bool success = true;
 
                Match match;
 
                int reagentIdx = 0;
 
                while ((line = reader.ReadLine()) != null)
 
                {
 
                    if (line.Equals("---EndNode---"))
 
                    {
 
                        break;
 
                    }
 
                    match = keyValueRegex.Match(line);
 
                    if (match.Success)
 
                    {
 
                        switch (match.Groups[1].Value)
 
                        {
 
                            case "Reagents":
 
                                {
 
                                    int reagentCount = int.Parse(match.Groups[2].Value);
 
                                    reagents = new List<uint>(reagentCount);
 
                                    reagentInUse.Clear();
 
                                    reagentIdx = 0;
 
                                    //int reagentCount = int.Parse(match.Groups[2].Value);
 
                                    for (int i = 0; i < reagents.Length; ++i)
 
                                    {
 
                                        reagents[i] = INVALID_REAGENT;
 
                                        reagentInUse[i] = false;
 
                                    }
 
                                    nextReagentPos = 0;
 
                                }
 
                                break;
 
                            case "Reagent":
 
                                {
 
                                    Match reagentInfo = reagentPartsRegex.Match(match.Groups[2].Value);
 
                                    if (reagentInfo.Success)
 
                                    {
 
                                        uint reagentId = uint.Parse(reagentInfo.Groups["id"].Value);
 
                                        int isInUse = int.Parse(reagentInfo.Groups["inUse"].Value);
 
                                        uint weight = uint.Parse(reagentInfo.Groups["weight"].Value);
 
                                        reagents.Add(reagentId);
 
                                        currentWeights[reagentIdx] = weight;
 
                                        reagents[nextReagentPos] = reagentId;
 
                                        currentWeights[nextReagentPos] = weight;
 
                                        if (isInUse != 0)
 
                                        {
 
                                            reagentInUse.Add(reagentId);
 
                                            reagentInUse[reagentId] = true;
 
                                        }
 
                                        ++nextReagentPos;
 
                                    }
 
                                    else
 
                                    {
 
                                        success = false;
 
                                    }
 
                                }
 
                                break;
 
                            case "CurrentTargetQuantity":
...
 
@@ -420,16 +477,21 @@ namespace DesertPaintLab
 
        // events
 
        public event EventHandler Finished;
 
        public event EventHandler Progress;
 
        public event EventHandler<NewRecipeEventArgs> NewRecipe;
 

	
 
        public RecipeGenerator(ReactionSet reactions)
 
        {
 
            this.reactions = reactions;
 
            foreach (PaintColor color in Palette.Colors)
 
            {
 
                recipes.Add(color.Name, new PaintRecipe());
 
                recipeCosts.Add(color.Name, uint.MaxValue);
 
            }
 
        }
 

	
 
        public SortedDictionary<string, PaintRecipe> Recipes
 
        {
 
            get
 
            {
 
                return recipes;
 
            }
...
 
@@ -454,26 +516,26 @@ namespace DesertPaintLab
 
        private class ReagentCostSort : IComparer<Reagent>
 
        {
 
            public int Compare(Reagent reagent1, Reagent reagent2)
 
            {
 
                return (int)reagent1.Cost - (int)reagent2.Cost;
 
            }
 
        }
 

	
 
        public void InitRecipes(SortedDictionary<string, PaintRecipe> recipes)
 
        public void InitRecipes(SortedDictionary<string, PaintRecipe> initialRecipes)
 
        {
 
            if (running)
 
            {
 
                return;
 
            }
 
            foreach (PaintRecipe recipe in recipes.Values)
 
            foreach (PaintRecipe recipe in initialRecipes.Values)
 
            {
 
                PaintRecipe recipeCopy = new PaintRecipe(recipe);
 
                AddCheapestRecipe(recipeCopy);
 
                //PaintRecipe recipeCopy = new PaintRecipe(recipe);
 
                AddCheapestRecipe(recipe);
 
            }
 
        }
 

	
 
        private void InitSortedReagents()
 
        {
 
            costSortedReagents.Clear();
 
            foreach (string name in ReagentManager.Names)
 
            {
...
 
@@ -503,22 +565,23 @@ namespace DesertPaintLab
 
            InitSortedReagents();
 
            this.maxReagents = (uint)Math.Min(costSortedReagents.Count, this.maxReagents);
 

	
 
            totalReagents = (uint)costSortedReagents.Count;
 

	
 
            // Pre-populate recipes list with:
 
            // 1) 1-ingredient recipes @ 10db for all enabled ingredients with a count >= 10
 
            // 2) any previously-generated recipes
 
            PaintRecipe recipe = new PaintRecipe();
 
            recipe.Reactions = reactions;
 
            foreach (Reagent reagent in costSortedReagents)
 
            {
 
                if (!reagent.IsCatalyst && reagent.RecipeMax >= 10)
 
                {
 
                    PaintRecipe recipe = new PaintRecipe();
 
                    recipe.Reactions = reactions;
 
                    recipe.Clear();
 
                    recipe.AddReagent(reagent.Name, 10);
 
                    AddCheapestRecipe(recipe);
 
                }
 
            }
 

	
 
            while (!searchQueue.IsEmpty)
 
            {
 
                SearchNode node;
...
 
@@ -757,19 +820,18 @@ namespace DesertPaintLab
 
                {
 
                    Finished(this, null);
 
                }
 
            }
 
        }
 

	
 
        // Add the cheapest recipe to the recipe list
 
        // returns the discarded recipe from the pair (or null if no original recipe to replace)
 
        private PaintRecipe AddCheapestRecipe(PaintRecipe recipe)
 
        private void AddCheapestRecipe(PaintRecipe recipe)
 
        {
 
            PaintRecipe discarded = recipe;
 
            if (recipe.IsValid)
 
            {
 
                recipe.Reactions = reactions;
 

	
 
                string colorName = Palette.FindNearest(recipe.ReactedColor);
 
                //System.Console.WriteLine("Recipe: {0} {1}:", colorName, recipe.Cost);
 
                //foreach (PaintRecipe.RecipeIngredient ingr in recipe.Ingredients)
 
                //{
...
 
@@ -777,31 +839,30 @@ namespace DesertPaintLab
 
                //}
 
                uint cost;
 
                lock (workerLock)
 
                {
 
                    if (recipeCosts.TryGetValue(colorName, out cost))
 
                    {
 
                        if (cost > recipe.Cost)
 
                        {
 
                            discarded = recipes[colorName];
 
                            recipes[colorName].CopyFrom(recipe);
 
                            recipeCosts[colorName] = recipe.Cost;
 
                            recipes[colorName] = recipe;
 
                            if (NewRecipe != null)
 
                            {
 
                                NewRecipeEventArgs args = new NewRecipeEventArgs(colorName, recipe);
 
                                NewRecipe(this, args);
 
                            }
 
                        }
 
                    }
 
                    else
 
                    {
 
                        discarded = null;
 
                        // This would be an error!
 
                        recipeCosts.Add(colorName, recipe.Cost);
 
                        recipes.Add(colorName, recipe);
 
                        recipes.Add(colorName, new PaintRecipe(recipe));
 
                        if (NewRecipe != null)
 
                        {
 
                            NewRecipeEventArgs args = new NewRecipeEventArgs(colorName, recipe);
 
                            NewRecipe(this, args);
 
                        }
 
                    }
 
                }
 
            }
...
 
@@ -811,18 +872,16 @@ namespace DesertPaintLab
 
            //    foreach (PaintRecipe.RecipeIngredient ingr in recipe.Ingredients)
 
            //    {
 
            //        msg += String.Format("    -> {0} {1}", ingr.quantity, ingr.name);
 
            //    }
 
            //    lock (workerLock) {
 
            //        Console.WriteLine(msg);
 
            //    }
 
            //}
 
            
 
            return discarded;
 
        }
 

	
 
        private bool Iterate(SearchNode node)
 
        {
 
            // pick recipe quantities at current recipe ingredients/size
 
            if (NextRecipe(node))
 
            {
 
                lock(workerLock)
...
 
@@ -840,36 +899,36 @@ namespace DesertPaintLab
 
            }
 

	
 
            // Search for next ingredient combo - all quantity combos for previous were searched
 
            //System.Console.WriteLine("Finding next ingredient combo");
 
            do
 
            {
 
                if (!node.AddNextReagent())
 
                {
 
                    while ((node.Reagents.Count > node.InitialCount) && (node.LastReagent == (totalReagents-1)))
 
                    while ((node.ReagentCount > node.InitialCount) && (node.LastReagent == (totalReagents-1)))
 
                    {
 
                        node.RemoveLastReagent();
 
                    }
 
                    if (node.Reagents.Count == node.InitialCount)
 
                    if (node.ReagentCount == node.InitialCount)
 
                    {
 
                        // done
 
                        return false;
 
                    }
 
                    uint nextReagent = node.NextFreeReagent(node.LastReagent);
 
                    while ((node.Reagents.Count > node.InitialCount) && (nextReagent >= totalReagents))
 
                    while ((node.ReagentCount > node.InitialCount) && (nextReagent >= totalReagents))
 
                    {
 
                        // No more reagents to try at this level
 
                        node.RemoveLastReagent();
 
                        if (node.Reagents.Count > node.InitialCount)
 
                        if (node.ReagentCount > node.InitialCount)
 
                        {
 
                            nextReagent = node.NextFreeReagent(node.LastReagent);
 
                        }
 
                    }
 
                    if (node.Reagents.Count == node.InitialCount)
 
                    if (node.ReagentCount == node.InitialCount)
 
                    {
 
                        // done
 
                        return false;
 
                    }
 
                    node.ReplaceLastReagent(nextReagent);
 
                }
 
            } while (node.MaxQuantity < (10 + node.CatalystCount));
 
            node.InitForQuantity(node.MaxQuantity);
...
 
@@ -892,41 +951,32 @@ namespace DesertPaintLab
 
        {
 
            // First, run the current recipe
 
            if (node.TestRecipe == null)
 
            {
 
                node.TestRecipe = new PaintRecipe();
 
                node.TestRecipe.Reactions = reactions;
 
            }
 
            node.TestRecipe.Clear();
 
            for (int i = 0; i < node.Reagents.Count; ++i)
 
            for (int i = 0; i < node.ReagentCount; ++i)
 
            {
 
                node.TestRecipe.AddReagent(node.Reagent(i).Name, node.CurrentWeights[i]);
 
            }
 
            PaintRecipe replacement = AddCheapestRecipe(node.TestRecipe);
 
            if (replacement == null)
 
            {
 
                node.TestRecipe = new PaintRecipe();
 
                node.TestRecipe.Reactions = reactions;
 
            }
 
            else
 
            {
 
                node.TestRecipe = replacement;
 
            }
 
            AddCheapestRecipe(node.TestRecipe);
 
            
 
            // check for the next recipe
 
            uint remainingWeight = node.CurrentTargetQuantity - node.CatalystCount;
 
            if (remainingWeight < 10)
 
            {
 
                // not possible to make a valid recipe
 
                return false;
 
            }
 
            //uint remainingReagents = (uint)node.Reagents.Count - node.CatalystCount;
 

	
 
            uint depth = (uint)node.Reagents.Count;
 
            uint depth = (uint)node.ReagentCount;
 
            uint weightToConsume = 0;
 
            uint spaceBelow = 0;
 
            int reagentsBelow = 0;
 
            for (int i = (int)depth-1 ; i >= 0; --i)
 
            {
 
                uint currentWeight = node.CurrentWeights[i];
 

	
 
                if ((spaceBelow >= (weightToConsume+1)) && (currentWeight > 1))
...
 
@@ -1005,14 +1055,20 @@ namespace DesertPaintLab
 

	
 
        public void Stop()
 
        {
 
            this.requestCancel = true;
 
        }
 

	
 
        public void Reset()
 
        {
 
            recipes.Clear();
 
            recipeCosts.Clear();
 
            foreach (PaintRecipe recipe in recipes.Values)
 
            {
 
                recipe.Clear();
 
            }
 
            foreach (string key in recipeCosts.Keys)
 
            {
 
                recipeCosts[key] = uint.MaxValue;
 
            }
 
        }
 
    }
 
}
 

	
RecipeGeneratorWindow.cs
Show inline comments
...
 
@@ -17,16 +17,17 @@
 
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 THE SOFTWARE.
 
*/
 

	
 
using System;
 
using System.Collections.Generic;
 
using System.Collections.Concurrent;
 

	
 
namespace DesertPaintLab
 
{
 
    public partial class RecipeGeneratorWindow : Gtk.Window
 
    {
 
        RecipeGenerator generator;
 
        PlayerProfile profile;
 
        bool canceling = false;
...
 
@@ -49,16 +50,22 @@ namespace DesertPaintLab
 
        static public Gtk.ListStore RecipeModel
 
        {
 
            get
 
            {
 
                return colorStore;   
 
            }
 
        }
 

	
 
        Gtk.ThreadNotify notifyFinished;
 
        Gtk.ThreadNotify notifyProgress;
 
        Gtk.ThreadNotify notifyNewRecipe;
 

	
 
        ConcurrentQueue<PaintRecipe> pendingNewRecipes = new ConcurrentQueue<PaintRecipe>();
 

	
 
        public RecipeGeneratorWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
 
        {
 
            this.profile = profile;
 
            this.Build();
 
            maxIngredientsSpinButton.Value = 5; // TODO: read/save profile info
 
            maxRecipeSpinButton.Value = 20; // TODO: read/save profile info
 
            fullQuantitySpinButton.Value = 20; // TODO: read/save profile info
 
            fullQuantityDepthSpinButton.Value = 4; // TODO: read/save profile info
...
 
@@ -79,19 +86,23 @@ namespace DesertPaintLab
 
            colorStore.SetSortColumnId(0, Gtk.SortType.Ascending);
 
            recipeList.Model = RecipeModel;
 

	
 
            recipeList.Selection.Changed += OnColorSelected;
 

	
 
            profile.LoadRecipes();
 

	
 
            // init UI
 
            foreach (string key in profile.Recipes.Keys)
 
            foreach (KeyValuePair<string, PaintRecipe> pair in profile.Recipes)
 
            {
 
                if (pair.Value.IsValid)
 
            {
 
                colorStore.AppendValues(key);
 
                    string colorName = pair.Key;
 
                    colorStore.AppendValues(colorName);
 
                }
 
            }
 

	
 
            canceling = false;
 
            running = false;
 
            pauseForCheckpoint = false;
 

	
 
            generator = new RecipeGenerator(profile.Reactions);
 
            generator.InitRecipes(profile.Recipes);
...
 
@@ -106,19 +117,23 @@ namespace DesertPaintLab
 
                generator.LoadState(stateFile);
 
                if (generator.CanResume)
 
                {
 
                    beginButton.Label = "Restart";
 
                    stopResumeButton.Label = "Resume";
 
                    stopResumeButton.Sensitive = true;
 
                }
 
            }
 
            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 
            countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
 

	
 
            Destroyed += OnDestroyed;
 

	
 
            notifyFinished = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleFinished));
 
            notifyProgress = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleProgress));
 
            notifyNewRecipe = new Gtk.ThreadNotify(new Gtk.ReadyEvent(HandleNewRecipe));
 
        }
 

	
 
        protected void OnMaxIngredientsChanged(object sender, EventArgs e)
 
        {
 
            // TODO: save profile setting
 
            // TODO: no longer permit resume
 
        }
 

	
...
 
@@ -146,17 +161,17 @@ namespace DesertPaintLab
 
            ExportToWikiAction.Sensitive = false;
 
            IngredientsAction.Sensitive = false;
 
            maxRecipeSpinButton.Sensitive = false;
 
            beginButton.Sensitive = false; // TODO: change to "pause"?
 
            stopResumeButton.Sensitive = true;
 
            fullQuantitySpinButton.Sensitive = false;
 
            fullQuantityDepthSpinButton.Sensitive = false;
 

	
 
            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 
            countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount, Palette.Count);
 

	
 
            // TODO: hook up event notifications
 
            // - progress
 
            // - complete
 
            // - new recipe / recipe update
 

	
 
            // Total recipe search count
 
            //int current = ReagentManager.Names.Count;
...
 
@@ -207,19 +222,18 @@ namespace DesertPaintLab
 
                    running = true;
 
        
 
                    stopResumeButton.Label = "Pause";
 
                    generator.ResumeRecipeGeneration();
 
                }
 
            }
 
        }
 

	
 
        protected void OnFinished(object sender, EventArgs args)
 
        private void HandleFinished()
 
        {
 
            Gtk.Application.Invoke(delegate {
 
                generator.Wait();
 
                if (pauseForCheckpoint)
 
                {
 
                    pauseForCheckpoint = false;
 
                    generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
                    generator.ResumeRecipeGeneration();
 
                }
 
                else
...
 
@@ -242,89 +256,108 @@ namespace DesertPaintLab
 
                        stopResumeButton.Sensitive = true;
 
                        beginButton.Label = "Restart";
 
                    }
 
                    else
 
                    {
 
                        System.IO.File.Delete(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
                    }
 
                }
 
            });
 
        }
 

	
 
        protected void OnNewRecipe(object sender, NewRecipeEventArgs args)
 
        protected void OnFinished(object sender, EventArgs args)
 
        {
 
            PaintRecipe recipe = new PaintRecipe(args.Recipe); // copy it
 
            Gtk.Application.Invoke(delegate
 
            notifyFinished.WakeupMain();
 
            //Gtk.Application.Invoke(delegate {
 
            //    HandleFinished();
 
            //});
 
        }
 

	
 
        private void HandleNewRecipe()
 
            {
 
                progressBar.Pulse();
 
            
 
            PaintRecipe recipe = null;
 
            if (pendingNewRecipes.TryDequeue(out recipe))
 
            {
 
                string recipeColor = Palette.FindNearest(recipe.ReactedColor);
 
                // TODO: Add item to recipe list only if not already listed
 
                bool exists = false;
 
                Gtk.TreeIter iter;
 
                if (colorStore.GetIterFirst(out iter))
 
                {
 
                    do
 
                    {
 
                        string color = (string)colorStore.GetValue(iter, 0);
 
                        if (color.Equals(args.Color))
 
                        if (color.Equals(recipeColor))
 
                        {
 
                            exists = true;
 
                            break;
 
                        }
 
                    } while (colorStore.IterNext(ref iter));
 
                }
 
                if (!exists)
 
                {
 
                    //Console.WriteLine("Add new recipe for {0}", args.Color);
 
                    //    bool isMissingReactions = args.Recipe.CheckMissingReactions(ref missingReactions);
 
                    //    string missingReactionLabel = isMissingReactions ? "X" : "";
 
                    colorStore.AppendValues(args.Color); // , missingReactionLabel);
 
                    countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 
                    colorStore.AppendValues(recipeColor); // , missingReactionLabel);
 
                    countLabel.Text = String.Format("{0} / {1}", profile.RecipeCount+1, Palette.Count);
 
                }
 
                profile.SetRecipe(recipe);
 

	
 
                long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
 
                long delta = progressTime - lastProfileSave;
 
                if (delta >= RECIPE_SAVE_INTERVAL)
 
                {
 
                    profile.SaveRecipes();
 
                    lastProfileSave = progressTime;
 
                }
 
            });
 
            }
 
        }
 

	
 
        protected void OnProgress(object sender, EventArgs args)
 
        protected void OnNewRecipe(object sender, NewRecipeEventArgs args)
 
        {
 
            Gtk.Application.Invoke(delegate
 
            PaintRecipe recipe = new PaintRecipe(args.Recipe); // copy it, so the worker thread can release
 
            lock(this) {
 
                pendingNewRecipes.Enqueue(recipe);
 
            }
 
            notifyNewRecipe.WakeupMain();
 
            //Gtk.Application.Invoke(delegate {
 
            //    HandleNewRecipe();
 
            //});
 
        }
 

	
 
        private void HandleProgress()
 
            {
 
                // TODO: based on time rather than count
 
                long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
 
                long delta = progressTime - lastProgressUpdate;
 
                if (delta > 30)
 
                {
 
                lastProgressUpdate = progressTime;
 
                    progressBar.Pulse();
 
                    lastProgressUpdate = progressTime;
 
                }
 
                delta = progressTime - lastStatusUpdate;
 
                if (delta > 500)
 
                {
 
                    // Update recipe count label as well
 
                lastStatusUpdate = progressTime;
 
                    statusLabel.Text = String.Format("Recipes searched: {0:N00}", generator.RecipeCount);
 
                    lastStatusUpdate = progressTime;
 
                }
 
                //progressBar.Fraction = (double)((generator.RecipeCount / 10000) % 100) / 100.0;
 

	
 
                delta = progressTime - lastCheckpoint;
 
                if (delta > CHECKPOINT_INTERVAL)
 
                {
 
                lastCheckpoint = progressTime;
 
                    pauseForCheckpoint = true;
 
                    lastCheckpoint = progressTime;
 
                    generator.Stop();
 
                }
 
            });
 
        }
 

	
 
        protected void OnProgress(object sender, EventArgs args)
 
        {
 
            notifyProgress.WakeupMain();
 
        }
 

	
 
        protected void OnColorSelected(object o, EventArgs args)
 
        {
 
            Gtk.TreeModel model;
 
            Gtk.TreeIter iter;
 
            Gtk.TreeSelection selection = recipeList.Selection;
 
            if ((selection != null) && selection.GetSelected(out model, out iter))
bin/Debug/colors.txt
Show inline comments
 
deleted file
bin/Debug/ingredients.txt
Show inline comments
 
deleted file
bin/Debug/template/dp_reactions.txt
Show inline comments
 
deleted file
bin/Debug/template/ingredients.txt
Show inline comments
 
deleted file
bin/Release/colors.txt
Show inline comments
 
deleted file
bin/Release/ingredients.txt
Show inline comments
 
deleted file
bin/Release/template/dp_reactions.txt
Show inline comments
 
deleted file
bin/Release/template/ingredients.txt
Show inline comments
 
deleted file
gtk-gui/gui.stetic
Show inline comments
 
<?xml version="1.0" encoding="utf-8"?>
 
<stetic-interface>
 
  <configuration>
 
    <images-root-path>..</images-root-path>
 
    <target-gtk-version>2.12</target-gtk-version>
 
  </configuration>
 
  <import>
 
    <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <widget-library name="../bin/Release/DesertPaintLab.exe" internal="true" />
 
    <widget-library name="../bin/Debug/DesertPaintLab.exe" internal="true" />
 
  </import>
 
  <widget class="Gtk.Window" id="MainWindow" design-size="629 265">
 
    <action-group name="Default">
 
      <action id="FileAction">
 
        <property name="Type">Action</property>
 
        <property name="Accelerator">&lt;Alt&gt;f</property>
 
        <property name="Label" translatable="yes">_File</property>
 
        <property name="ShortLabel" translatable="yes">_File</property>
...
 
@@ -1185,17 +1185,17 @@ You can either import an existing Practi
 
    <child>
 
      <widget class="Gtk.VBox" id="vbox2">
 
        <property name="MemberName" />
 
        <property name="Spacing">6</property>
 
        <property name="BorderWidth">8</property>
 
        <child>
 
          <widget class="Gtk.MenuBar" id="menubar1">
 
            <property name="MemberName" />
 
            <node name="menubar1" type="Menubar">
 
            <node name="__gtksharp_64_Stetic_Editor_ActionMenuBar" type="Menubar">
 
              <node type="Menu" action="ExportAction">
 
                <node type="Menuitem" action="ExportToWikiAction" />
 
              </node>
 
              <node type="Menu" action="SettingsAction">
 
                <node type="Menuitem" action="IngredientsAction" />
 
              </node>
 
            </node>
 
          </widget>
mac/build-mac-bundle.sh
Show inline comments
...
 
@@ -10,17 +10,15 @@ if [ -d DesertPaintLab.app ]; then
 
fi
 
/bin/mkdir -p bin/DesertPaintLab.app
 
/bin/mkdir -p bin/DesertPaintLab.app/Contents/MacOS
 
/bin/cp Info.plist bin/DesertPaintLab.app/Contents/Info.plist
 
/bin/cp launcher.sh bin/DesertPaintLab.app/Contents/MacOS
 
/bin/chmod 755 bin/DesertPaintLab.app/Contents/MacOS/launcher.sh
 
/bin/cp ../bin/Release/DesertPaintLab.exe bin/DesertPaintLab.app/Contents/MacOS/
 
/bin/mkdir -p bin/DesertPaintLab.app/Contents/Resources
 
/bin/cp ../bin/Release/colors.txt bin/DesertPaintLab.app/Contents/Resources/
 
/bin/cp ../bin/Release/ingredients.txt bin/DesertPaintLab.app/Contents/Resources/
 
/bin/cp -r ../bin/Release/template bin/DesertPaintLab.app/Contents/Resources/template
 
/bin/cp -r ../data bin/DesertPaintLab.app/Contents/Resources/data
 

	
 
/usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleShortVersionString ${VERSION}
 
/usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleVersion ${VERSION}
 

	
 
# package up into a DMG
 
/usr/bin/hdiutil create -volname DesertPaintLab -srcfolder bin/ -ov -format UDIF -fs HFS+ DesertPaintLab.dmg
0 comments (0 inline, 0 general)