/// <summary> /// Returns all possible moves for the given unit /// </summary> /// <param name="c">Character unit</param> /// <returns>List of x,y positions that the unit can possibly move to.</returns> /// <remarks>Currenty assumes all units can only move 1 space per move.</remarks> public List <Tuple <int, int> > getPossibleMoves() { return(GameBoard.getPossibleMovesFromLoc(xPos, yPos)); }
/// <summary> /// Moves the character down one space. /// </summary> public Boolean moveDown() { Logger.log(String.Format(@"Moving {0} down one space...", this.id), "debug"); return(GameBoard.update(this, xPos, (short)(yPos + 1))); }
/// <summary> /// Moves the character up and left one space. /// </summary> public Boolean moveUpLeft() { Logger.log(String.Format(@"Moving {0} up and left (diagonally) one space...", this.id), "debug"); return(GameBoard.update(this, (short)(xPos - 1), (short)(yPos - 1))); }
/// <summary> /// Moves the character down and right one space. /// </summary> public Boolean moveDownRight() { Logger.log(String.Format(@"Moving {0} down and right (diagonally) one space...", this.id), "debug"); return(GameBoard.update(this, (short)(xPos + 1), (short)(yPos + 1))); }
private int isMovingToInterceptOpponent(Character unit, List <Character> enemy_units, int prev_x, int prev_y) { // as long as the cpu unit is moving toward another player unit, return true foreach (Character e_unit in enemy_units) { if (GameBoard.distance(unit.xPos, unit.yPos, e_unit.xPos, e_unit.yPos) < GameBoard.distance(prev_x, prev_y, e_unit.xPos, e_unit.yPos)) { return(HEURISTIC_INTERCEPT_OPPONENT); } } return(0); }
/// <summary> /// Moves the character right one space. /// </summary> public Boolean moveRight() { Logger.log(String.Format(@"Moving {0} right one space...", this.id), "debug"); return(GameBoard.update(this, (short)(xPos + 1), yPos)); }
private int isFleeingFromOverwhelmingForce(Character unit, List <Character> enemy_units, List <Character> friendly_units, int prev_x, int prev_y) { List <Character> unitsToConsider = new List <Character>(); int enemy_count = 0; int unit_count = 0; // get all units within 3 spaces of the current unit foreach (Character enemy in enemy_units) { if (GameBoard.distance(enemy.xPos, enemy.yPos, unit.xPos, unit.yPos) <= 3) { unitsToConsider.Add(enemy); enemy_count++; } } foreach (Character friendly_unit in friendly_units) { // don't include the given unit if (friendly_unit == unit) { continue; } if (GameBoard.distance(friendly_unit.xPos, friendly_unit.yPos, unit.xPos, unit.yPos) <= 3) { unit_count++; } } // if the player force is at least the overwhelming percentage, fleeing is an option if (enemy_count / (unit_count + 1) > OVERWHELMING_FORCE_PERCENT) { // now we need to get which direction they are all mainly coming from // get the average x and y vector they are coming from float avg_x = 0.0f; float avg_y = 0.0f; List <int> vectors = new List <int>(); foreach (Character enemy in unitsToConsider) { avg_x += (enemy.xPos - unit.xPos); avg_y += (enemy.yPos - unit.yPos); } // if the resultant additions so far are very small, we're surrounded, so there's nowhere to run to if ((avg_x < 1 && avg_x > -1) && (avg_y < 1 && avg_y > -1)) { return(0); } // get the unit vector of current motion float motion_x = unit.xPos - prev_x; float motion_y = unit.yPos - prev_y; motion_x = motion_x / ((float)Math.Sqrt(motion_x * motion_x + motion_y * motion_y)); motion_y = motion_x / ((float)Math.Sqrt(motion_x * motion_x + motion_y * motion_y)); // make the averages unit vectors avg_x = avg_x / ((float)Math.Sqrt(avg_x * avg_x + avg_y * avg_y)); avg_y = avg_y / ((float)Math.Sqrt(avg_x * avg_x + avg_y * avg_y)); // now just get the angle between the vectors float theta = (float)Math.Acos(motion_x * avg_x + motion_y * avg_y); // if current motion is greater than 90 degrees away from the enemy positions, unit is fleeing if (theta > Math.PI / 2) { return(HEURISTIC_FLEE_FROM_OVER_FORCE); } else { return(0); } } else { return(0); } }
private int isTravellingToBase(Character unit, int prev_x, int prev_y, Tuple <int, int> basePos, Boolean isEnemyBase = true) { // if the base is not defined, the unit can't be traveling to it if (basePos.Item1 < 0) { return(0); } if (GameBoard.distance(unit.xPos, unit.yPos, basePos.Item1, basePos.Item2) < GameBoard.distance(prev_x, prev_y, basePos.Item1, basePos.Item2)) { if (isEnemyBase) { return(HEURISTIC_TRAVEL_TO_ENEMY_BASE); } else { int numGuarding = 0; foreach (EnemyCharacter friendly in cpuUnits) { if (GameBoard.distance(friendly.xPos, friendly.yPos, cpuBasePos.Item1, cpuBasePos.Item2) < 3) { numGuarding++; } } return(HEURISTIC_TRAVEL_TO_HOME_BASE - numGuarding); } } else { return(0); } }
public static String saveGame(Char whose_turn) { System.Console.Clear(); System.Console.Write(@"Save name: "); String save_name = System.Console.ReadLine(); String file_name; if (save_name == "") { String timestamp = DateTime.Now.ToString(@"yyyyMMddHHmmffff"); file_name = FlameBadge.save_dir + timestamp + @".fbsave"; } else { file_name = FlameBadge.save_dir + save_name + @".fbsave"; if (File.Exists(file_name)) { System.Console.WriteLine("Are you sure you want to overwrite save '{0}'? (Y/n)", save_name); Boolean need_answer = true; while (need_answer) { ConsoleKeyInfo answer; answer = System.Console.ReadKey(); switch (answer.KeyChar) { case 'n': case 'N': need_answer = false; GameBoard.saveGame(whose_turn); break; case 'y': case 'Y': need_answer = false; File.Delete(file_name); break; default: System.Console.WriteLine(@"Please input either 'y' or 'n': "); break; } } } } try { using (StreamWriter writer = new StreamWriter(file_name)) { // write the map for (int i = 0; i < MAP_SIZE; i++) { for (int j = 0; j < MAP_SIZE; j++) { writer.Write(board[i, j]); writer.Write(@" "); } writer.WriteLine(); } writer.WriteLine(); writer.WriteLine(); // write the living player units and their positions, and stats writer.Write(@"Player {0}", FlameBadge.player_units.Count); writer.WriteLine(); foreach (var unit in FlameBadge.player_units) { writer.Write(@"{0} {1} {2} {3} {4} {5}", unit.id, unit.xPos, unit.yPos, unit.health, unit.level, unit.dpsMod); writer.WriteLine(); } writer.WriteLine(); writer.WriteLine(); // write the living computer units and their positions, and stats writer.Write(@"Computer {0}", FlameBadge.cpu_units.Count); writer.WriteLine(); foreach (var unit in FlameBadge.cpu_units) { writer.Write(@"{0} {1} {2} {3} {4} {5}", unit.id, unit.xPos, unit.yPos, unit.health, unit.level, unit.dpsMod); writer.WriteLine(); } writer.WriteLine(); writer.WriteLine(); // write who of the player units was taking his turn writer.Write(@"TURN {0}", whose_turn); } System.Console.WriteLine("Game Saved!"); System.Threading.Thread.Sleep(1000); GameBoard.redraw(); Sidebar.announce(String.Format(@"{0} taking turn...", whose_turn), true); } catch (Exception e) { String msg = String.Format(@"The game could not be saved. Reason: " + e); Logger.log(msg, "error"); return(null); } Logger.log("Game saved."); return(file_name); }
/// <summary> /// Returns all possible moves from the given location /// </summary> /// <param name="x">Location x.</param> /// <param name="y">Location y.</param> /// <param name="moveSpeed">(Optional) Number of spaces the unit can move in one turn. (default is 1)</param> /// <returns>List of x,y positions that are reachable from the location.</returns> public static List <Tuple <int, int> > getPossibleMovesFromLoc(int x, int y, int moveSpeed = 1) { List <Tuple <int, int> > moves = new List <Tuple <int, int> >(); if (GameBoard.isValidMove((short)(x - 1), (short)y)) { moves.Add(new Tuple <int, int>(x - 1, y)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x - 1, y, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)(x + 1), (short)y)) { moves.Add(new Tuple <int, int>(x + 1, y)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x + 1, y, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)x, (short)(y - 1))) { moves.Add(new Tuple <int, int>(x, y - 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x, y - 1, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)x, (short)(y + 1))) { moves.Add(new Tuple <int, int>(x, y + 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x, y + 1, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)(x - 1), (short)(y - 1))) { moves.Add(new Tuple <int, int>(x - 1, y - 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x - 1, y - 1, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)(x + 1), (short)(y - 1))) { moves.Add(new Tuple <int, int>(x + 1, y - 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x + 1, y - 1, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)(x - 1), (short)(y + 1))) { moves.Add(new Tuple <int, int>(x - 1, y + 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x - 1, y + 1, moveSpeed - 1)); } } if (GameBoard.isValidMove((short)(x + 1), (short)(y + 1))) { moves.Add(new Tuple <int, int>(x + 1, y + 1)); if (moveSpeed > 1) { moves.AddRange(getPossibleMovesFromLoc(x + 1, y + 1, moveSpeed - 1)); } } return(moves); }
public FlameBadge() { // Set up saves directory if (!Directory.Exists(save_dir)) Directory.CreateDirectory(save_dir); // Check if any save files exist // If they don't we won't bother offering a load game option DirectoryInfo dir = new DirectoryInfo(save_dir); Boolean is_loaded = false; if (dir.GetFiles().Length != 0) is_loaded = _offerContinue(); String loaded_file = ""; if (is_loaded) loaded_file = _getSavedGame(dir); if (loaded_file == "") is_loaded = false; else loaded_file = save_dir + loaded_file; // if we loaded we need to know whose turn it was Char curr_turn = '0'; if (is_loaded) curr_turn = _getTurn(loaded_file); // Draw the game board. GameBoard game_board = new GameBoard(is_loaded ? loaded_file : null); // Put the pieces on the board. PlayerCharacter.placePieces(is_loaded, loaded_file); EnemyCharacter.placePieces(is_loaded, loaded_file); // mainloop while (true) { for (int i = 0; i < player_units.Count; i++) { // if we loaded a game, skip over everyone until the rightful // unit goes if (curr_turn != '0') { if (player_units[i].id != curr_turn) continue; else curr_turn = '0'; } player_units[i].takeTurn(); List<Character> victims = GameBoard.getAttackableUnits(player_units[i].xPos, player_units[i].yPos, cpu_units.Cast<Character>().ToList()); if (victims.Count > 0) { //pass in true to signify player GameBoard.attack(player_units[i].id, victims[0].id, true); GameBoard.redraw(); if (cpu_units.Count == 0) FlameBadge.hasEnded = true; } Tuple<Int16, Int16> enemyCastle = GameBoard.getCPUCastle(); if ((int)enemyCastle.Item2 == (int)player_units[i].xPos && (int)enemyCastle.Item1 == (int)player_units[i].yPos) { FlameBadge.hasEnded = true; } if (FlameBadge.hasEnded) _endGame(); } for (int i = 0; i < cpu_units.Count; i++) { cpu_units[i].takeTurn(); List<Character> victims = GameBoard.getAttackableUnits(cpu_units[i].xPos, cpu_units[i].yPos, player_units.Cast<Character>().ToList()); if (victims.Count > 0) { //pass in false to signify AI GameBoard.attack(cpu_units[i].id, victims[0].id, false); GameBoard.redraw(); if (player_units.Count == 0) FlameBadge.hasEnded = true; } Tuple<Int16, Int16> enemyCastle = GameBoard.getPlayerCastle(); if ((int)enemyCastle.Item2 == (int)cpu_units[i].xPos && (int)enemyCastle.Item1 == (int)cpu_units[i].yPos) { FlameBadge.hasEnded = true; FlameBadge.cpuCapture = true; } if (FlameBadge.hasEnded) _endGame(); } } }
public static void placePieces(Boolean is_loaded, String loaded_file) { if (!is_loaded) { //Logger.log(@"Placing enemy pieces in random positions."); Tuple <Int16, Int16> castleCoords = GameBoard.getCPUCastle(); Int16 j = castleCoords.Item1; Int16 i = castleCoords.Item2; //Logger.log(@"Placing player pieces in random positions."); if (i - 1 >= 0) { if (GameBoard.overlay[i - 1, j] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i - 1), (short)j); EnemyCharacter character = new EnemyCharacter('A', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (i + 1 < GameBoard.overlay.GetLength(0)) { if (GameBoard.overlay[i + 1, j] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i + 1), (short)j); EnemyCharacter character = new EnemyCharacter('B', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (j - 1 >= 0) { if (GameBoard.overlay[i, j - 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i), (short)(j - 1)); EnemyCharacter character = new EnemyCharacter('C', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (j + 1 < GameBoard.overlay.GetLength(1)) { if (GameBoard.overlay[i, j + 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i), (short)(j + 1)); EnemyCharacter character = new EnemyCharacter('D', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } //diagonals if (i - 1 >= 0 && j + 1 < GameBoard.overlay.GetLength(1)) { if (GameBoard.overlay[i - 1, j + 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i - 1), (short)(j + 1)); EnemyCharacter character = new EnemyCharacter('E', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (i + 1 < GameBoard.overlay.GetLength(0) && j - 1 >= 0) { if (GameBoard.overlay[i + 1, j - 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i + 1), (short)(j - 1)); EnemyCharacter character = new EnemyCharacter('F', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (i - 1 >= 0 && j - 1 >= 0) { if (GameBoard.overlay[i - 1, j - 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i - 1), (short)(j - 1)); EnemyCharacter character = new EnemyCharacter('G', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } if (i + 1 < GameBoard.overlay.GetLength(0) && j + 1 < GameBoard.overlay.GetLength(1)) { if (GameBoard.overlay[i + 1, j + 1] != '@') { Tuple <Int16, Int16> coords = Tuple.Create((short)(i + 1), (short)(j + 1)); EnemyCharacter character = new EnemyCharacter('H', coords.Item1, coords.Item2, 10, 1, 1); FlameBadge.cpu_units.Add(character); GameBoard.update(character, coords.Item1, coords.Item2); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1)); } } } else { Logger.log(@"Placing computer pieces according to loaded save file."); try { using (StreamReader sr = new StreamReader(loaded_file)) { while (sr.Peek() > -1) { String line = sr.ReadLine(); if (line.StartsWith("Computer")) { for (int i = 0; i < Convert.ToInt16(line.Split()[1]); i++) { String[] unit_info = sr.ReadLine().Split(); EnemyCharacter character = new EnemyCharacter(Convert.ToChar(unit_info[0]), Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2]), Convert.ToInt32(unit_info[3]), Convert.ToInt32(unit_info[4]), Convert.ToInt32(unit_info[5])); FlameBadge.cpu_units.Add(character); GameBoard.update(character, Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2])); Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2]), Convert.ToInt32(unit_info[3]), Convert.ToInt32(unit_info[4]), Convert.ToInt32(unit_info[5]))); } } } } } catch (Exception) { Logger.log("Could not load computer pieces from save file. Quitting...", "error"); Environment.Exit(1); } } }
public override void takeTurn() { /*Sidebar.announce(String.Format(@"CPU taking turn...", this.id.ToString()), false); * * Random rand = new Random(); * * // MAGIC NUMBER ALERT!!! * // 8 - Move Up 7 - MoveUpLeft * // 4 - Move Left 9 - MoveUpRight * // 6 - Move Right 1 - MoveDownLeft * // 2 - Move Left 3 - MoveDownRight * List<Char> moves = new List<Char> {'1', '2', '3', '4', '6', '7', '8', '9'}; * * while (true) * { * // The computer is an idiot * Char move = moves[rand.Next(moves.Count)]; * * if (makeMove(move)) * { * Sidebar.announce(String.Format(@"CPU's turn, please wait...", this.id.ToString()), false); * System.Threading.Thread.Sleep(1500); * * break; * } * }*/ // EXAMPLE AI CODE (AI object should be declared at a higher level though, not for each individual unit). // The 3rd and 4th parameters are base positions. If given with x and y less than 0, the AI assumes no bases exist. // The 5th parameter is the AI level, which controls how far into the future the search goes. The level caps at 5 (because any higher takes forever). Tuple <Int16, Int16> castleLoc = GameBoard.getCPUCastle(); Tuple <int, int> convertedLoc = Tuple.Create((int)castleLoc.Item2, (int)castleLoc.Item1); Tuple <Int16, Int16> castlePlayerLoc = GameBoard.getPlayerCastle(); Tuple <int, int> convertedPlayerLoc = Tuple.Create((int)castlePlayerLoc.Item2, (int)castlePlayerLoc.Item1); AI smartCPU = new AI(FlameBadge.player_units, FlameBadge.cpu_units, convertedPlayerLoc, convertedLoc, 2); Tuple <int, int> nextMoveLoc = smartCPU.getNextMove(this); if (nextMoveLoc.Item1 < this.xPos && nextMoveLoc.Item2 > this.yPos) { makeMove('1'); } else if (nextMoveLoc.Item1 == this.xPos && nextMoveLoc.Item2 > this.yPos) { makeMove('2'); } else if (nextMoveLoc.Item1 > this.xPos && nextMoveLoc.Item2 > this.yPos) { makeMove('3'); } else if (nextMoveLoc.Item1 < this.xPos && nextMoveLoc.Item2 == this.yPos) { makeMove('4'); } else if (nextMoveLoc.Item1 > this.xPos && nextMoveLoc.Item2 == this.yPos) { makeMove('6'); } else if (nextMoveLoc.Item1 < this.xPos && nextMoveLoc.Item2 < this.yPos) { makeMove('7'); } else if (nextMoveLoc.Item1 == this.xPos && nextMoveLoc.Item2 < this.yPos) { makeMove('8'); } else if (nextMoveLoc.Item1 > this.xPos && nextMoveLoc.Item2 < this.yPos) { makeMove('9'); } else { Logger.log(String.Format(@"Error getting move for cpu unit {0}", this.id), "Error"); } }