public bool TryGetNextNode(char nextValue, out PatternNode nextNode, bool allowCreate = false) { switch (nextValue) { case Constants.UnplantedCharacter: if (UnplantedNode == null && allowCreate) { UnplantedNode = new PatternNode(Pattern + nextValue); } nextNode = UnplantedNode; break; case Constants.PlantedCharacter: if (PlantedNode == null && allowCreate) { PlantedNode = new PatternNode(Pattern + nextValue); } nextNode = PlantedNode; break; default: nextNode = null; break; } return(nextNode != null); }
private static void ParseInput(string inputFilePath, out string initialState, out PatternNode rootPatternNode) { initialState = string.Empty; rootPatternNode = new PatternNode(string.Empty); using (var reader = new StreamReader(inputFilePath)) { initialState = reader.ReadLine()?.Substring(Constants.InitialStatePrefix.Length); while (!reader.EndOfStream) { var noteString = reader.ReadLine(); if (!string.IsNullOrEmpty(noteString)) { var patternResult = noteString.Split(Constants.PatternResultDelimeter); var currentNode = rootPatternNode; foreach (var value in patternResult[0]) { currentNode.TryGetNextNode(value, out currentNode, allowCreate: true); } currentNode.Result = patternResult[1][0]; } } } }
/// <summary> /// Simulates the spreading of plants in a row of pots from their initial /// state based on rules/patterns defined by the rootPatternNode trie /// after running for the given generationCount. /// </summary> /// <remarks> /// For large generationCounts where the state stabilizes, this function /// will shortcut the pattern matching generation processing. /// </remarks> private static long SimulatePlantSpread(string state, PatternNode rootPatternNode, long generationCount) { var stateOriginIndex = 0L; long?stableStateOriginIndexOffset = null; var generation = 0; for (; generation < generationCount && stableStateOriginIndexOffset == null; generation++) { var newState = new StringBuilder(state.Length); var newOriginIndexOffset = 0L; for (var index = -Constants.PatternOffset; index <= state.Length + Constants.PatternOffset; index++) { var currentNode = rootPatternNode; for (var offset = -Constants.PatternOffset; offset <= Constants.PatternOffset; offset++) { var offsetIndex = index + offset; var stateCharacter = (offsetIndex < 0 || offsetIndex >= state.Length) ? '.' : state[offsetIndex]; if (!currentNode.TryGetNextNode(stateCharacter, out currentNode)) { break; } } if (currentNode?.Result != null) { newState.Append(currentNode.Result); if (newOriginIndexOffset == 0 && currentNode.Result == Constants.PlantedCharacter) { stateOriginIndex += index; newOriginIndexOffset = index; } } else { newState.Append(Constants.UnplantedCharacter); } } var tempState = newState.ToString().Trim(Constants.UnplantedCharacter); if (state == tempState) { stableStateOriginIndexOffset = newOriginIndexOffset; } state = tempState; } if (stableStateOriginIndexOffset != null) { stateOriginIndex += (stableStateOriginIndexOffset.Value * (generationCount - generation)); } var plantedPotNumberSum = 0L; for (var index = 0; index < state.Length; index++) { if (state[index] == Constants.PlantedCharacter) { plantedPotNumberSum += (index + stateOriginIndex); } } return(plantedPotNumberSum); }