/// <summary> /// Evaluates all possible neighbor cells. The return values of <paramref name="f"/> are used as probability multipliers /// to chose a random a option. /// Currently not thread-safe /// </summary> /// <param name="location">Location to evaluate the neighborhood of</param> /// <param name="f">Evaluation function. Must return 0/NotAChoice if not applicable, and >1 otherwise. Higher values indicate higher probability</param> /// <returns>Chocen relative cell, or Grid.RelativeCell.Invalid if none was found.</returns> public static Grid.RelativeCell EvaluateChoices(Grid.CellID location, Func<Grid.RelativeCell, Grid.CellID, int> f) { options.Clear(); int total = 0; foreach (var n in location.GetRelativeNeighbors()) { Grid.CellID cellLocation = location + n; int q = f(n, cellLocation); if (q > 0) { total += q; options.Add(new KeyValuePair<int, Grid.RelativeCell>(q, n)); } } if (total == 0) return Grid.RelativeCell.Invalid; if (options.Count == 1) return options[0].Value; int c = random.Next(total); foreach (var o in options) { if (c <= o.Key) return o.Value; c -= o.Key; } Out.Log(Significance.ProgramFatal, "Logic error"); return Grid.RelativeCell.Invalid; }
/// <summary> /// Determines a feasible, possibly ideal neighbor technite target, based on a given evaluation function /// </summary> /// <param name="location"></param> /// <param name="f">Evaluation function. Must return 0/NotAChoice if not applicable, and >1 otherwise. Higher values indicate higher probability</param> /// <returns>Chocen relative cell, or Grid.RelativeCell.Invalid if none was found.</returns> public static Grid.RelativeCell EvaluateNeighborTechnites(Grid.CellID location, Func<Grid.RelativeCell, Technite, int> f) { return EvaluateChoices(location, (relative, cell) => { Grid.Content content = Grid.World.GetCell(cell).content; if (content != Grid.Content.Technite) return NotAChoice; Technite other = Technite.Find(cell); if (other == null) { Out.Log(Significance.Unusual, "Located neighboring technite in " + cell + ", but cannot find reference to class instance"); return NotAChoice; } return f(relative,other); } ); }
/// <summary> /// Determines a feasible, possibly ideal technite neighbor cell that is at the very least on the same height level. /// Higher and/or lit neighbor technites are favored /// </summary> /// <param name="location"></param> /// <returns></returns> public static Grid.RelativeCell GetLitOrUpperTechnite(Grid.CellID location) { return EvaluateNeighborTechnites(location, (relative, technite) => { int rs = 0; if (technite.Status.Lit) rs++; rs += relative.HeightDelta; return rs; }); }
/// <summary> /// Determines a food source in the neighborhood of the specified location /// </summary> /// <param name="location"></param> /// <returns></returns> public static Grid.RelativeCell GetFoodChoice(Grid.CellID location) { return EvaluateChoices(location, (relative, cell) => { Grid.Content content = Grid.World.GetCell(cell).content; int yield = Technite.MatterYield[(int)content]; //zero is zero, no exceptions if (Grid.World.GetCell(cell.BottomNeighbor).content != Grid.Content.Technite) return yield; return NotAChoice; } ); }
/// <summary> /// Determines a feasible neighborhood cell that can work as a replication destination. /// </summary> /// <param name="location"></param> /// <returns></returns> public static Grid.RelativeCell GetSplitTarget(Grid.CellID location) { return EvaluateChoices(location, (relative, cell) => { Grid.Content content = Grid.World.GetCell(cell).content; int rs = 100; if (content != Grid.Content.Clear && content != Grid.Content.Water) rs -= 90; if (Grid.World.GetCell(cell.TopNeighbor).content == Grid.Content.Technite) return NotAChoice; //probably a bad idea to split beneath technite if (Technite.EnoughSupportHere(cell)) return relative.HeightDelta + rs; return NotAChoice; } ); }
public static Grid.RelativeCell EvaluateYieldChoices(Grid.CellID location, Func<Grid.RelativeCell, Grid.CellID, int> f) { options.Clear(); foreach (var n in location.GetRelativeNeighbors()) { Grid.CellID cellLocation = location + n; int q = f(n, cellLocation); if (q > 0) { options.Add(new KeyValuePair<int, Grid.RelativeCell>(q, n)); } } if (options.Count == 0) { //Out.Log(Significance.ProgramFatal, "Logic error"); return Grid.RelativeCell.Invalid; } if (options.Count == 1) return options[0].Value; int maxYield = 0; Grid.RelativeCell maxOption = Grid.RelativeCell.Invalid; foreach (var o in options) { if(maxYield <= o.Key) { maxYield = o.Key; maxOption = o.Value; } } return maxOption; //else //{ // Out.Log(Significance.ProgramFatal, "Logic error"); // return Grid.RelativeCell.Invalid; //} }
public static Grid.RelativeCell GetValleyTarget(Grid.CellID location) { return EvaluateValleyChoices(location, (relative, cell) => { //Grid.Content content = Grid.World.GetCell(cell).content; //int rs = 100; //if (content != Grid.Content.Clear && content != Grid.Content.Water) // rs -= 90; //if (Grid.World.GetCell(cell.TopNeighbor).content == Grid.Content.Technite) // return NotAChoice; //probably a bad idea to split beneath technite //if (Technite.EnoughSupportHere(cell)) // return relative.HeightDelta + rs; if (Grid.World.GetCell(cell).content == Grid.Content.Clear) { if (Grid.World.GetCell(cell.BottomNeighbor).content != Grid.Content.Technite) { if (Technite.EnoughSupportHere(cell)) return 1; } } return NotAChoice; } ); }
internal static bool EnoughSupportHere(Grid.CellID cell) { if (Grid.IsSolid(cell.BottomNeighbor.BottomNeighbor)) return true; foreach (var n0 in cell.GetHorizontalNeighbors()) if (Grid.IsSolid(n0) && Grid.IsSolid(n0.BottomNeighbor)) return true; return false; }
public static Grid.RelativeCell EvaluateValleyChoices(Grid.CellID location, Func<Grid.RelativeCell, Grid.CellID, int> f) { //suche höhergelegene leere Zelle über Matter options.Clear(); int total = 0; foreach (var n in location.GetRelativeEqualOrLowerNeighbors()) //GetRelativeUpperNeighbors effizienter { Grid.CellID cellLocation = location + n; if (cellLocation.Layer <= location.Layer) { int q = f(n, cellLocation); if (q > 0) { total += q; options.Add(new KeyValuePair<int, Grid.RelativeCell>(q, n)); } } } if (total == 0) return Grid.RelativeCell.Invalid; if (options.Count == 1) return options[0].Value; int c = random.Next(total); return options[c].Value; //Out.Log(Significance.ProgramFatal, "Logic error"); //return Grid.RelativeCell.Invalid; }
protected /**/ Technite(Grid.CellID loc) { Location = loc; }
/// <summary> /// Updates the next task to execute. Technites can memorize and execute only one task per round, thus the logic /// must redefine this task each round. If the last task result is TaskResult.MoreWorkNeeded, then the last task /// is not cleared automatically, but can be redefined if desired. /// Calling the method several times on the same technite before a new round is processed will overwrite the previously set task. /// Calling SetNextTask() at all is optional. The technite will sooner or later default to not doing anything in this case. /// </summary> /// <param name="t">Task to execute next</param> /// <param name="target">Location target of the task</param> /// <param name="parameter">Task parameter. What the parameter does depends on the task executed.</param> public void SetNextTask(Task t, Grid.RelativeCell target, byte parameter = 0) { //Out.Log(Significance.Low, this + "->" + t + " @" + target); Grid.CellID absoluteTarget = Location + target; if (!absoluteTarget.IsValid) throw new TaskException(this,"Trying to set invalid relative target "+target+". Task not set."); if (t == Task.SelfTransformToType) { if (parameter > MatterYield.Length) throw new TaskException(this,"Parameter for task "+t+" ("+parameter+") is not a valid matter type."); if (MatterYield[parameter] == 0) throw new TaskException(this,"Parameter for task " + t + " (" + parameter + "/"+((Grid.Content)parameter) + ") is not a suitable transformation output."); } else if ((t == Task.TransferEnergyTo || t == Task.TransferMatterTo) && parameter == 0) throw new TaskException(this, "Task "+t+" requires a non-zero parameter value"); Grid.Content content = Grid.World.CellStacks[absoluteTarget.StackID].volumeCell[absoluteTarget.Layer].content; nextTask = t; taskParameter = parameter; taskTarget = target; }
public CompressedTarget(Grid.RelativeCell target) { Data = (byte)((byte)target.NeighborIndex | (byte)((target.HeightDelta + 1) << 4)); }
/// <summary> /// Attempts to a find a technite based on its location. /// Hashtable lookup is used to quickly locate the technite. /// </summary> /// <param name="location">Location to look at</param> /// <returns>Technite reference, if a technite was found in the given location, null otherwise</returns> public static Technite Find(Grid.CellID location) { Technite rs; if (map.TryGetValue(location, out rs)) return rs; return null; }
public CompressedLocation(Grid.CellID id) { Data = (uint)(((uint)id.Layer & 0xFF) | (id.StackID << 8)); }