对于大富翁游戏的简单建模
昨天晚上和朋友们一起玩大富翁游戏,玩了几局总是输,我怀疑先出发的玩家大概率是赢家。于是和一朋友利用matlab对游戏进行仿真。游戏规则已经简化,但基本符合我们的游戏规则。下面是代码部分。
主程序。
主程序
clear;clc;
dbstop if error
%% 模拟大富翁
tic
ITER = 2000;
winer = cell(ITER,11);
for TIMES = 1:ITER
% 定义地图
D.placedata = [2400,200,1200,6000,11000,1000,1200;
3000,300,1600,7000,13000,1500,1500;
2600,300,1600,7000,13000,1500,1300;
2800,300,1600,7000,13000,1500,1400;
2600,300,1600,7000,13000,1500,1300;
3200,400,2000,8000,16000,2000,1600;
3600,400,2000,8000,16000,2000,1800;
2200,200,1200,6000,11000,1000,1100;
3400,400,2000,8000,16000,2000,1700;
2200,200,1200,6000,11000,1000,1100;
2400,200,1200,6000,11000,1000,1200;
3200,400,2000,8000,16000,2000,1600;
2800,300,1600,7000,13000,1500,1400;
3400,400,2000,8000,16000,2000,1700;
3000,300,1600,7000,13000,1500,1500;
3600,400,2000,8000,16000,2000,1800;
2000,3000,6000,9000,12000,+inf,1000;
2000,3000,6000,9000,12000,+inf,1000;
2000,3000,6000,9000,12000,+inf,1000;
2000,3000,6000,9000,12000,+inf,1000;];
% 0表示起始地,+2000,1-16表示地点索引,17-20表示连锁地点,-1表示机会和命运,-2表示获得一枚幸运星,-3表示什么也不做
D.map = [0,1,17,2,-1,3,4,-1,5,-2,-1,6,7,18,8,-3,-1,9,10,11,12,19,-1,20,-3,13,14,-1,15,16];
% 第一列为目前所在地,第二列为目前所有金钱,第三列为目前持有空地,目前持有一星地,二星地,三星地,现状态 0为正常,1为跳过
% 第八列为幸运星个数 第九列为在抵押房产,第十列为是否已经遍历,第十一列为玩家索引
D.N = 4;%N个玩家
D.starts = 7;%幸运星个数为7
D.people = cell(D.N,11);
%初始化目前所在地
for i = 1:size(D.people,1)
D.people{i,1} = 1;
D.people{i,2} = 15000;
D.people{i,7} = 0;
D.people{i,10} = 0;
D.people{i,11} = i;
end
turns = 0;
while true%一局
%循环遍历每个玩家
player = 1;
while true%一轮
if size(D.people,1)==1
break
end
D.people{player,10} = 1;
%如果要跳过,则跳过
if D.people{player,7}==1
D.people{player,7} = 0;
if sum(cell2mat(D.people(:,10))) ~= size(D.people,1)
player = find(cell2mat(D.people(:,10)) == 0);
player = player(1);
continue
else
break
end
end
%随机抛色子
dian = randperm(6,1);
[D.people{player,1},tf] = chulidian(D.people{player,1}+dian);
%得到现在地点是什么内容
if tf == 1 %如果经历了原点
D.people{player,2} = D.people{player,2}+2000;
end
content = D.map(D.people{player,1});
% D = contentcheck(D);
if content == 0
elseif content == -2
D.people{player,8} = D.people{player,8}+1;
D = xingyunxingcheck(D,player);
elseif content == -1
D = destinyandchance(D,player);
elseif content == -3
else
[D,tf] = paycheck(D,player);
if tf ~= 1%如果没有破产则进行购买检测
D = buycheck(D,player);
% else%如果破产则找到下一个玩家
% if sum(cell2mat(D.people(:,10))) ~= size(D.people,1)
% player = find(cell2mat(D.people(:,10)) == 0);
% player = player(1);
% else
% break
% end
end
end
% disp(sum(cell2mat(D.people(:,10))))
% disp(size(D.people,1))
% disp('-----------------------------------')
if sum(cell2mat(D.people(:,10))) ~= size(D.people,1)
player = find(cell2mat(D.people(:,10)) == 0);
player = player(1);
else
break
end
end
% for i = 1:size(D.people,1)
% if isempty(D.people(i,1))
% D.people(i,:) = [];
% end
% end
%将所有玩家的被访问信息置零
for i = 1:size(D.people,1)
D.people{i,10} = 0;
end
turns = turns+1;
if size(D.people,1) == 1
break
end
end
winer(TIMES,:) = D.people;
clear D
disp(TIMES)
end
%% 结果分析
%检查最后获胜玩家和投色子的先后顺序的关系
win = zeros(ITER,1);
money = zeros(ITER,1);
for i = 1:size(winer,1)
win(i) = winer{i,11};
money(i) = winer{i,2};
end
figure(1)
histogram(win)
figure(2)
histogram(money)
toc
%%
xlswrite('wind.xls', win);
xlswrite('money.xls', money);
得到所有玩家的幸运星列表
function Dout = xingyunxingcheck(D,player)
%得到所有玩家的幸运星列表
startslist = cell2mat(D.people(:,8));
% 如果幸运星被分配完,则选取最多的几位玩家随机在自己地盘上盖房子
if sum(startslist)==D.starts
%统计该玩家有多少块地以及可以建房屋的地
di = D.people(player,3:5);
%统计这些地建一所房屋需要花费多少钱,优先建造有2所房屋的地方
for i = 3:-1:1
if isempty(di(i))
continue
else
houseidx = cell2mat(di(i));
houseconprice = D.placedata(houseidx,6);
houseconprice(houseconprice==+inf) = [];
if isempty(houseconprice)
continue
else
%取最大的一个建造价格,造房子
[house,houseidx] = find(houseconprice==max(houseconprice));
house = house(1);
houseidx = houseidx(1);
D.people{player,i}(houseidx) = [];
D.people{player,i+1}(end+1) = house;
break
end
end
end
%将所有玩家幸运星清零
for i = 1:size(D.people,1)
D.people{i,8} = 0;
end
end
Dout = D;
规则判断与执行
function Dout = destinyandchance(D,player)
object = [1,1,2,2,3,3,4,4,5,6,7,8,9,10,11,11];
len = length(object);
r = randperm(len,1);
event = object(r);
if event == 1%减一个幸运星
D.people{player,8} = D.people{player,8}-1;
elseif event == 2%加一个幸运星
D.people{player,8} = D.people{player,8}+1;
D = xingyunxingcheck(D,player);
elseif event == 3%让该玩家与另一玩家减500
tempplayer = randperm(size(D.people,1),1);
while tempplayer == player
tempplayer = randperm(size(D.people,1),1);
end
%找到tempplayer的初始编号
startind = D.people{tempplayer,11};
D.people{player,2} = D.people{player,2}-500;
D.people{tempplayer,2} = D.people{tempplayer,2}-500;
D = breakcheck(D,player);
[~,row] = ismember(startind,cell2mat(D.people(:,11)));
D = breakcheck(D,row);
elseif event == 4%让该玩家减750
D.people{player,2} = D.people{player,2}-750;
D = breakcheck(D,player);
elseif event == 5%让该玩家减100
D.people{player,2} = D.people{player,2}-100;
D = breakcheck(D,player);
elseif event == 6%让该玩家减200
D.people{player,2} = D.people{player,2}-200;
D = breakcheck(D,player);
elseif event == 7%让该玩家减500
D.people{player,2} = D.people{player,2}-500;
D = breakcheck(D,player);
elseif event == 8%让该玩家加1850
D.people{player,2} = D.people{player,2}-1850;
elseif event == 9%让该玩家加1000
D.people{player,2} = D.people{player,2}-1850;
elseif event == 10%加3000停一轮
D.people{player,2} = D.people{player,2}+3000;
D.people{player,7} = 1;
elseif event == 11%2/3 stop 1/3 nothing
if rand()<2/3
D.people{player,7} = 1;
end
end
Dout = D;
支付玩家过路费&得到玩家到达地点
function [Dout,tf] = paycheck(D,player)
%支付玩家过路费
%得到玩家到达地点
dian = D.map(D.people{player,1});
%判断地点的归属
tempplayer = 0;
for i = 1:size(D.people,1)
for j = 3:6
if ismember(dian,D.people{i,j})
tempplayer = i;
break
end
end
if tempplayer ~=0
break
end
end
if tempplayer ~= 0
%支付玩家乾
D.people{tempplayer,2} = D.people{tempplayer,2}+D.placedata(dian,j-1);
D.people{player,2} = D.people{player,2}-D.placedata(dian,j-1);
[D,tf] = breakcheck(D,player);
else
tf = 0;
end
Dout = D;
选择是否购买该地
function Dout = buycheck(D,player)
%选择是否购买该地
%得到该土地购买价格
dian = D.map(D.people{player,1});
price = D.placedata(dian,1);
%得到该玩家剩余乾数量
res = D.people{player,2};
%如果剩余乾数量大于土地购买价格则购买土地
%判断地点的归属
tempplayer = 0;
for i = 1:size(D.people,1)
for j = 3:6
if ismember(dian,D.people{i,j})
tempplayer = i;
break
end
end
if tempplayer ~=0
break
end
end
%如果没有人拥有这件地产则选择够不够买
if tempplayer == 0
if price<res
D.people{player,2} = D.people{player,2}-price;
D.people{player,3}(end+1) = dian;
end
end
%如果土地是自己的则选择是不是购买绿房子
if tempplayer == player
if j ~= 6
upgradeprice = D.placedata(dian,6);
upgradeprice(upgradeprice==+inf) = [];
if ~isempty(upgradeprice)
if upgradeprice<res
%升级房屋
D.people{player,j}(D.people{player,j}==dian) = [];
D.people{player,j+1}(end+1) = dian;
end
end
end
end
Dout = D;
找到破产的玩家
function [Dout,tf] = breakcheck(D,player)
tf = 0;
%找到破产的玩家
own = D.people{player,2};
if own<0
%得到该玩家欠债数
%清算该玩家的房产
house = D.people(player,3:6);
%先卖房屋数量少的房产
for i = 1:4
payoff = 0;
h = house{i};
if ~isempty(h)
%将抵押费从小到大排序
hmortgage = D.placedata(h,7);
hmortgage(hmortgage == +inf) = [];
[val,ind] = sort(hmortgage,'ascend');
hmortgage = val;
j = 1;
while true
%首先卖掉所有房子
own = own+(i-1)*0.5*D.placedata(ind(j),6);
%将该房产绿色房子数量减至0
D.people{player,i+2}(ind(j)) = [];
D.people{player,3}(end+1) = h(ind(j));
if own < 0
%卖掉该房屋
own = own+D.placedata(ind(j),7);
D.people{player,3}(end) = [];
D.people{player,9}(end+1) = h(ind(j));
end
if own >0
payoff = 1;
break
end
hmortgage(j) = [];
if isempty(hmortgage)
break
else
[val,ind] = sort(hmortgage,'ascend');
hmortgage = val;
end
end
if payoff == 1
break
end
end
end
if payoff == 1
D.people{player,2} = own;
else
D.people(player,:) = [];
tf = 1;
end
end
Dout = D;
处理位置点
function [dian,tf] = chulidian(data)
if sum(data>30)>0
tf = 1;
else
tf = 0;
end
data(data>30) = data(data>30)-30;
dian = data;
end
获胜者分布
获胜者资金分布
附加 朋友文章