private static void PartOne() { var gridSize = 347991; var grid = new Dictionary <string, int>(); var moveOutcome = new MoveOutcome { X = 0, Y = 0, Direction = Move.First }; for (int i = 1; i <= gridSize; i++) { moveOutcome = GetNextCoordinates(moveOutcome, grid); grid.Add(GetCoordinate(moveOutcome.X, moveOutcome.Y), i); } var locationOfTarget = grid.FirstOrDefault(v => v.Value == gridSize).Key; var locationOfStart = grid.FirstOrDefault(v => v.Value == 1).Key; Console.WriteLine($"Location Of Target: {locationOfTarget}"); Console.WriteLine($"Location Of Start: {locationOfStart}"); var targetX = int.Parse(locationOfTarget.Split(",")[0]); var targetY = int.Parse(locationOfTarget.Split(",")[1]); var startX = int.Parse(locationOfStart.Split(",")[0]); var startY = int.Parse(locationOfStart.Split(",")[1]); var stepsAcross = Math.Abs(targetX - startX); var stepsUpDown = Math.Abs(targetY - startY); Console.WriteLine($"Steps Across: {stepsAcross}"); Console.WriteLine($"Steps Up/Down: {stepsUpDown}"); Console.WriteLine($"Total Steps: {(stepsAcross + stepsUpDown)}"); }
// Attempts to move player avatar to a new location and returns the outcome of the movement - potential location will be updated with the location the player avatar is trying to move to public CommandOutcome MovePlayer(MovementWord command) { // Start with potential location being the same as the current location PotentialLocation = CurrentLocation; // Keep track of where player avatar is moving from UpdateOldLocations(); // See if the command is valid for movement from this location MoveOutcome outcome = locationController.TryMovement(command); string moveMsg; if (outcome.locationID != null && outcome.locationID != "") { // The command attempts to move player avatar to a new location PotentialLocation = outcome.locationID; return(CommandOutcome.FULL); } else if (outcome.messageID != null && outcome.messageID != "") { // The command triggers a message for the player instead of a movement moveMsg = outcome.messageID; } else { // The command doesn't do anything at this location, so show a default message for that command moveMsg = command.DefaultMessageID; } textDisplayController.AddTextToLog(playerMessageController.GetMessage(moveMsg)); return(CommandOutcome.MESSAGE); }
private static MoveOutcome GetNextCoordinates(MoveOutcome lastMove, Dictionary <string, int> grid) { var currentX = lastMove.X; var currentY = lastMove.Y; switch (lastMove.Direction) { case Move.First: //Special case for first move. return(new MoveOutcome { Direction = Move.Right, }); case Move.Right: while (true) { return(new MoveOutcome { Direction = GetNextDirection(currentX + 1, currentY, lastMove.Direction, grid), X = currentX + 1, Y = currentY }); } case Move.Up: while (true) { return(new MoveOutcome { Direction = GetNextDirection(currentX, currentY + 1, lastMove.Direction, grid), X = currentX, Y = currentY + 1 }); } case Move.Left: while (true) { return(new MoveOutcome { Direction = GetNextDirection(currentX - 1, currentY, lastMove.Direction, grid), X = currentX - 1, Y = currentY }); } case Move.Down: while (true) { return(new MoveOutcome { Direction = GetNextDirection(currentX, currentY - 1, lastMove.Direction, grid), X = currentX, Y = currentY - 1 }); } } throw new Exception("Invalid Input"); }
private MoveOutcome FreshOutcome() { MoveOutcome outcome = new MoveOutcome(); outcome.locationID = null; outcome.messageID = null; outcome.failedCondition = false; return(outcome); }
// Check to see if it is possible to move from this location using the given command and returns the outcome of the movement public MoveOutcome TryMovement(Command command, LocationController controller) { MoveOutcome outcome = new MoveOutcome(); outcome.locationID = null; outcome.messageID = null; // If travel is forced, set command to null, which will find the first option that is unconditional, or where the condition is met if (travelIsForced) { command = null; } bool failedCondition = false; // Find and return the first option matching the given command for (int i = 0; i < travelOptions.Length; i++) { outcome = travelOptions[i].TryMovement(command, controller); // Check if a computed location needs to be translated to final location if (!outcome.failedCondition && outcome.locationID != null && controller.IsComputedLocation(outcome.locationID)) { outcome.locationID = controller.GetComputedLocation(outcome.locationID); // If the new location is null, it means we need to get the next location from the movement table if (outcome.locationID == null) { outcome.failedCondition = true; } } if (outcome.failedCondition) { // The current option matched but failed a condition, so indicate we should match the next item with a condition that passes or which is unconditional command = null; failedCondition = true; } else if (outcome.locationID != null || outcome.messageID != null) { failedCondition = false; break; } } // If we get here with failedCondition set then there's been an error as no unconditional alternative was found for one or more conditional entries if (failedCondition) { Debug.LogErrorFormat("Location \"{0}\" has at least one conditional travel option without an unconditional alternative", ShortDescription); } return(outcome); }
private static int GetSumOfNeighbours(MoveOutcome moveOutcome, Dictionary <string, int> grid) { //Check everything around (if there). var sum = 0; if (moveOutcome.X == 0 && moveOutcome.Y == 0) { //First move, return 1 return(1); } if (grid.ContainsKey(GetCoordinate(moveOutcome.X + 1, moveOutcome.Y))) { sum += grid[GetCoordinate(moveOutcome.X + 1, moveOutcome.Y)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X + 1, moveOutcome.Y + 1))) { sum += grid[GetCoordinate(moveOutcome.X + 1, moveOutcome.Y + 1)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X, moveOutcome.Y + 1))) { sum += grid[GetCoordinate(moveOutcome.X, moveOutcome.Y + 1)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X - 1, moveOutcome.Y + 1))) { sum += grid[GetCoordinate(moveOutcome.X - 1, moveOutcome.Y + 1)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X - 1, moveOutcome.Y))) { sum += grid[GetCoordinate(moveOutcome.X - 1, moveOutcome.Y)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X - 1, moveOutcome.Y - 1))) { sum += grid[GetCoordinate(moveOutcome.X - 1, moveOutcome.Y - 1)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X, moveOutcome.Y - 1))) { sum += grid[GetCoordinate(moveOutcome.X, moveOutcome.Y - 1)]; } if (grid.ContainsKey(GetCoordinate(moveOutcome.X + 1, moveOutcome.Y - 1))) { sum += grid[GetCoordinate(moveOutcome.X + 1, moveOutcome.Y - 1)]; } return(sum); }
private int applyOutcome(CCharacter attacker, CCharacter target, MoveOutcome outcome, int damage) { switch (outcome) { case (MoveOutcome.Hit): break; case (MoveOutcome.Crit): damage += (int)attacker.Stats.GetStat(new CriticalDamage()); break; case (MoveOutcome.Dodge): damage = 0; break; case (MoveOutcome.BlockCrit): damage += (int)(attacker.Stats.GetStat(new CriticalDamage()) * 1.15f); //extra damage for critting through block break; case (MoveOutcome.Block): damage = 0; break; } var moveLog = new ExchangeProfile() { objectId = attacker.ObjectId, outcome = outcome, damage = damage, totalDamage = fight.updateTotalDamage(attacker, damage) //bonus damage is accrued before potential overkill clamp }; resultForClient.Add(moveLog.objectId, moveLog); //All time stats: damage++, crit++, critdamage++, hit++, dodge++, blockcrit++, block++ attacker.Effects.OnDamageGiven(damage, attacker); //target.Effects.OnDamageReceived is called inside Stats.ApplyDamage return(target.Stats.ApplyDamage(damage, attacker)); //clamps to actual damage dealt on overkill then inflicts and returns its value }
private static void PartTwo() { var gridSize = 347991; var grid = new Dictionary <string, int>(); var moveOutcome = new MoveOutcome { X = 0, Y = 0, Direction = Move.First }; for (var i = 1; i <= gridSize; i++) { moveOutcome = GetNextCoordinates(moveOutcome, grid); var sum = GetSumOfNeighbours(moveOutcome, grid); if (sum > gridSize) { Console.WriteLine(sum); break; } grid.Add(GetCoordinate(moveOutcome.X, moveOutcome.Y), sum); } }
public int ProcessOutcome(SpellEnvironment env, MoveOutcome outcome) { const string METHODNAME = "ProcessOutcome"; var attacker = env.Character; var target = env.Target; var attackerStats = attacker.Stats; var damage = (int)attackerStats.GetStat(new Damage(), target); //calculates rng damage (minDmg <= dmg <= maxDmg) and applies target negation switch (outcome) { case (MoveOutcome.Hit): //HIT CHANCE VS TARGET'S DODGE CHANCE if (attackerStats.GetStat(new HitChance(), target) > RngUtil.hundredRoll()) { //CRIT CHANCE VS TARGET'S ANTI-CRIT CHANCE, if fails then HIT damage = attackerStats.GetStat( new CriticalHitChance(), target) > RngUtil.hundredRoll() ? applyOutcome(attacker, target, MoveOutcome.Crit, damage) : applyOutcome(attacker, target, MoveOutcome.Hit, damage); } else { //IF HIT 'MISSES' ITS A DODGE damage = applyOutcome(attacker, target, MoveOutcome.Dodge, damage); } break; case (MoveOutcome.Block): damage = applyOutcome(attacker, target, attacker.Stats.GetStat(new CriticalHitChance(), target) * 0.2f > RngUtil.hundredRoll() ? MoveOutcome.BlockCrit : MoveOutcome.Block, damage); break; } return(damage); }
public void Run() { Console.WriteLine(); while (true) { board.Print(); Move currentMove = GetUserInput(); MoveOutcome result = TryPerformMove(currentMove); switch (result) { case MoveOutcome.BlackWins: Console.WriteLine("Black wins"); return; case MoveOutcome.WhiteWins: Console.WriteLine("White wins"); return; case MoveOutcome.Illegal: Console.Clear(); Console.WriteLine("This move is not legal"); break; case MoveOutcome.Success: board.ChangeTurns(); Console.Clear(); Console.WriteLine(); break; default: throw new NotImplementedException(); } } }
public MoveOutcome ExecuteMove(Move move) { MoveOutcome outcome = MoveOutcome.OK; List <Cell> newCells = new List <Cell>(); List <Cell> oldCells = new List <Cell>(); // Update history with activeCells List <Cell> historyStep = new List <Cell>(activeCells); history.Add(historyStep); // playerCameraControl = false; Cell.RootDirection direction = Cell.RootDirection.Up; switch (move) { case Move.UP: direction = Cell.RootDirection.Up; break; case Move.DOWN: direction = Cell.RootDirection.Down; break; case Move.RIGHT: direction = Cell.RootDirection.Right; break; case Move.LEFT: direction = Cell.RootDirection.Left; break; } activeCells.ForEach(cell => { int newX = Mathf.RoundToInt(cell.transform.position.x); // TODO store X/Y in cell int newY = Mathf.RoundToInt(cell.transform.position.y); // TODO store X/Y in cell Cell.RootDirection previousPosition = Cell.RootDirection.Up; var cellDirection = direction; var cellMove = move; if (cell.IsInverted) { switch (direction) { case Cell.RootDirection.Left: cellDirection = Cell.RootDirection.Right; break; case Cell.RootDirection.Right: cellDirection = Cell.RootDirection.Left; break; } switch (move) { case Move.LEFT: cellMove = Move.RIGHT; break; case Move.RIGHT: cellMove = Move.LEFT; break; } } if (cell.Status != Cell.RootStatus.WATER && cell.Status != Cell.RootStatus.POISON) { switch (cellMove) { case Move.UP: newY++; break; case Move.DOWN: newY--; break; case Move.RIGHT: newX++; break; case Move.LEFT: newX--; break; } } if (newY < cell.transform.position.y) { previousPosition = Cell.RootDirection.Up; } if (newY > cell.transform.position.y) { previousPosition = Cell.RootDirection.Down; } if (newX < cell.transform.position.x) { previousPosition = Cell.RootDirection.Right; } if (newX > cell.transform.position.x) { previousPosition = Cell.RootDirection.Left; } var cellOutcome = CheckCell(newX, newY); switch (cellOutcome) { case MoveOutcome.NONE: oldCells.Add(cell); AddFx(fxRock, new Vector3(cell.transform.position.x, cell.transform.position.y, -2)); break; case MoveOutcome.DEATH: ProcessRoot(cells[newX, newY], cell, previousPosition, cellDirection); outcome = MoveOutcome.DEATH; soundLose.Play(); cells[newX, newY].Fx = AddFx(fxDeath, new Vector3(newX, newY, -1), true); newCells.Add(cells[newX, newY]); cells[newX, newY].Status = Cell.RootStatus.POISON; break; case MoveOutcome.OK: case MoveOutcome.OK_INVERT: AddFx(fxEarth, new Vector3(newX, newY, -2)); soundDig.Play(); if (cellOutcome == MoveOutcome.OK_INVERT) { soundInvert.Play(); } if (cellOutcome == MoveOutcome.OK_INVERT) { cells[newX, newY].IsInverted = !cell.IsInverted; } else { cells[newX, newY].IsInverted = cell.IsInverted; } newCells.Add(cells[newX, newY]); ProcessRoot(cells[newX, newY], cell, previousPosition, cellDirection); break; case MoveOutcome.WATER: ProcessRoot(cells[newX, newY], cell, previousPosition, cellDirection); cells[newX, newY].Fx = AddFx(fxWater, new Vector3(newX, newY + 0.7f, -2), true); soundWater.Play(); newCells.Add(cells[newX, newY]); cells[newX, newY].Status = Cell.RootStatus.WATER; waterCount--; break; } }); activeCells = oldCells; newCells.ForEach(cell => activeCells.Add(cell)); if (outcome == MoveOutcome.DEATH) { // StartCoroutine(LoseSequence()); isDead = true; return(MoveOutcome.DEATH); } // ProcessRoot(newCells, direction); if (waterCount <= 0) { StartCoroutine(WinSequence()); gameOver = true; return(MoveOutcome.WIN); } return(outcome); }
} // We need to query the options destination when calculating possible routes // Check to see if the given command is valid for this movement option and return null if it isn't or a move outcome with Location or MessageID if it is public MoveOutcome TryMovement(Command command, LocationController controller) { MoveOutcome outcome = FreshOutcome(); // If commands are null or the given command is null, this is a forced movement entry, so just get the destination / message ID if (commands == null || command == null) { outcome.locationID = destination; outcome.messageID = messageID; } else { // Otherwise, search for a the first entry that matches the given command for (int i = 0; i < commands.Length; i++) { if (command == commands[i]) { outcome.locationID = destination; outcome.messageID = messageID; break; } } } // If a match was found, check for conditions if (outcome.locationID != null || outcome.messageID != null) { ItemController itemController = controller.IC; PlayerController playerController = controller.PC; bool conditionMet = false; switch (conditionType) { case ConditionType.NONE: conditionMet = true; break; case ConditionType.PROBABILITY: // There's a % chance of the movement happening if (Random.Range(0, 100) + 1 <= percentage) { conditionMet = true; } break; case ConditionType.PRESENT: // The required item must be in location or carried if (itemController.ItemsAt(playerController.CurrentLocation).Contains(requiredItem)) { conditionMet = true; break; } goto case ConditionType.CARRYING; // Note: falls through to CARRYING check if condition not met case ConditionType.CARRYING: // The required item must be carried if (playerController.HasItem(requiredItem)) { conditionMet = true; } break; case ConditionType.ITEMSTATE: if (itemController.GetItemState(requiredItem) != forbiddenItemState) { conditionMet = true; } break; default: Debug.LogErrorFormat("Unknown travel condition: {0}", conditionType); break; } // If the condition was not met, clear the outcome but indicate a condition was failed if (!conditionMet) { outcome = FreshOutcome(); outcome.failedCondition = true; } } return(outcome); }