protected void CompletelyRandom() { bool done = false; int x, y; bool result; while (!done) { x = rand.Next(GameState.BOARDHEIGHT); y = rand.Next(GameState.BOARDWIDTH); if (opponentBoard.AvailableMove(x, y)) { result = opponentBoard.MakeMove(x, y); opponentBoard.DisplayAction(x, y, $"NPC player{playerNum}"); // DEBUG, Change to display just opponent board later DisplayGameState.DisplayOpponentBoard(opponentBoard); //DisplayGameState.DisplayBothBoards(opponentBoard, ownBoard); if (result) { currentSearch = new HashSet <Tuple <int, int> >(); currentSearch.Add(new Tuple <int, int>(x, y)); searchNewShip = false; } done = true; } } }
private void PlaceShips() { bool done; Tuple <int, int>[] shipCoordinates; PLACEMENT_STATUS status = PLACEMENT_STATUS.CONTINUE; foreach (Tuple <string, int> piece in Ship.PIECES) { // initialize ship coordinates shipCoordinates = new Tuple <int, int> [piece.Item2]; // testing just a do something x time loop for (int i = 0; i < shipCoordinates.Length; i++) { // Go right 1 shipCoordinates[i] = new Tuple <int, int>(i * Ship.DIRECTIONS[0].Item1, i * Ship.DIRECTIONS[0].Item2); } done = false; status = PLACEMENT_STATUS.CONTINUE; while (!done) { Console.Clear(); DisplayInstructions(); // Display status related to controls switch (status) { case PLACEMENT_STATUS.CONTINUE: Console.WriteLine($"Please place the size {piece.Item2} {piece.Item1}"); break; case PLACEMENT_STATUS.PLACEMENT_ERROR: Console.ForegroundColor = ERROR_COLOR; Console.WriteLine("A ship is already there! Please choose another location"); Console.ResetColor(); break; default: // in theory should never have PLACEMENT_STATUS.PLACED_OK Console.WriteLine("Should not reach here"); break; } DisplayGameState.DisplayOwnBoard(playerGameState, shipCoordinates); // if tried to status = PlaceShipCommands(shipCoordinates); if (status == PLACEMENT_STATUS.CAN_PLACE) { if (playerGameState.ValidPlacement(shipCoordinates)) { playerGameState.AddShip(new Ship(piece.Item1, shipCoordinates)); done = true; } } } Console.Clear(); Console.WriteLine("All ships successfully placed"); DisplayGameState.DisplayOwnBoard(playerGameState); } }
private void PickSpot() { columnNumber = rowNumber = -1; bool done = false; // For now result not actually used bool result = false; TargetingStatus status = TargetingStatus.Continue; while (!done) { Console.Clear(); DisplayInstructions(); DisplayCurrentStatus(); if (status == TargetingStatus.Continue) { Console.WriteLine(""); } else if (status == TargetingStatus.InvalidTarget) { Console.ForegroundColor = ERROR_COLOR; Console.WriteLine("Invalid location, please call out another location"); Console.ResetColor(); } else { // Should not reach here Console.WriteLine("Time to debug why the game did not break out of loop"); } DisplayGameState.DisplayBothBoards(opponentGameState, playerGameState, rowNumber, columnNumber); status = HandleInput(ReadUserInput()); if (status == TargetingStatus.LegalTarget) { result = opponentGameState.MakeMove(rowNumber, columnNumber); done = true; } } Console.Clear(); opponentGameState.DisplayAction(rowNumber, columnNumber, "Player" + playerNum); // Display board state one last time before clearing screen DisplayGameState.DisplayBothBoards(opponentGameState, playerGameState, rowNumber, columnNumber); }
// Hmmm, there are some really difficult game states for NPC to check // In the interest of time, I will not make the AI completely optimal // Some ship placement can be really tricky and will require AI to keep track of order of moves // For now I do not want to do that protected void Nextmove() { List <int[]> soFar = new List <int[]>(); // NPC will randomly select a hit, and use DFS to prioritize adjacent hits // Continue Adjacent path if able, otherwise, choose any legal move // Randomly choose to go thorugh direction list forward or backward int index = rand.Next(currentSearch.Count); //gotta assign it to something Tuple <int, int> temp; HashSet <Tuple <int, int> > highPriority = new HashSet <Tuple <int, int> >(); HashSet <Tuple <int, int> > lowPriority = new HashSet <Tuple <int, int> >(); List <int[]> highPriorityList = new List <int[]>(); List <int[]> lowPriorityList = new List <int[]>(); // Randomly choosing a number from HashSet // O(N) but best to have this here since it's done once per move foreach (Tuple <int, int> t in currentSearch) { foreach (Tuple <int, int> direction in Ship.DIRECTIONS) { temp = new Tuple <int, int>(t.Item1 + direction.Item1, t.Item2 + direction.Item2); // check if the move is good if (ValidMove(temp.Item1, temp.Item2)) { if (TwoAdjacent(temp.Item1, temp.Item2)) { if (!highPriority.Contains(temp)) { highPriority.Add(temp); highPriorityList.Add(new int[] { temp.Item1, temp.Item2 }); } } else if (!lowPriority.Contains(temp)) { lowPriority.Add(temp); lowPriorityList.Add(new int[] { temp.Item1, temp.Item2 }); } } } } int[] result; if (highPriority.Count > 0) { result = highPriorityList[rand.Next(highPriorityList.Count)]; } else if (lowPriority.Count > 0) { result = lowPriorityList[rand.Next(highPriorityList.Count)]; } else { result = new int[] { 0, 0 }; Console.WriteLine("Something went seriously wrong at choose next NPC move"); } opponentBoard.MakeMove(result[0], result[1]); if (opponentBoard.IsHit(result[0], result[1])) { currentSearch.Add(new Tuple <int, int>(result[0], result[1])); } opponentBoard.DisplayAction(result[0], result[1], $"NPC player{playerNum}"); // DEBUG, Display just opponent board state DisplayGameState.DisplayOpponentBoard(opponentBoard); //DisplayGameState.DisplayBothBoards(opponentBoard, ownBoard); // Check if AI will continue to search for ships or go completely random next turn FoundAllNearbyShips(); }