Coverage Summary for Class: CliWriter (it.polimi.ingsw.Client.CLI)

Class Method, % Branch, % Line, %
CliWriter 0% (0/20) 0% (0/246) 0% (0/373)
CliWriter$1 0% (0/1) 0% (0/1)
Total 0% (0/21) 0% (0/246) 0% (0/374)


1 package it.polimi.ingsw.Client.CLI; 2  3 import it.polimi.ingsw.Controller.Actions.*; 4 import it.polimi.ingsw.Controller.MoveDestination; 5 import it.polimi.ingsw.Misc.OptionalValue; 6 import it.polimi.ingsw.Misc.Pair; 7 import it.polimi.ingsw.Model.*; 8 import it.polimi.ingsw.Model.Enums.GameMode; 9 import it.polimi.ingsw.Model.Enums.GamePhase; 10 import it.polimi.ingsw.Model.Enums.PawnColour; 11 import it.polimi.ingsw.Network.SocketWrapper; 12 import it.polimi.ingsw.Server.Messages.Events.Requests.*; 13  14 import java.io.BufferedReader; 15 import java.io.IOException; 16 import java.util.ArrayList; 17 import java.util.List; 18 import java.util.UUID; 19 import java.util.concurrent.BrokenBarrierException; 20 import java.util.concurrent.CyclicBarrier; 21 import java.util.stream.Collectors; 22 import java.util.stream.IntStream; 23  24 /** 25  * This class takes Client's commands from terminal, provides support to the user and sends the command to the Server by using the SocketWrapper 26  */ 27 public class CliWriter implements Runnable { 28  29  /** 30  * used to synchronize CliWriter and CliReader, useful when the first one needs to wait the second one 31  */ 32  final CyclicBarrier cyclicBarrier; 33  /** 34  * socket wrapper to connect the Client to the Server 35  */ 36  private final SocketWrapper socketWrapper; 37  /** 38  * used to store the client's game data 39  */ 40  private final ClientView clientView; 41  /** 42  * used to acquire text from command line 43  */ 44  private final BufferedReader stdIn; 45  46  47  public CliWriter(SocketWrapper socketWrapper, ClientView clientView, BufferedReader bufferedReader, CyclicBarrier cyclicBarrier) { 48  this.socketWrapper = socketWrapper; 49  this.clientView = clientView; 50  this.stdIn = bufferedReader; 51  this.cyclicBarrier = cyclicBarrier; 52  } 53  54  @Override 55  public void run() { 56  try { 57  //wait for the CliReader to receive the confirmation of successful connection to the server 58  cyclicBarrier.await(); 59  } catch (BrokenBarrierException | InterruptedException e) { 60  throw new RuntimeException(e); 61  } 62  //exit the Thread whether the client was not able to connect to the server 63  if (!this.clientView.isConnected()) { 64  return; 65  } 66  try { 67  System.out.println( 68  """ 69  ERIANTYS 70  Welcome Player 71  """ 72  ); 73  String nickname; 74  while (true) { 75  System.out.println("Insert Username:"); 76  //acquire Username from stdIn 77  nickname = stdIn.readLine(); 78  if (!this.clientView.isConnected()) return; 79  //whether at least one between nickname and password is empty then repeat the login process 80  if (nickname.equals("")) { 81  System.out.println("Username not well formatted"); 82  } else { 83  if (!this.clientView.isConnected()) return; 84  //create and initialize the DeclarePlayer request 85  DeclarePlayerRequest dp = new DeclarePlayerRequest(nickname); 86  //send the request to the server 87  socketWrapper.sendMessage(dp); 88  //wait for the CliReader to receive the confirmation of successful login 89  cyclicBarrier.await(); 90  //check if this Client is connected 91  if (this.clientView.isLogged()) { 92  break; 93  } 94  } 95  //repeat until user has typed Username and password correctly (syntactically) or typed password is wrong 96  } 97  //set nickname in clientView object 98  this.clientView.setNickname(nickname); 99  String input; 100  if (!this.clientView.isConnected()) Thread.currentThread().interrupt(); 101  while (true) { 102  //acquire command from stdIn 103  input = stdIn.readLine(); 104  if (!this.clientView.isConnected()) return; 105  //execute command 106  elaborateInput(input); 107  } 108  } catch (IOException | BrokenBarrierException e) { 109  System.out.println("IO exception when reading from stdIn."); 110  e.printStackTrace(); 111  } catch (InterruptedException e) { 112  throw new RuntimeException(e); 113  } 114  } 115  116  /** 117  * This method, given a String, executes the proper method according to User's request 118  * 119  * @param userInput: text containing the command 120  * @throws IOException the integer read from command line 121  */ 122  private void elaborateInput(String userInput) throws IOException { 123  switch (userInput.toLowerCase()) { 124  case "showactions" -> printActions(); 125  case "createlobby" -> createLobby(); 126  case "joinlobby" -> joinLobby(); 127  case "startgame" -> startGame(); 128  case "charactercardinfo" -> { 129  if (checkActionRequest()) return; 130  characterCardInfo(); 131  } 132  case "playassistantcard" -> { 133  if (checkActionRequest()) return; 134  playAssistantCard(); 135  } 136  case "playcharactercard" -> { 137  if (checkActionRequest()) return; 138  playCharacterCard(); 139  } 140  case "movestudent" -> { 141  if (checkActionRequest()) return; 142  moveStudent(); 143  } 144  case "movemothernature" -> { 145  if (checkActionRequest()) return; 146  moveMotherNature(); 147  } 148  case "choosecloud" -> { 149  if (checkActionRequest()) return; 150  chooseCloud(); 151  } 152  case "endturn" -> { 153  if (checkActionRequest()) return; 154  endTurn(); 155  } 156  default -> System.out.println("Command not valid"); 157  } 158  } 159  160  /** 161  * This method, after checking the gameMode, takes CharacterCard's number and extracts the characteCard; basing on CharacterCard type 162  * the methods create dynamically the CharacterCardInput by requesting the user only the right input. 163  * 164  * @throws IOException input has gone wrong 165  */ 166  private void playCharacterCard() throws IOException { 167  //check for GameMode's validity 168  if (this.clientView.getModel().getGameMode() == GameMode.SIMPLE) { 169  System.out.println("Command valid only in Advanced GameMode"); 170  return; 171  } 172  //Get selected characterCard's index 173  int selected = getCharacterCardIndex(); 174  int finalSelected = selected; 175  //get current player 176  PlayerBoard currentPlayer = this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer(); 177  //extract CharacterCard from GameBoard 178  CharacterCard characterCard = this.clientView.getModel().getCharacterCards().stream().filter(characterCard1 -> characterCard1.getId() == finalSelected).findFirst().get(); 179  //get selected characterCard's index from gameBoard 180  selected = IntStream.range(0, 3).filter(i -> this.clientView.getModel().getCharacterCards().get(i).getId() == characterCard.getId()).findFirst().orElse(selected); 181  PlayCharacterCard playCharacterCard; 182  PlayerActionRequest playerActionRequest; 183  //pattern matching switch responsible for redirecting user to right input creation 184  switch (characterCard) { 185  case Card01 card01 -> { 186  PawnColour pawnToMove; 187  System.out.println("Type student's position (from 0 to 3) to move"); 188  //Get selected pawn's index from 0 to 3 (Card01 contains 4 students) 189  while (true) { 190  selected = getInt(); 191  if (selected < 0 || selected > 3) { 192  System.out.println("Index not valid, try again"); 193  } else { 194  break; 195  } 196  } 197  //get selected pawn having the index 198  pawnToMove = (PawnColour) card01.getState().get(selected); 199  System.out.println("Type target island's id"); 200  //get Island's ID 201  Integer IslandId = getInt(); 202  //create playCharacterCard's controller action 203  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.of(IslandId), OptionalValue.of(pawnToMove), OptionalValue.empty()); 204  //create playerActionRequest message to send to the server 205  playerActionRequest = new PlayerActionRequest(playCharacterCard); 206  } 207  case Card02 ignored -> { 208  //create playCharacterCard's controller action 209  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.empty(), OptionalValue.empty()); 210  //create playerActionRequest message to send to the server 211  playerActionRequest = new PlayerActionRequest(playCharacterCard); 212  } 213  case Card03 ignored1 -> { 214  System.out.println("Type target island's id"); 215  //get Island's ID 216  Integer IslandId = getInt(); 217  //create playCharacterCard's controller action 218  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.of(IslandId), OptionalValue.empty(), OptionalValue.empty()); 219  //create playerActionRequest message to send to the server 220  playerActionRequest = new PlayerActionRequest(playCharacterCard); 221  } 222  case Card04 ignored2 -> { 223  //create playCharacterCard's controller action 224  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.empty(), OptionalValue.empty()); 225  //create playerActionRequest message to send to the server 226  playerActionRequest = new PlayerActionRequest(playCharacterCard); 227  } 228  case Card05 ignored3 -> { 229  System.out.println("Type target island's id"); 230  //get Island's ID 231  Integer IslandId = getInt(); 232  //create playCharacterCard's controller action 233  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.of(IslandId), OptionalValue.empty(), OptionalValue.empty()); 234  //create playerActionRequest message to send to the server 235  playerActionRequest = new PlayerActionRequest(playCharacterCard); 236  } 237  case Card06 ignored4 -> { 238  //create playCharacterCard's controller action 239  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.empty(), OptionalValue.empty()); 240  //create playerActionRequest message to send to the server 241  playerActionRequest = new PlayerActionRequest(playCharacterCard); 242  } 243  case Card07 card07 -> { 244  System.out.println("You can now type up to 3 pairs to exchange, the first element coming from the entrance and the second one from the card\n" + 245  "Press 'enter' after a pair if you want to exchange less than 3 pairs"); 246  //create List of Pairs which will contain up to 3 pairs of pawns 247  List<Pair<PawnColour, PawnColour>> pairs = new ArrayList<>(); 248  //index containing pawn's index in currentPlayers' entrance 249  OptionalValue<Integer> PawnPosition; 250  //index containing pawn's index inside the card 251  int cardIndex; 252  outerWhile: 253  do { 254  System.out.println("Insert entrance's position containing the pawn to move, or 'enter' to conclude the choice"); 255  do { 256  //get pawn's index (that one coming from entrance) 257  PawnPosition = getOptionalInt(); 258  //if user pressed 'enter' the input will interrupt (the user can choose less than 3 pairs) 259  if (PawnPosition.isEmpty()) break outerWhile; 260  //check whether user typed an invalid index 261  if (PawnPosition.get() < 0 || PawnPosition.get() >= currentPlayer.getEntranceStudents().size()) 262  System.out.println("Target Entrance Position invalid"); 263  else break; 264  } while (true); 265  System.out.println("Select pawn's index from card"); 266  do { 267  //get pawn's index (that one coming from the card) 268  cardIndex = getInt(); 269  //check whether user typed an invalid index 270  if (cardIndex < 0 || cardIndex >= card07.getState().size()) 271  System.out.println("Target Card Position invalid"); 272  else { 273  break; 274  } 275  } while (true); 276  //add to the list containing the pairs the one just chosen by the user 277  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), (PawnColour) card07.getState().get(cardIndex))); 278  //repeat the loop until the user has selected 3 pairs or pressed 'enter' 279  } while (pairs.size() < 3); 280  //create playCharacterCard's controller action 281  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.empty(), OptionalValue.of(pairs)); 282  //create playerActionRequest message to send to the server 283  playerActionRequest = new PlayerActionRequest(playCharacterCard); 284  } 285  case Card08 ignored5 -> { 286  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.empty(), OptionalValue.empty()); 287  //create playerActionRequest message to send to the server 288  playerActionRequest = new PlayerActionRequest(playCharacterCard); 289  } 290  case Card09 ignored6 -> { 291  System.out.println("type the colour to make it irrelevant during this turn"); 292  //create playerActionRequest message to send to the server 293  playerActionRequest = createPlayerActionByPawnColour(selected, currentPlayer); 294  } 295  case Card10 ignored7 -> { 296  System.out.println("You can now type up to 2 pairs to exchange, the first element coming from the entrance and the second one from the dining room\n" + 297  "Press 'enter' after a pair if you want to exchange less than 2 pairs"); 298  //create List of Pairs which will contain up to 2 pairs of pawns 299  List<Pair<PawnColour, PawnColour>> pairs = new ArrayList<>(); 300  //index containing pawn's index in currentPlayers' entrance 301  OptionalValue<Integer> PawnPosition; 302  outerWhile: 303  do { 304  System.out.println("Insert entrance's position containing the pawn to move, or 'enter' to conclude the choice"); 305  do { 306  //get pawn's index (that one coming from entrance) 307  PawnPosition = getOptionalInt(); 308  //if user pressed 'enter' the input will interrupt (the user can choose less than 3 pairs) 309  if (PawnPosition.isEmpty()) break outerWhile; 310  //check whether user typed an invalid index 311  if (PawnPosition.get() < 0 || PawnPosition.get() >= currentPlayer.getEntranceStudents().size()) 312  System.out.println("Target Entrance Position invalid"); 313  else { 314  break; 315  } 316  } while (true); 317  System.out.println("Select diningRoom's colour"); 318  boolean repeat = true; 319  //get the selected PawnColour from stdIn and add the pair to the list 320  do { 321  switch (stdIn.readLine().toLowerCase()) { 322  case "red" -> { 323  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), PawnColour.RED)); 324  repeat = false; 325  } 326  case "yellow" -> { 327  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), PawnColour.YELLOW)); 328  repeat = false; 329  } 330  case "green" -> { 331  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), PawnColour.GREEN)); 332  repeat = false; 333  } 334  case "pink" -> { 335  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), PawnColour.PINK)); 336  repeat = false; 337  } 338  case "blue" -> { 339  pairs.add(new Pair<>(currentPlayer.getEntranceStudents().get(PawnPosition.get()).get(), PawnColour.BLUE)); 340  repeat = false; 341  } 342  case default -> System.out.println("Colour not valid, try again"); 343  } 344  //repeat whether the user typed an invalid PawnColour 345  } while (repeat); 346  //repeat the loop until the user has selected 2 pairs or pressed 'enter' 347  } while (pairs.size() < 2); 348  //create playCharacterCard's controller action 349  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), 350  selected, 351  OptionalValue.empty(), 352  OptionalValue.empty(), 353  OptionalValue.of(pairs)); 354  //create playerActionRequest message to send to the server 355  playerActionRequest = new PlayerActionRequest(playCharacterCard); 356  } 357  case Card11 card11 -> { 358  System.out.println("Select pawn's index from card"); 359  int cardIndex; 360  do { 361  //get selected pawn's index from card 362  cardIndex = getInt(); 363  //check whether user typed an invalid index 364  if (cardIndex < 0 || cardIndex >= card11.getState().size()) 365  System.out.println("Target Card Position invalid"); 366  else { 367  break; 368  } 369  } while (true); 370  //create playCharacterCard's controller action 371  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of((PawnColour) card11.getState().get(cardIndex)), OptionalValue.empty()); 372  //create playerActionRequest message to send to the server 373  playerActionRequest = new PlayerActionRequest(playCharacterCard); 374  } 375  case Card12 ignored8 -> { 376  System.out.println("Select Pawn's colour to remove from all Playerboards' diningrooms"); 377  //create playerActionRequest message to send to the server 378  playerActionRequest = createPlayerActionByPawnColour(selected, currentPlayer); 379  } 380  case default -> { 381  System.out.println("CharacterCard not valid"); 382  return; 383  } 384  } 385  //send playerActionRequest to the server 386  socketWrapper.sendMessage(playerActionRequest); 387  } 388  389  /** 390  * This method prints selected characterCard to the command line to explain card's effect to the player 391  * 392  * @throws IOException input has gone wrong 393  */ 394  private void characterCardInfo() throws IOException { 395  //check for GameMode's validity 396  if (this.clientView.getModel().getGameMode() == GameMode.SIMPLE) { 397  System.out.println("Command valid only in Advanced GameMode"); 398  return; 399  } 400  //get selected characterCard's index 401  int selected = getCharacterCardIndex(); 402  //every switch's case print CharacterCard's info (every information is available on game's guide) 403  switch (selected) { 404  case 1 -> System.out.println("EFFECT: Take 1 Student from this card and place it on " + 405  "an Island of your choice. Then, draw a new Student from the Bag and place it on this card."); 406  case 2 -> System.out.println("EFFECT: During this turn, you take control of any\n" + 407  " number of Professors even if you have the same number of Students as the player who currently controls them."); 408  case 3 -> System.out.println(""" 409  EFFECT: Choose an Island and resolve the Island as if 410  Mother Nature had ended her movement there. Mother 411  Nature will still move and the Island where she ends her movement will also be resolved."""); 412  case 4 -> System.out.println("EFFECT: You may move Mother Nature up to 2\n" + 413  " additional Islands than is indicated by the Assistant card you've played."); 414  case 5 -> System.out.println(""" 415  EFFECT: Place a No Entrytile on an Island of your choice. 416  The first time Mother Nature ends her movement there, put the No Entry tile back onto this card 417  DO NOT calculate influence on that Island, or place any Towers."""); 418  case 6 -> 419  System.out.println("EFFECT: When resolving a Conquering on an Island, Towers do not count towards influence."); 420  case 7 -> 421  System.out.println("EFFECT: you may take up to 3 students from this card and replace them with the same number of Students\n" + 422  " from your Entrance"); 423  case 8 -> 424  System.out.println("EFFECT: During the influence calculation this turn, you count as having 2 more influence"); 425  case 9 -> 426  System.out.println("EFFECT: Choose a color of Student: during the influence calculation this turn, that color adds no influence"); 427  case 10 -> 428  System.out.println("EFFECT: You may exchange up to 2 Students between your entrance and your Dining Room"); 429  case 11 -> 430  System.out.println("EFFECT: Take 1 Student from this card and place it in your Dining Room. Then, draw a new Student from the\n" + 431  "Bag and place it on this card."); 432  case 12 -> System.out.println(""" 433  EFFECT: Choose a type of Student: every player (including yourself) must return 3 Students of that type 434  from their Dining Room to the bag. If any player has fewer than 3 Students of that type, return as many Students as they have. 435  """); 436  } 437  System.out.println("You may now continue with the game, remember the 'showActions' command, it's your best friend during the game"); 438  } 439  440  /** 441  * Support method responsible for checking whether the user has the rights to perform the requested action. 442  * This method will only be executed to check actions available only when the match has started 443  * 444  * @return true if the check fails 445  */ 446  private boolean checkActionRequest() { 447  //check if the user is present inside a lobby 448  if (!this.clientView.isInLobby()) { 449  System.out.println("Action not valid, join or create a lobby"); 450  return true; 451  } 452  //check if the game has started 453  if (!this.clientView.getGameStarted()) { 454  if (this.clientView.getAdmin().equals(this.clientView.getNickname())) { 455  System.out.println("Action not valid, you need to start the game"); 456  } else { 457  System.out.println("Action not valid, you need to wait for the admin to start the game"); 458  } 459  return true; 460  } 461  return false; 462  } 463  464  /** 465  * Method responsible for print actions during all the game 466  */ 467  private void printActions() { 468  //actions available outside a lobby 469  if (!this.clientView.isInLobby()) { 470  System.out.println("Available commands:\n"); 471  System.out.println("-- createLobby (create a open or private lobby)"); 472  System.out.println("-- joinLobby (join a lobby with the UUID)"); 473  return; 474  } 475  if (!this.clientView.getGameStarted()) { 476  //actions available when the game has not started 477  if (this.clientView.getNickname().equals(this.clientView.getAdmin())) { 478  //if the user is the admin 479  System.out.println("Available commands:\n"); 480  System.out.println("-- startGame (start the game)"); 481  } else { 482  //if the user is not the admin 483  System.out.println("No actions available, wait for the admin to start the game"); 484  } 485  return; 486  } 487  //print action-phase commands 488  printGameActions(); 489  } 490  491  /** 492  * Executes the createLobby command; during the creation the user is able to choose lobby's visibility (private or public) and 493  * lobby's dimension (this dimension will also be game's number of players). 494  * <p> 495  * Finally, it creates the createLobby request and then sends it to the server. 496  * 497  * @throws IOException if an I/O error occurs 498  */ 499  private void createLobby() throws IOException { 500  //check if the user is already in a lobby 501  if (!clientView.isInLobby()) { 502  //create CreateLobbyRequest object 503  CreateLobbyRequest createLobbyRequest; 504  //print visibility request 505  System.out.println("Do you want to create an open or private lobby?"); 506  System.out.println("O : open"); 507  System.out.println("P : private"); 508  boolean isPublic; 509  String input; 510  loop: 511  while (true) { 512  //get visibility choice 513  input = stdIn.readLine().toUpperCase(); 514  //assign user's choice to boolean variable 'isPublic' 515  switch (input) { 516  case "O" -> { 517  isPublic = true; 518  break loop; 519  } 520  case "P" -> { 521  isPublic = false; 522  break loop; 523  } 524  case default -> System.out.println("input not correct, please try again"); 525  } 526  } 527  //print lobby's dimension request 528  System.out.println("how many player will the lobby contain?"); 529  int players; 530  while (true) { 531  //get lobby's dimension from stdIn 532  players = getInt(); 533  //check input's validity (lobby's dimension must be between 2 and 4) 534  if (players >= 2 && players <= 4) { 535  break; 536  } 537  System.out.println("Amount of players not valid"); 538  } 539  //initialize createLobbyRequest object to send to the server 540  createLobbyRequest = new CreateLobbyRequest(isPublic, players); 541  //send request to the server 542  socketWrapper.sendMessage(createLobbyRequest); 543  } else { 544  System.out.println("You are already in a lobby"); 545  } 546  } 547  548  /** 549  * Executes the joinLobby command by knowing lobby's UUID, it allows to access both open and private lobbies. 550  * <p> 551  * Finally, it creates the joinLobby request and then sends it to the Server. 552  * 553  * @throws IOException if an I/O error occurs 554  */ 555  private void joinLobby() throws IOException { 556  //check if the user is already in a lobby 557  if (!clientView.isInLobby()) { 558  //create ConnectLobbyRequest object 559  ConnectLobbyRequest connectLobbyRequest; 560  System.out.println("Insert lobby's UUID"); 561  UUID id = null; 562  boolean repeat; 563  do { 564  try { 565  //get UUID from stdIn 566  id = UUID.fromString(stdIn.readLine()); 567  repeat = false; 568  } catch (IllegalArgumentException e) { 569  System.out.println("UUID not valid, try again"); 570  repeat = true; 571  } 572  //repeat until the user types a valid UUID (syntactically, the server will check if the UUID is associated with a valid lobby) 573  } while (repeat); 574  //initialize connectLobbyRequest object to send to the server 575  connectLobbyRequest = new ConnectLobbyRequest(id); 576  //send message to the server 577  socketWrapper.sendMessage(connectLobbyRequest); 578  579  } else { 580  System.out.println("You are already in a lobby"); 581  } 582  } 583  584  /** 585  * Executes the startGame command, it can be executed only by lobby's admin and whether the lobby is full. 586  * The admin can choose the game mode between simple and advanced. 587  * <p> 588  * Finally, it creates the startGameRequest and then sends it to the Server. 589  * 590  * @throws IOException if an I/O error occurs 591  */ 592  private void startGame() throws IOException { 593  if (this.clientView.isInLobby()) { 594  ////print gameMode request 595  System.out.println("Select the game mode:"); 596  System.out.println("S: simple"); 597  System.out.println("A: advanced"); 598  //create GameMode object 599  GameMode gameMode; 600  String input; 601  //create startGameRequest object 602  StartGameRequest startGameRequest; 603  loop: 604  //repeat until the user types a valid gamemode 605  while (true) { 606  ////get gameMode from stdIn 607  input = stdIn.readLine().toUpperCase(); 608  switch (input) { 609  case "S" -> { 610  gameMode = GameMode.SIMPLE; 611  break loop; 612  } 613  case "A" -> { 614  gameMode = GameMode.ADVANCED; 615  break loop; 616  } 617  case default -> System.out.println("input not correct, please try again"); 618  } 619  } 620  //initialize startGameRequest object 621  startGameRequest = new StartGameRequest(gameMode); 622  //send message to the server 623  socketWrapper.sendMessage(startGameRequest); 624  } else { 625  System.out.println("You first need to join or create a lobby"); 626  } 627  } 628  629  630  /** 631  * Executes the playAssistantCard command 632  * The method shows the available assistantCard at that moment (removing the used cards and cards picked by other players in the same turn to avoid 633  * playing cards with same value). 634  * <p> 635  * Finally, it creates the playAssistantCard request and then sends it to the Server. 636  * 637  * @throws IOException if an I/O error occurs 638  */ 639  private void playAssistantCard() throws IOException { 640  System.out.println("select one of these available assistant card"); 641  //get the unused cards 642  ArrayList<AssistantCard> availableAssistants = this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getMutableAssistantCards() 643  .stream().filter(assistantCard -> !assistantCard.getUsed()) 644  .collect(Collectors.toCollection(ArrayList::new)); 645  //from the unused cards, extract the card with a priority not selected before by other players 646  for (PlayerBoard pb : this.clientView.getModel().getMutableTurnOrder().getCurrentTurnOrder()) { 647  if (this.clientView.getModel().getMutableTurnOrder().getMutableSelectedCard(pb).isPresent()) { 648  availableAssistants.removeIf(assistantCard -> assistantCard.getPriority() == this.clientView.getModel().getMutableTurnOrder().getMutableSelectedCard(pb).get().getPriority()); 649  } 650  } 651  //get the priority of the available cards 652  ArrayList<Integer> cardNumbers = availableAssistants.stream().map(AssistantCard::getPriority).collect(Collectors.toCollection(ArrayList::new)); 653  availableAssistants.forEach(assistantCard -> System.out.println("priority:" + assistantCard.getPriority() + " maxMovement:" + assistantCard.getMaxMovement())); 654  //get the selected card 655  int selected; 656  do { 657  selected = getInt(); 658  if (!cardNumbers.contains(selected)) { 659  System.out.println("Card not available"); 660  } else { 661  break; 662  } 663  //repeat until the user pic 664  } while (true); 665  PlayAssistantCard playAssistantCard = new PlayAssistantCard(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId(), selected); 666  PlayerActionRequest playerAction = new PlayerActionRequest(playAssistantCard); 667  socketWrapper.sendMessage(playerAction); 668  } 669  670  /** 671  * Executes the moveStudent command, the method requires from the user to type pawn's index inside entrance then it 672  * allows the user to choose the destination: 673  * type enter to move the pawn directly to the dining room 674  * type a number that will be interpreted as the island's id on which to move the pawn 675  * <p> 676  * Finally, it creates the moveStudent request and then sends it to the Server. 677  * 678  * @throws IOException if an I/O error occurs 679  */ 680  private void moveStudent() throws IOException { 681  //get entrance size 682  int entranceSize = this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getEntranceSize() - 1; 683  System.out.println("Insert the number of entrance's position between 0 and " + entranceSize); 684  //get selected pawn's index from entrance 685  int selected = getInt(); 686  687  System.out.println("Type the island id to move the selected student there or press 'Enter' to send it to the dining room"); 688  //get destination ('enter' for dining room or island's ID) 689  OptionalValue<Integer> choice = getOptionalInt(); 690  //create MoveStudent object 691  MoveStudent moveStudent; 692  if (choice.isEmpty()) { 693  //if the user has typed 'enter' then initialize the moveStudent action with dining room as MoveDestination 694  moveStudent = new MoveStudent(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId(), selected, MoveDestination.toDiningRoom()); 695  } else { 696  //if the user has typed a number then initialize the moveStudent with that number 697  moveStudent = new MoveStudent(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId(), selected, MoveDestination.toIsland(choice.get())); 698  } 699  //create and initialize clientPlayerAction to send to the Server 700  PlayerActionRequest clientPlayerAction = new PlayerActionRequest(moveStudent); 701  //send the action request to the Server 702  socketWrapper.sendMessage(clientPlayerAction); 703  704  } 705  706  /** 707  * Executes the moveMotherNature command, this method asks the user to type the amount of steps motherNature should take 708  * <p> 709  * Finally, it creates the moveMotherNature request and then sends it to the Server. 710  * 711  * @throws IOException if an I/O error occurs 712  */ 713  private void moveMotherNature() throws IOException { 714  int steps = this.clientView.getModel().getMutableEffects().isMotherNatureMovementIncreased() ? 715  this.clientView.getModel().getMutableTurnOrder().getMutableSelectedCard(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer()).get().getPriority() + 2 : 716  this.clientView.getModel().getMutableTurnOrder().getMutableSelectedCard(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer()).get().getPriority(); 717  System.out.println("You can now move mother nature up to " + steps + " steps"); 718  System.out.println("How many steps do you want mother nature to take?"); 719  //get the amount of steps to perform 720  steps = getInt(); 721  //create and initialize moveMotherNature action 722  MoveMotherNature moveMotherNature = new MoveMotherNature(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId(), steps); 723  //create and initialize PlayerActionRequest to send to the server 724  PlayerActionRequest clientPlayerAction = new PlayerActionRequest(moveMotherNature); 725  //send action request to the server 726  socketWrapper.sendMessage(clientPlayerAction); 727  } 728  729  /** 730  * Executes the chooseCloud command, this method asks the user to type a number corresponding to Island's id. 731  * Finally, it creates the chooseCloudTile request and then sends it to the Server. 732  * 733  * @throws IOException if an I/O error occurs 734  */ 735  private void chooseCloud() throws IOException { 736  System.out.println("Select one cloud from 0 to " + (this.clientView.getModel().getClouds().size() - 1)); 737  //get selected Cloud's ID 738  int selectedCloud = getInt(); 739  //create and initialize ChooseCloudTile Object with the selected Island's ID 740  ChooseCloudTile chooseCloudTile = new ChooseCloudTile(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId(), selectedCloud); 741  //create and initialize clientPlayerAction request to send to the Server 742  PlayerActionRequest clientPlayerAction = new PlayerActionRequest(chooseCloudTile); 743  //send clientPlayerAction request to the Server 744  socketWrapper.sendMessage(clientPlayerAction); 745  } 746  747  /** 748  * Executes the endTurn command to end currentPlayer's action turn and move on to the next player 749  */ 750  private void endTurn() throws IOException { 751  //create and initialize endTurnOfActionPhase action 752  EndTurnOfActionPhase endTurnOfActionPhase = new EndTurnOfActionPhase(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getId()); 753  //create and initialize PlayerActionRequest to send to the server 754  PlayerActionRequest clientPlayerAction = new PlayerActionRequest(endTurnOfActionPhase); 755  //send action to the server 756  socketWrapper.sendMessage(clientPlayerAction); 757  } 758  759  /** 760  * print all the available actions basing on current game phase 761  */ 762  private void printGameActions() { 763  //check whether the user is allowed to perform any action (i.e. if is the current player) 764  if (!this.clientView.getNickname().equals(this.clientView.getModel().getMutableTurnOrder().getMutableCurrentPlayer().getNickname())) { 765  System.out.println("No actions are allowed out of turn"); 766  return; 767  } 768  //get current gamePhase 769  GamePhase gamePhase = this.clientView.getModel().getMutableTurnOrder().getGamePhase(); 770  System.out.println("during the " + gamePhase + " phase these are the available commands:"); 771  switch (gamePhase) { 772  //during SETUP phase the user can only play the assistant card 773  case SETUP -> 774  System.out.println("--playAssistantCard (play the assistant card to establish the turn order)"); 775  //print all actions available during ACTION phase 776  case ACTION -> { 777  System.out.println("--moveStudent (move one student from entrance to dining room or one island)"); 778  //only in advanced game mode the user can play a CharacterCard 779  if (this.clientView.getModel().getGameMode() == GameMode.ADVANCED) { 780  System.out.println("--playCharacterCard (activate the powerful effect of the character card)"); 781  } 782  System.out.println("--moveMotherNature (move mother nature and calculate the influence"); 783  System.out.println("--chooseCloud (fill your entrance after moving three students)"); 784  //only in advanced game mode the user can get CharacterCard's info 785  if (this.clientView.getModel().getGameMode() == GameMode.ADVANCED) 786  System.out.println("--characterCardInfo (show the information about one characterCard)"); 787  System.out.println("--endTurn (end your turn)"); 788  } 789  default -> System.out.println("Gamephase is not valid"); 790  } 791  } 792  793  /** 794  * Support method used to acquire chosen characterCard from command line; it requires user to type the characterCard number 795  * (not the index inside Game's list of 3 characterCards but the "id" o the card between 1 and 12). The methods also checks 796  * if the chosen characterCard's number is present among the 3 CharacterCards available during the game. 797  * 798  * @return int representing characterCard's number 799  * @throws IOException if an I/O error occurs 800  */ 801  private int getCharacterCardIndex() throws IOException { 802  System.out.println("Pick one character card from the list above (type the card number)"); 803  int selected; 804  //ArrayList containing the 3 characterCards' numbers available during the game 805  ArrayList<Integer> characterCardsNumbers = 806  this.clientView.getModel().getCharacterCards().stream().map(CharacterCard::getId).collect(Collectors.toCollection(ArrayList::new)); 807  do { 808  //acquire number 809  selected = getInt(); 810  //check if this number belongs to the list of available characterCards 811  if (!characterCardsNumbers.contains(selected)) { 812  System.out.println("CharacterCard not available"); 813  } else { 814  break; 815  } 816  //repeat until the chosen number belongs to the list of available characterCards 817  } while (true); 818  //return the chosen number 819  return selected; 820  } 821  822  /** 823  * Support method to read an integer from command line, this method does not accept 'enter' as input 824  * 825  * @return the integer read from command line 826  * @throws IOException if an I/O error occurs 827  */ 828  private int getInt() throws IOException { 829  int result; 830  while (true) { 831  try { 832  //get text from stdIn 833  String text = stdIn.readLine(); 834  if (text == null) 835  throw new IOException(); 836  //try to parse String from stdIn to Integer 837  result = Integer.parseInt(text); 838  break; 839  } catch (NumberFormatException ex) { 840  System.out.println("This string is not a number, retry."); 841  } 842  //repeat until the String is a valid number 843  } 844  return result; 845  } 846  847  /** 848  * Support method to read an integer from command line, this method accepts 'enter' as input 849  * 850  * @return the integer read from command line or Optional.empty if the user pressed "Enter" 851  * @throws IOException if an I/O error occurs 852  */ 853  private OptionalValue<Integer> getOptionalInt() throws IOException { 854  int result; 855  while (true) { 856  try { 857  //get text from stdIn 858  String text = stdIn.readLine(); 859  if (text == null) 860  throw new IOException(); 861  //if user has typed 'enter' then return Optional.empty 862  if (text.equals("")) 863  return OptionalValue.empty(); 864  //try to parse String from stdIn to Integer 865  result = Integer.parseInt(text); 866  break; 867  } catch (NumberFormatException ex) { 868  System.out.println("This string is not a number, retry."); 869  } 870  //repeat until the String is a valid number 871  } 872  return OptionalValue.of(result); 873  } 874  875  /** 876  * Support method that create the PlayerActionRequest after that user type a PawnColour. 877  * 878  * @param selected selected CharacterCard's index among the 3 available during the game 879  * @param currentPlayer current player in turn, necessary to create PlayCharacterCard action 880  * @return PlayerActionRequest with the selected PawnColour as parameter 881  * @throws IOException if an I/O error occurs 882  */ 883  private PlayerActionRequest createPlayerActionByPawnColour(int selected, PlayerBoard currentPlayer) throws IOException { 884  //create PlayerActionRequest object 885  PlayerActionRequest playerActionRequest; 886  //create PlayCharacterCard object 887  PlayCharacterCard playCharacterCard = null; 888  boolean repeat = true; 889  do { 890  //get the input from stdIn, every switch's case create a playCharacterCard with selected pawnColour 891  switch (stdIn.readLine().toLowerCase()) { 892  case "red" -> { 893  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of(PawnColour.RED), OptionalValue.empty()); 894  repeat = false; 895  } 896  case "yellow" -> { 897  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of(PawnColour.YELLOW), OptionalValue.empty()); 898  repeat = false; 899  } 900  case "green" -> { 901  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of(PawnColour.GREEN), OptionalValue.empty()); 902  repeat = false; 903  } 904  case "pink" -> { 905  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of(PawnColour.PINK), OptionalValue.empty()); 906  repeat = false; 907  } 908  case "blue" -> { 909  playCharacterCard = new PlayCharacterCard(currentPlayer.getId(), selected, OptionalValue.empty(), OptionalValue.of(PawnColour.BLUE), OptionalValue.empty()); 910  repeat = false; 911  } 912  case default -> System.out.println("Colour not valid, try again"); 913  } 914  //repeat until the user types a valid pawnColour 915  } while (repeat); 916  //initialize playerActionRequest 917  playerActionRequest = new PlayerActionRequest(playCharacterCard); 918  //return the playerActionRequest 919  return playerActionRequest; 920  } 921 }