/// <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; }
/// <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> /// Automatically called for each technite state chunk received from the server. /// </summary> /// <param name="state"></param> public static void CreateOrUpdate(Interface.Struct.TechniteState state) { Grid.CellID loc = new CompressedLocation(state.location).CellID; Grid.Content cellContent = Grid.World.CellStacks[loc.StackID].volumeCell[loc.Layer].content; Technite tech; if (map.TryGetValue(loc, out tech)) { if (tech.state.TTL < new CompressedState(state.state).GetTTL()) { tech.transitionState = TransitionState.RemoveFromMap; map.Remove(loc); } else { tech.ImportState(state); all.Add(tech); if (cellContent != Grid.Content.Technite) { Out.Log(Significance.Unusual, "Expected technite content in cell, but found " + cellContent + " (reused state is " + tech + ")"); } return; } } tech = createNew(loc); //new Technite(loc); tech.ImportState(state); map.Add(loc, tech); all.Add(tech); if (++createdThisRound <= MaxLogPerRound) { Out.Log(Significance.Low, tech + " created"); } if (cellContent != Grid.Content.Technite) { Out.Log(Significance.Unusual, "Expected technite content in cell, but found " + cellContent + " (new state is " + tech + ")"); } }
/// <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 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; } )); }