Камень-ножницы для бумаги C++

Я пытаюсь сделать игру Rock Paper Scissors на C++. Я протестировал свой код на codecademy.com, и он работал правильно, но когда я выполняю его на codewars.com, я получаю эту ошибку:

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

Это мой код:

#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 ответа

Я предполагаю, что вопрос, который вы хотели задать - но не записали в своем вопросе, - это "почему я получаю это сообщение об ошибке?"

Что ж, есть путь через rps()который не возвращает значения. Вы, как человек, могли бы знать, что rps()всегда вызывается только с помощью "камень", "бумага" или "ножницы", но компилятор этого не делает. В таком случае, что должно rps() вернуться, если вы назовете это как rps(std::string("stone"),std::string("knife"))? Он должен что-то вернуть (или вызвать исключение), потому что вы обещали, что он вернет std::string.

Вы можете делать разные вещи:

  • вернуть пустой std::string, если нет победителя, или какое-то другое специальное значение
  • вызвать исключение, если ни одно из условий не выполняется
  • измените тип параметра на перечисление вместо строки, чтобы компилятор мог (возможно) определить, что вы обработали все 9 возможных случаев

Обратите внимание, что здесь вам помогает компилятор. Почему завершение непустой функции без возврата значения не приводит к ошибке компилятора?

Как уже упоминалось в другом ответе, параметры p1 и p2 из std::string rps(const std::string& p1, const std::string& p2) находятся std::strings и может - с точки зрения компилятора - содержать любое значение.

Учитывая, что может быть комбинация p1 и p2для которого не выполняется ни одно из условий. Если вы не вернете значение из void функция (кроме main) это вызовет неопределенное поведение.

Таким образом, вам нужно либо сгенерировать исключение в этот момент, либо вернуть, например, пустую строку.

Но было бы лучше изменить код, чтобы параметры и возвращаемые типы были перечислениями, а функция сначала проверяла выигрышные ситуации и по умолчанию возвращала, что никто не выиграл.

#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;
}

Если вам действительно нужно использовать строки в качестве входных данных, вы хотите проверить / преобразовать их за пределами вашего rps функция с чем-то вроде этого:

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");
  }
}
Другие вопросы по тегам