C++ Rock Paper Scissors

669 views Asked by At

I`m trying to make Rock Paper Scissors game in c++.I tested my code on codecademy.com And It worked Properly but when I execute it on codewars.com It gives me this error :

main.cpp:29:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^

This is my code :

#include <string>
#include <iostream>

std::string rps(const std::string& p1, const std::string& p2)
{
  if (p1 == "rock" && p2 == "paper") {
    return "Player 2 won!";
  } else if (p1 == "rock" && p2 ==  "scissors") {
    return "Player 1 won!";
  } else if (p1 == "rock" && p2 ==  "rock") {
    return "Draw";
  } else if (p1 == "paper" && p2 == "rock") {
    return "Player 1 won!";
  } else if (p1 == "paper" && p2 == "scissors") {
    return "Player 2 won!";
  } else if (p1 == "paper" && p2 == "paper") {
    return "Draw";
  } else if (p1 == "scissors" && p2 == "rock") {
    return "Player 2 won!";
  } else if (p1 == "scissors" && p2 == "paper") {
    return "Player 1 won!";
  } else if (p1 == "scissors" && p2 == "scissors") {
    return "Draw";
  }
}
int main() {
  std::cout << rps("rock", "scissors") << "\n";
  std::cout << rps("rock", "paper") << "\n";
  std::cout << rps("rock", "rock") << "\n";
  std::cout << rps("scissors", "paper") << "\n";
  std::cout << rps("scissors", "rock") << "\n";
  return 1;
}
2

There are 2 answers

2
t.niese On

As already mentioned in the other answer, the parameters p1 and p2 of std::string rps(const std::string& p1, const std::string& p2) are std::strings and can - from the perspective of the compiler - contain any value.

Given that there can be a combination of p1 and p2 for which none of the conditions is true. If you don't return a value from a void function (except main) it will cause undefined behavior.

So you either need to throw an exception at that point or return e.g. an empty string.

But it would be better to change the code so that the parameters and return types are enums and the function first checks for the win situations and as a default returns that no one won.

#include <iostream>
#include <vector>

enum class Winner { kPlayerOne, kPlayerTwo, kNone };
enum class Hand { kRock, kScissors, kPaper };

Winner rps(const Hand &p1, const Hand &p2) {
    
  if (p1 == Hand::kRock && p2 == Hand::kPaper) {
    return Winner::kPlayerTwo;
  } else if (p1 == Hand::kRock && p2 == Hand::kScissors) {
    return Winner::kPlayerOne;
  } else if (p1 == Hand::kPaper && p2 == Hand::kRock) {
    return Winner::kPlayerOne;
  } else if (p1 == Hand::kPaper && p2 == Hand::kScissors) {
    return Winner::kPlayerTwo;
  } else if (p1 == Hand::kScissors && p2 == Hand::kRock) {
    return Winner::kPlayerTwo;
  } else if (p1 == Hand::kScissors && p2 == Hand::kPaper) {
    return Winner::kPlayerOne;
  }
  
  return Winner::kNone;
}

std::string to_string(const Winner &winner) {
  if (winner == Winner::kPlayerOne) {
    return "Player 1 won!";
  } else if (winner == Winner::kPlayerTwo) {
    return "Player 2 won!";
  } else {
    return "Draw";
  }
}

int main() {
  std::cout << to_string(rps(Hand::kRock, Hand::kScissors)) << "\n";
  std::cout << to_string(rps(Hand::kRock, Hand::kPaper)) << "\n";
  std::cout << to_string(rps(Hand::kRock, Hand::kRock)) << "\n";
  std::cout << to_string(rps(Hand::kScissors, Hand::kPaper)) << "\n";
  std::cout << to_string(rps(Hand::kScissors, Hand::kRock)) << "\n";
  return 1;
}

If you really need to use strings as an input you want to verify/convert them outside of your rps function with something like that:

Hand string_to_hand(const std::string &str) {
  if (str == "rock") {
    return Hand::kRock;
  } else if (str == "scissors") {
    return Hand::kScissors;
  } else if (str == "paper") {
    return Hand::kPaper;
  } else {
    throw std::runtime_error("input is not a valid hand");
  }
}
1
Adriaan de Groot On

I'm going to assume the question you wanted to ask -- but didn't write down in your question -- is "why do I get this error message?"

Well, there's a path through rps() that does not return a value. You, as a person, might know that rps() is always called only with "rock", "paper", or "scissors", but the compiler does not. In that case, what should rps() return if you call it as rps(std::string("stone"),std::string("knife")) ? It has to return something (or throw an exception) because you've promised it would return a std::string.

There's various things you might do:

  • return an empty std::string if there is no winner, or some other special value
  • raise an exception if none of the conditions is true
  • change your parameter type to an enumeration instead of a string, so that the compiler can (possibly) determine that you have handled all 9 possible cases

Note that the compiler is helping you here. Why does flowing off the end of a non-void function without returning a value not produce a compiler error?