БлогNot. Свинья-мультиплеер

Свинья-мультиплеер

Просто пример маленького консольного мультиплеера со сравнением нескольких случайных стратегий хода.

Сама игра - старая добрая "Свинка", только я не ограничивал максимальное количество ходов игрока, как и написано в англоязычной статье ("Players take turns to roll a single dice as many times as they wish").

Стратегия 1 равновероятно продолжает или завершает ход, стратегия 2 пытается учесть, сколько очков осталось до победы, третья просто всегда играет, пока за ход не набрано 20 очков, а четвёртая дополняет этот подход случайным выбором.

На серии из 1000 тестов стабильно лучшей оказывается третья, примерно так:

Player   I (RAND): 40 total
Player  II (Q2WIN): 219 total
Player III (AL20): 668 total
Player  IV (AL20T): 73 total

Ниже показан исходник приложения, которое выполнялось в консоли актуальной сборки Visual Studio 2019.

#include <windows.h>
#include <iostream>
#include <string>
using namespace std;
const int PLAYERS = 4, MAX_POINTS = 100;
enum Moves { ROLL, HOLD };

class player { //Основной класс игрока
public:
 player() { current_score = round_score = 0; }
 void addCurrScore() { current_score += round_score; }
 int getCurrScore() { return current_score; }
 int getRoundScore() { return round_score; }
 void addRoundScore(int rs) { round_score += rs; }
 void zeroRoundScore() { round_score = 0; }
 virtual int getMove() = 0;
 virtual ~player() {}
protected:
 int current_score, round_score;
};

class RAND_Player : public player { //Стратегия 1
 virtual int getMove() {
  if (round_score + current_score >= MAX_POINTS) return HOLD;
  if (rand() % 10 < 5) return ROLL;
  if (round_score > 0) return HOLD;
  return ROLL;
 }
};

class Q2WIN_Player : public player { //Стратегия 2
 virtual int getMove() {
  if (round_score + current_score >= MAX_POINTS) return HOLD;
  int q = MAX_POINTS - current_score;
  if (q < 6) return ROLL;
  q /= 4;
  if (round_score < q) return ROLL;
  return HOLD;
 }
};

class AL20_Player : public player { //Стратегия 3
 virtual int getMove() {
  if (round_score + current_score >= MAX_POINTS) return HOLD;
  if (round_score < 20) return ROLL;
  return HOLD;
 }
};

class AL20T_Player : public player { //Стратегия 4 
 virtual int getMove() {
  if (round_score + current_score >= MAX_POINTS) return HOLD;
  int d = (100 * round_score) / 20;
  if (round_score < 20 && d < rand() % 100) return ROLL;
  return HOLD;
 }
};

class Auto_pigGame { //Автоплеер с 4 игроками
public:
 Auto_pigGame() {
  _players[0] = new RAND_Player();
  _players[1] = new Q2WIN_Player();
  _players[2] = new AL20_Player();
  _players[3] = new AL20T_Player();
 }

 ~Auto_pigGame() {
  delete _players[3]; delete _players[2]; delete _players[1]; delete _players[0];
 }

 int play() { //Вернёт номер игрока-победителя 0..PLAYERS-1
  int die, p = 0;
  bool endGame = false;
  while (!endGame) {
   switch (_players[p]->getMove()) {
   case ROLL:
    die = rand() % 6 + 1;
    if (die == 1) {
     cout << "Player " << p + 1 << " rolled " << die << " - current score: " << _players[p]->getCurrScore() << endl << endl;
     nextTurn(p);
     continue;
    }
    _players[p]->addRoundScore(die);
    cout << "Player " << p + 1 << " rolled " << die << " - round score: " << _players[p]->getRoundScore() << endl;
    break;
   case HOLD:
    _players[p]->addCurrScore();
    cout << "Player " << p + 1 << " holds - current score: " << _players[p]->getCurrScore() << endl << endl;
    if (_players[p]->getCurrScore() >= MAX_POINTS)
     endGame = true;
    else nextTurn(p);
   }
  }
  showScore();
  return p;
 }
private:
 void nextTurn(int& p) { //Переход хода
  _players[p]->zeroRoundScore();
  ++p %= PLAYERS;
 }

 void showScore() { //Показать теущие результаты
  cout << endl;
  cout << "Player   I (RAND): " << _players[0]->getCurrScore() << endl;
  cout << "Player  II (Q2WIN): " << _players[1]->getCurrScore() << endl;
  cout << "Player III (AL20): " << _players[2]->getCurrScore() << endl;
  cout << "Player  IV (AL20T): " << _players[3]->getCurrScore() << endl << endl;
 }

 player* _players[PLAYERS];
};

int main () {
 srand(GetTickCount64()); //или GetTickCount в 32-разрядной архитектуре
 const int tests = 1000; //количество тестов
 int stat [PLAYERS] = {0};
 for (int i = 0; i < tests; i++) {
  Auto_pigGame pg;
  stat[pg.play()]++;
 }
 cout << endl;
 cout << "Player   I (RAND): " << stat[0] << " total" << endl;
 cout << "Player  II (Q2WIN): " << stat[1] << " total" << endl;
 cout << "Player III (AL20): " << stat[2] << " total" << endl;
 cout << "Player  IV (AL20T): " << stat[3] << " total" << endl;
 
 return 0;
}

28.10.2021, 18:51 [320 просмотров]


теги: c++ алгоритм random игра