Kamień, papier, nożyczki w C #
Tworzę grę Rock, paper, scissors w języku C # i obecnie mam problem z wyświetleniem komunikatu, gdy ktoś wprowadzi dane wejściowe inne niż R, S lub P. Na przykład próbuję ustawić wartość domyślną w przełączniku oświadczenie do pracy, ale nie mam szczęścia. To, co obecnie mam. Jeśli są jakieś inne problemy, które popełniłem, daj mi znać.
using System;
namespace Rockpaperscissors
{
class Program
{
static void Main(string[] args)
{
string inputPlayer, Computer;
int randomnum;
string loop;
bool keepPlaying = true;
while (keepPlaying)
{
int wins = 0;
int Loses = 0;
int ties = 0;
while (keepPlaying)
{
Random myRandomObject = new Random();
randomnum = myRandomObject.Next(1, 4);
Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
inputPlayer = Console.ReadLine();
inputPlayer = inputPlayer.ToUpper();
switch (randomnum)
{
case 1:
Computer = "Rock";
Console.WriteLine("The computer played Rock");
if (inputPlayer == "R")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "P")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
else if (inputPlayer == "S")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
break;
case 2:
Computer = "Paper";
Console.WriteLine("The computer played Paper");
if (inputPlayer == "P")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "R")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
else if (inputPlayer == "S")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
break;
case 3:
Computer = "Scissors";
Console.WriteLine("The computer played Scissors");
if (inputPlayer == "S")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "R")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
else if (inputPlayer == "P")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
break;
default:
Console.WriteLine("Please enter a correct entry");
break;
}
Console.WriteLine("Scores:\tWins:\t{0},\tLoses:\t{1},\tties:\t{2}", wins, Loses, ties);
Console.WriteLine("Would you like to continue playing? (y/n)");
loop = Console.ReadLine();
if (loop == "y")
{
keepPlaying = true;
}
else if (loop == "n")
{
keepPlaying = false;
}
else
{
}
}
}
}
}
}
Proszę pomóż!
Odpowiedzi
Oto metoda, której używałem z aplikacjami konsolowymi, która bardzo pomaga. Właściwie mam ich kilka do pobierania typów (takich jak int
lub double
) od użytkownika. Pobiera podpowiedź, która jest wyświetlana użytkownikowi i zawiera opcjonalną metodę walidatora, którą uruchomi na danych wejściowych, aby sprawdzić, czy jest poprawna.
Oto jeden dla wprowadzania ciągu:
public static string GetStringFromUser(string prompt, Func<string, bool> validator = null)
{
var isValid = true;
string result;
do
{
if (!isValid)
{
WriteLineColor("Invalid input, please try again.", ConsoleColor.Red);
}
else isValid = false;
Console.Write(prompt);
result = Console.ReadLine();
} while (validator != null && !validator.Invoke(result));
return result;
}
W twoim przypadku możesz to po prostu nazwać tak:
string playerInput = GetStringFromUser(
"To play: enter R for Rock, S for Scissors, P for Paper: ",
x => x.ToUpper() == "R" || x.ToUpper() == "S" || x.ToUpper() == "P");
Console.WriteLine($"You entered: {playerInput}");
Console.Write("\nPress any key to continue...");
Console.ReadKey();
A oto przykładowe dane wyjściowe:

Sugerowałbym zadeklarowanie twoich prawidłowych ruchów w tablicy takiej jak ta:
string[] validMoves = new string[3] { "R", "P", "S" };
następnie przed instrukcją switch dopasuj, jeśli użytkownik podał poprawne lub nie dane wejściowe, jeśli nie jest poprawne, uruchom ponownie while
pętlę, w przeciwnym razie przejdź do switch
instrukcji. Coś jak poniżej:
if (!validMoves.Contains(inputPlayer))
{
Console.WriteLine("Please select a valid move.");
continue;
}
Oto jak powinna wyglądać Twoja główna metoda:
static void Main(string[] args)
{
string inputPlayer, Computer;
int randomnum;
string loop;
bool keepPlaying = true;
string[] validMoves = new string[3] { "R", "P", "S" };
int wins = 0;
int Loses = 0;
int ties = 0;
while (keepPlaying)
{
// while (keepPlaying) // You can get rid of this while loop as it is not helping you out.
// { // second while loop opening
Random myRandomObject = new Random();
randomnum = myRandomObject.Next(1, 4);
Console.Write("To play: enter R for Rock, S for Scissors, P for Paper.");
inputPlayer = Console.ReadLine();
inputPlayer = inputPlayer.ToUpper();
if (!validMoves.Contains(inputPlayer))
{
Console.WriteLine("Please select a valid move.");
continue;
}
switch (randomnum)
{
case 1:
Computer = "Rock";
Console.WriteLine("The computer played Rock");
if (inputPlayer == "R")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "P")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
else if (inputPlayer == "S")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
break;
case 2:
Computer = "Paper";
Console.WriteLine("The computer played Paper");
if (inputPlayer == "P")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "R")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
else if (inputPlayer == "S")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
break;
case 3:
Computer = "Scissors";
Console.WriteLine("The computer played Scissors");
if (inputPlayer == "S")
{
Console.WriteLine("Tie!!\n\n");
ties++;
}
else if (inputPlayer == "R")
{
Console.WriteLine("You win!!\n\n");
wins++;
}
else if (inputPlayer == "P")
{
Console.WriteLine("Computer wins!!\n\n");
Loses++;
}
break;
default: // You can get rid of this default block, it won't ever hit.
Console.WriteLine("Please enter a correct entry");
break;
}
Console.WriteLine("Scores:\tWins:\t{0},\tLoses:\t{1},\tties:\t{2}", wins, Loses, ties);
Console.WriteLine("Would you like to continue playing? (y/n)");
loop = Console.ReadLine();
if (loop == "y")
{
keepPlaying = true;
}
else if (loop == "n")
{
keepPlaying = false;
}
// } // second while loop closing
}
}
Chociaż nie jest to bezpośrednią odpowiedzią na twoje pytanie, powinno pokazać logikę / przepływ programu, który żąda wprowadzenia danych od użytkownika i pyta ponownie, jeśli wprowadzają nieprawidłowe dane.
while (true)
{
Console.WriteLine("1. Print A then C");
Console.WriteLine("2. Print B then C");
Console.Write("Enter option: ");
var input = Console.ReadLine();
switch (input)
{
case "1":
Console.WriteLine("A");
break;
case "2":
Console.WriteLine("B");
break;
default:
Console.WriteLine("Invalid Input. Please try again");
continue;
}
Console.WriteLine("C");
}
Tutaj drukowanie A / B jest jak wybieranie ręki, podczas gdy drukowanie C jest jak pokazywanie wyniku. Do default
zastosowania Branża continue
( patrz dok ), aby powrócić do początku pętli i tak nie drukuje C.

Jeśli wolisz podejście bardziej zorientowane obiektowo, poniżej znajduje się mały przykład.
użycie: dotnet run "Twoje imię"
Program.cs
using System;
namespace RockPaperScissors
{
partial class Program
{
static void Main(string[] args)
{
StartGame(args);
}
static void StartGame(string[] args)
{
var playerName = (args.Length == 1) ? args[0] : "Player 1";
var player1 = new Player(playerName);
var player2 = new ComputerPlayer();
var game = new RPSGame(player1, player2);
game.Init();
while (true)
{
game.DisplayAvailablePlay();
game.ReadPlayerInput();
if (!game.IsValidPlay())
continue;
game.Play();
game.DisplayResult();
}
}
}
}
RPSGame.cs
using System;
namespace RockPaperScissors
{
internal partial class RPSGame
{
public RPSGame(Player firstPlayer, ComputerPlayer secondPlayer)
{
Player1 = firstPlayer;
Player2 = secondPlayer;
}
internal GameStatus CurrentGameStatus = GameStatus.UnStarted;
internal int MatchDraws = 0;
internal IPlayer Player1 { get; }
internal IPlayer Player2 { get; }
public IPlayer CurrentPlayer { get; private set; }
public IPlayer Winner { get; private set; }
internal void Init()
{
SetStatus(GameStatus.Started);
SetCurrentPlayer(Player1);
Console.CancelKeyPress += Console_CancelKeyPress;
}
public void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
this.SetStatus(GameStatus.Ended);
e.Cancel = true;
Environment.Exit(1);
}
internal void DisplayAvailablePlay()
{
Console.WriteLine("To play: enter R for Rock, S for Scissors, P for Paper.");
Console.WriteLine("Press (Ctrl+C or Ctrl+Break) to Exit the game.");
}
internal void ReadPlayerInput()
{
var playerSelectedKey = Console.ReadKey(false);
CurrentPlayer.SetSelectKey(playerSelectedKey.Key);
}
internal void DisplayResult()
{
if (Winner != null)
{
Console.WriteLine();
Console.WriteLine("The Winner is:" + this.Winner.Name);
Console.WriteLine("Played:" + GetDisplayName(this.Winner.SelectedKey));
} else
{
Console.WriteLine("Draw!");
Console.WriteLine("You both Played:" + GetDisplayName(this.Player1.SelectedKey));
}
Console.WriteLine($"Your Score: wins({Player1.AmountWins}), losses({Player1.AmountLoss}), draws({MatchDraws})");
}
private string GetDisplayName(ConsoleKey selectedKey)
{
return Enum.GetName(typeof(ConsoleKey), selectedKey);
}
internal void Play()
{
((ComputerPlayer)Player2).GenerateRandomChoice();
SetWinner(Player1, Player2);
}
private void SetWinner(IPlayer player1, IPlayer player2)
{
var differenceInState = player1.SelectedKey - player2.SelectedKey;
var generatedGameState = (GameState)Math.Abs(differenceInState);
switch (generatedGameState)
{
case GameState.RockScissor:
Winner = (differenceInState < 0) ? player1 : player2;
break;
case GameState.RockPaper:
Winner = (differenceInState < 0) ? player1 : player2;
break;
case GameState.PaperScissor:
Winner = (differenceInState < 0) ? player2 : player1;
break;
default:
Winner = null;
break;
}
UpdateStatistics();
SetStatus(GameStatus.Ended);
}
private void UpdateStatistics()
{
if (Winner == Player1)
{
Player1.AmountWins++;
Player2.AmountLoss++;
}
else if (Winner == Player2)
{
Player2.AmountWins++;
Player1.AmountLoss++;
}
else
{
MatchDraws++;
}
}
internal bool IsValidPlay()
{
switch (CurrentPlayer.SelectedKey)
{
case ConsoleKey.R:
case ConsoleKey.P:
case ConsoleKey.S:
return true;
}
return false;
}
private void SetCurrentPlayer(IPlayer currentPlayer)
{
this.CurrentPlayer = currentPlayer;
}
private void SetStatus(GameStatus status)
{
this.CurrentGameStatus = status;
}
}
}
BasePlayer.cs
using System;
namespace RockPaperScissors
{
class BasePlayer : IPlayer
{
public ConsoleKey SelectedKey { get; set; }
public string Name { get; set; }
public int AmountWins { get; set; }
public int AmountLoss { get; set; }
public void SetSelectKey(ConsoleKey playerSelectedKey)
{
SelectedKey = playerSelectedKey;
}
}
}
ComputerPlayer.cs
using System;
namespace RockPaperScissors
{
class ComputerPlayer : BasePlayer
{
public ComputerPlayer()
{
Name = "Computer Player";
GenerateRandomChoice();
}
public void GenerateRandomChoice()
{
var rnd = new Random();
var choice = rnd.Next(1, 4);
switch(choice)
{
case 1:
SetSelectKey(ConsoleKey.R);
break;
case 2:
SetSelectKey(ConsoleKey.P);
break;
case 3:
SetSelectKey(ConsoleKey.S);
break;
}
}
}
}
GameState.cs
namespace RockPaperScissors
{
public enum GameState
{
RockScissor = 1,
RockPaper = 2,
PaperScissor = 3,
}
}
GameStatus.cs
namespace RockPaperScissors
{
public enum GameStatus
{
UnStarted = 0,
Started = 1,
Ended = -1
}
}
IPlayer.cs
using System;
namespace RockPaperScissors
{
interface IPlayer
{
public string Name { get; set; }
public int AmountWins { get; set; }
public int AmountLoss { get; set; }
public ConsoleKey SelectedKey { get; set; }
void SetSelectKey(ConsoleKey playerSelectedKey);
}
}
Player.cs
using System;
namespace RockPaperScissors
{
class Player : BasePlayer
{
public Player(string name)
{
Name = name;
}
}
}
To jest moje podejście do gry RPS i tego, jak radzić sobie z danymi wejściowymi użytkownika. Jeśli chodzi o projektowanie, zdefiniowałem kilka enum
typów, aby opisać różne ruchy lub wyniki.
public enum Move
{
Rock,
Scissors,
Paper,
}
public enum Outcome
{
Tie,
Loss,
Win,
}
Następnie mam dwie funkcje pomocnicze, jedną do obsługi danych wejściowych użytkownika (część, z którą op miał problem), a drugą do decydowania o grze, ponieważ op przyprawia mnie o ból głowy przy wszystkich powtórzeniach.
W duchu funkcji C #, takich jak int.TryParse(string, out int);
I zaprojektowałem PlayerMove()
funkcję w taki sposób, że zwraca, true
jeśli się powiedzie, i fase
poza tym. Rzeczywisty wynik funkcji jest przypisywany do out
nazwanej zmiennej move
.
static class Program
{
static readonly Random rng = new Random();
// .. Main() goes here ==============
/// <summary>
/// Parses user input and decides what move was chosen if any.
/// </summary>
/// <param name="input">The user input.</param>
/// <param name="move">The user move (output).</param>
/// <returns>False if a move wasn't selected, true otherwise.</returns>
static bool PlayerMove(string input, out Move move)
{
input = input.Trim().ToUpper();
move = 0;
if (string.IsNullOrWhiteSpace(input) || input.Length==0)
{
return false;
}
switch (input[0])
{
case 'R':
move = Move.Rock;
return true;
case 'P':
move = Move.Paper;
return true;
case 'S':
move = Move.Scissors;
return true;
default:
return false;
}
}
/// <summary>
/// Pick which combinations of plays wins for player, has a tie or a loss.
/// </summary>
/// <param name="player">The player move.</param>
/// <param name="computer">The computer move.</param>
/// <returns>The outcome of the game [Tie,Win,Loss]</returns>
static Outcome DecideGame(Move player, Move computer)
{
if (player==computer)
{
return Outcome.Tie;
}
else if ((player==Move.Rock && computer==Move.Scissors)
|| (player==Move.Scissors && computer==Move.Paper)
|| (player==Move.Paper && computer==Move.Rock))
{
return Outcome.Win;
}
else
{
return Outcome.Loss;
}
}
}
a teraz sama gra ma być umieszczona powyżej miejsca, w którym // Main() goes here
jest to wskazane.
Istnieje zmienna, keepPlaying
która śledzi, kiedy zakończyć. Główną pętlą gry jest do { } while(keepPlaying);
pętla.
Kroki są
- Zapytaj użytkownika
- Komputer wybiera
Move
losowo - Przeanalizuj dane wejściowe użytkownika i przypisz gracza
Move
- Jeśli użytkownik nie wykonał prawidłowego ruchu, przejdź do kroku 1
- Jeśli użytkownik właśnie nacisnął klawisz Enter,
input
zawiera pusty ciąg i gra kończy się. - Zdecyduj o wyniku gry
- Wyświetl wynik i dostosuj liczbę wygranych / remisów / porażek.
A główny kod poniżej, aby wykonać powyższe:
static void Main(string[] args)
{
bool keepPlaying = true;
int wins = 0, losses = 0, ties = 0;
do
{
Console.WriteLine();
Console.WriteLine($"Win={wins}, Loss={losses}, Tie={ties}"); Console.Write("To play: enter R for Rock, S for Scissors, P for Paper."); var input = Console.ReadLine(); var computer = (Move)rng.Next(0, 3); // Parse input and decide if the user made a move // or wants to quit (invalid input or none). if (PlayerMove(input, out Move player)) { Console.Write($"Player: {player}, Computer: {computer} => ");
// Decide the outcome of the game here
Outcome game = DecideGame(player, computer);
switch (game)
{
case Outcome.Tie:
ties++;
Console.WriteLine("Tie");
break;
case Outcome.Loss:
losses++;
Console.WriteLine("loss");
break;
case Outcome.Win:
wins++;
Console.WriteLine("Win");
break;
default:
throw new NotSupportedException();
}
}
else
{
// stop when user just pressed enter.
keepPlaying = input.Length>0;
}
} while (keepPlaying);
}