lochtext

http://us.battle.net/sc2/en/profile/2312833/1/lochtext/

ボードゲーム「モノポリー」のモンテカルロシミュレーションプログラム

授業の課題でモンテカルロシミュレーションを作れといわれたので、モノポリーをシミュレートするプログラムをC++で作ってみた。以下のような特徴がある。

  • 乱数発生器としてメルセンヌツイスタを用いた。
  • 繰り返し回数や土地の価格などを自由に変更できる。
  • プレイヤーごとの勝率や、ゲームが既定ターンで終了した割合などを出力できる。
  • プレイヤーの行動パターンがしょぼい。自由に追加できるので追加して遊ぼう。
  • 交渉による土地の交換などは実装していない。
  • チャンスカード、鉄道、エネルギー会社、刑務所なども実装していない。
  • 家を買うところのソースが良くないと思う。再帰とかできれいに実装できるのかな?

以下ソースを貼り付け

  • MC.h
int num_players = 3;
int player_type[3] = {3,2,1};
int num_games = 10000;
int num_turns = 1000;

//numbers,group,buy,pay,1,2,3,4,hotel,house.
int places_data[40][10] ={
0,0,0,0,0,0,0,0,0,0,
1,1,60,2,10,30,90,160,250,50,
2,0,0,0,0,0,0,0,0,0,
3,1,60,4,20,60,180,320,450,50,
4,0,0,0,0,0,0,0,0,0,
5,0,0,0,0,0,0,0,0,0,
6,2,100,6,30,90,270,400,550,50,
7,0,0,0,0,0,0,0,0,0,
8,2,100,6,30,90,270,400,550,50,
9,2,120,8,40,100,300,450,600,50,
10,0,0,0,0,0,0,0,0,0,
11,3,140,10,50,150,450,625,750,100,
12,0,0,0,0,0,0,0,0,0,
13,3,140,10,50,150,450,625,750,100,
14,3,160,12,60,180,500,700,900,100,
15,0,0,0,0,0,0,0,0,0,
16,4,180,14,70,200,550,750,950,100,
17,0,0,0,0,0,0,0,0,0,
18,4,180,14,70,200,550,750,950,100,
19,4,200,16,80,220,600,800,1000,100,
20,0,0,0,0,0,0,0,0,0,
21,5,220,18,90,250,700,875,1050,150,
22,0,0,0,0,0,0,0,0,0,
23,5,220,18,90,250,700,875,1050,150,
24,5,240,20,100,300,750,925,1100,150,
25,0,0,0,0,0,0,0,0,0,
26,6,260,22,110,330,800,975,1150,150,
27,6,260,22,110,330,800,975,1150,150,
28,0,150,28,70,0,0,0,0,0,
29,6,280,24,120,360,850,1025,1200,150,
30,0,0,0,0,0,0,0,0,0,
31,7,300,26,130,390,900,1100,1275,200,
32,7,300,26,130,390,900,1100,1275,200,
33,0,0,0,0,0,0,0,0,200,
34,7,320,28,150,450,1000,1200,1400,200,
35,0,200,25,50,100,200,0,0,0,
36,0,0,0,0,0,0,0,0,0,
37,8,350,35,175,500,1100,1300,1500,200,
38,0,0,0,0,0,0,0,0,0,
39,8,400,50,200,600,1400,1700,2000,200,
};

class GameMaster;

class Player{
private:
int playerNumber_;
int pos_;
int money_;
int playerType_;
bool bank_;
GameMaster  *gameMaster_;

public:
void gameStart(int j, int type_, GameMaster *gm_);

void doStep();

int pos();

int money();

void getmoney(int m);

bool bank();

void buy();

void build();

void buyHouse(int group_);

void pay();

int number();
};

class Place {
public:
	int pos_;
	Player *owner_;
	Player *monopoly_;
	int group_;
	int house_;
	int rent_;

	void init (int position_);
	
	void build();
};

class GameMaster{
public:
int counts_; //経過ターン数
Place place_[40] ;
Player *players_;
bool conc_;
int winner_;

void init();

void doTurn();

bool continueGame();

bool end();

bool unowned(int pos_);

void getPlace(Player *p, int pos_);

bool monopoly(Player *p, int groupNumber_);

void bankrupt(Player *p);

void finalize();
};

  • MC.cpp
#include <iostream>
#include <time.h>
#include "MT.h"
#include "MC.h"
#include <vector>


class CaseData{
private:
	int *result_money_;
	int *result_turns_;
	bool *result_conc_;
    int *winner_;
    double *winrate_;

public:
	void init(){
		result_money_ = new int[num_games*num_players];
		result_turns_ = new int[num_games];
		result_conc_ = new bool[num_games];
        winner_ = new int [num_games];
	}

	void recordResult(int games_, GameMaster &gm_){
		for ( int i = 0; i < num_players; i++){
			result_money_[games_*num_players + i] = gm_.players_[i].money();
		}
           result_turns_[games_] = gm_.counts_;
           result_conc_[games_] = gm_.conc_;
           winner_[games_] = gm_.winner_;
	}
	
	void writeResult(){
            int conc_games_ = 0;
            double av_conc_ = 0;
            double av_turns_ = 0;
            
            winrate_ = new double [num_players];
            for (int i = 0; i < num_players; i++){
                winrate_[i] = 0;
            }
            
            for (int i = 0; i < num_games ; i++){
                 av_conc_ = av_conc_ + (((double)result_conc_[i])/(double)num_games);
                 for (int j = 0; j < num_players ; j++){
                    if (winner_[i] == j){
                        winrate_[j] = winrate_[j] + (double)1/(double)num_games;
                    }
                }
                 if (result_conc_[i] == 1){
                    conc_games_++;
                }
            }

            for (int i = 0; i < num_games ; i++){
                 if (result_conc_[i] == 1){
                 av_turns_ = av_turns_ + (((double)result_turns_[i])/(double)conc_games_);
                 }
             }
            std::cout << "av_conc_" << av_conc_ << std::endl;
            std::cout << "av_turns_" << av_turns_ << std::endl;
            for (int i = 0; i<num_players; i++){
                std::cout << "winrate_of_player_" << i << "_is_" << winrate_[i] <<std::endl;
            }
	}
};

/////////////////////////////////////////////////////

void Player::gameStart(int j, int type_, GameMaster *gm_){
	pos_ = 0;
	money_ = 2000;
	playerType_ = type_;
	bank_ = 1;
	gameMaster_ = gm_;
	playerNumber_ = j;
}

void Player::doStep(){
	int step_ = genrand_int32()%6+1 + genrand_int32()%6+1;
	// std::cout << step_ <<std::endl;
	pos_ = pos_ + step_;
	if(pos_ >39){
		pos_ = pos_ - 40;
		getmoney(200);
	}
}

int Player::pos(){
	return pos_;
}

int Player::money(){
	return money_;
}

void Player::getmoney(int m){
		money_ = money_ + m;
}

bool Player::bank(){
	return bank_;
}

void Player::buy(){
	if (gameMaster_->unowned(pos_) && gameMaster_->place_[pos_].group_ != 0){
		switch(playerType_){
		case (1):
			if (2*places_data[pos_][2] < money_-500){
				money_ = money_ - places_data[pos_][2];
				gameMaster_->getPlace(this,pos_);
			}
			break;
        case (2):
			if (2*places_data[pos_][2] < money_-500 && pos_ < 20){
				money_ = money_ - places_data[pos_][2];
				gameMaster_->getPlace(this,pos_);
			}
			break;
        case (3):
			if (2*places_data[pos_][2] < money_-500 && pos_ > 20){
				money_ = money_ - places_data[pos_][2];
				gameMaster_->getPlace(this,pos_);
			}
			break;
		}
	}
}

void Player::build(){
	for (int i = 1; i <=8; i++){
		if(gameMaster_->monopoly(this, i) == 1){
			buyHouse(i);
		}
	}
}

void Player::buyHouse(int group_){
	std::vector<Place*> array;
	for(int i = 0;i<40;i++){
		if(gameMaster_->place_[i].group_ == group_){
			array.push_back(&(gameMaster_->place_[i]));
		}
	}

	if(group_ == 1 || group_ == 8){
		if(array[1]->house_ < array[0]->house_
			&& money_ - places_data[array[1]->pos_][9] > 500){
			array[1]->build();
			money_ = money_ - places_data[array[1]->pos_][9];
		} else if(array[0]->house_ <5
			&& money_ - places_data[array[0]->pos_][9] > 500){
			array[0]->build();
			money_ = money_ - places_data[array[0]->pos_][9];
		}
	} else {
		if(array[2]->house_ < array[1]->house_
			&& money_ - places_data[array[2]->pos_][9] > 500){
			array[2]->build();
			money_ = money_ - places_data[array[2]->pos_][9];
		}else if(array[1]->house_ < array[0]->house_
			&& money_ - places_data[array[1]->pos_][9] > 500){
			array[1]->build();
			money_ = money_ - places_data[array[1]->pos_][9];
		} else if(array[0]->house_ <5
			&& money_ - places_data[array[0]->pos_][9] > 500){
			array[0]->build();
			money_ = money_ - places_data[array[0]->pos_][9];
		}
	}
}

void Player::pay(){
	int pay_ = gameMaster_->place_[pos_].rent_;
	money_ = money_ - pay_;
	// std::cout << "payed_" << pay_  << "_at_" << pos_ << std::endl;
	gameMaster_->place_[pos_].owner_->getmoney(pay_);
	if (money_ < 0){
		bank_ =0;
		gameMaster_->bankrupt(this);
		// std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!bankrupt" << std::endl;
	}
}

int Player::number(){
    return playerNumber_;
}

///////////////////////////////////////////////////////

void Place::init (int position_){
		pos_ = position_;
		owner_ = NULL;
		monopoly_ = NULL;
		group_ = places_data[pos_][1];
		house_ = 0;
		rent_ = places_data[pos_][3];
	}
	
void Place::build(){
		house_ = house_ + 1;
		rent_ = places_data[pos_][3+house_];
		// std::cout << "bought_house" << std::endl;
	}

////////////////////////////////////////////////////////

void GameMaster::init(){
		counts_ = 0;
		players_ = new Player[num_players];
        conc_ = 0;
        winner_ = -1;
		for (int i = 0; i < num_players; i++){
			players_[i].gameStart(i, player_type[i], this);
		}
		for (int i = 0; i<40;i++){
			place_[i].init(i);
		}
	}
	
void GameMaster::doTurn(){
		for(int k = 0;  k<num_players; k++){
			if(players_[k].bank() == 1){
				players_[k].build();
				players_[k].doStep();
				if(unowned(players_[k].pos())){
					players_[k].buy();
				}else{
					players_[k].pay();
				}
			}
		}
	}
	
bool GameMaster::continueGame(){
		counts_++;
		if (end() == 1){
			// std:: cout << "end()" << std::endl;
			conc_ = 1;
            for (int i = 0; i<num_players; i++){
                if (players_[i].bank() == 1){
                    winner_ = players_[i].number();
                    // std::cout << "winner_is_" << winner_ <<std::endl;
                }
            }
			return 0;
		} else if (counts_ == num_turns){
			conc_ = 0;
			return 0;
		} else {
			return 1;
		}
	}
	
bool GameMaster::end(){
		int end_ = 0;
		for (int i = 0; i<num_players;i++){
			end_ = end_ + players_[i].bank();
		}
		if (end_ < 2){
			return 1;
		} else {
			return 0;
		}
	}

bool GameMaster::unowned(int pos_){
		if (place_[pos_].owner_ == NULL){
			return 1;
		} else {
			return 0;
		}
	}

void GameMaster::getPlace(Player *p, int pos_){
		place_[pos_].owner_ = p;
	}
	
bool GameMaster::monopoly(Player *p, int groupNumber_){
		int  mono_ = 1;
		
		for (int i = 0; i < 40 ; i++){ 
			if (place_[i].group_ == groupNumber_){
				if (place_[i].owner_ != p ){
					mono_ = mono_ * 0;
				}
			}
		}
		
		if (mono_ == 1) {
			return 1;
		} else {
			return 0;
		}
	}
	
void GameMaster::bankrupt(Player *p){
		for (int i = 0; i < 40; i++){
			if(place_[i].owner_ == p){
				place_[i].init(i); 
			}
		}
	}

void GameMaster::finalize(){
	delete players_;
}

/////////////////////////////////////////////////////////
	
int main(void){
    init_genrand((unsigned)time(NULL));
	
	CaseData caseData_;
	caseData_.init();
	GameMaster gameMaster_;
	
	for(int i = 0; i<num_games; i++){
		gameMaster_.init();
		
		//loop for start new game.
		for(int j = 0; j<num_players; j++){
			gameMaster_.players_[j].gameStart(j,player_type[j], &gameMaster_);
		}
		
            if (i % 10000 ==  0){
                  std::cout << "loop_start_"  << i << std::endl;
		}
            
		//loop for game.
		while(gameMaster_.continueGame() == 1){
			// std::cout << "this_is_turn_" << gameMaster_.counts_<< std::endl;
			gameMaster_.doTurn();
		}
		
		caseData_.recordResult(i,gameMaster_);
		gameMaster_.finalize();
	
	}
	
	caseData_.writeResult();
	
	return 0;
}