gpt4 book ai didi

matlab - SET游戏赔率模拟(MATLAB)

转载 作者:太空宇宙 更新时间:2023-11-03 19:43:11 26 4
gpt4 key购买 nike

最近发现大卡来了-SET .简而言之,共有 81 张具有以下四种特征的卡片:符号(椭圆形、波浪形或菱形)、颜色(红色、紫色或绿色)、数字(一、二或三)和阴影(实心、条纹或开放)。任务是定位(从选定的 12 张卡片中)一组 3 张卡片,其中四个特征中的每一个在每张卡片上都相同或在每张卡片上都不同(没有 2+1 组合)。

我在 MATLAB 中对其进行了编码,以找到解决方案并估计在随机选择的卡片中拥有一套的几率。

这是我估算赔率的代码:

%% initialization
K = 12; % cards to draw
NF = 4; % number of features (usually 3 or 4)
setallcards = unique(nchoosek(repmat(1:3,1,NF),NF),'rows'); % all cards: rows - cards, columns - features
setallcomb = nchoosek(1:K,3); % index of all combinations of K cards by 3

%% test
tic
NIter=1e2; % number of test iterations
setexists = 0; % test results holder
% C = progress('init'); % if you have progress function from FileExchange
for d = 1:NIter
% C = progress(C,d/NIter);

% cards for current test
setdrawncardidx = randi(size(setallcards,1),K,1);
setdrawncards = setallcards(setdrawncardidx,:);

% find all sets in current test iteration
for setcombidx = 1:size(setallcomb,1)
setcomb = setdrawncards(setallcomb(setcombidx,:),:);
if all(arrayfun(@(x) numel(unique(setcomb(:,x))), 1:NF)~=2) % test one combination
setexists = setexists + 1;
break % to find only the first set
end
end
end
fprintf('Set:NoSet = %g:%g = %g:1\n', setexists, NIter-setexists, setexists/(NIter-setexists))
toc

100-1000 次迭代很快,但要小心更多。在我的家用电脑上进行一百万次迭代大约需要 15 个小时。无论如何,有了 12 张牌和 4 个功能,我有大约 13:1 的机会得到一个系列。这其实是个问题。说明书上说这个数字应该是33:1。最近由 Peter Norvig 证实了这一点.他提供了Python代码,但我还没有测试。

那么你能找到错误吗?欢迎对性能改进提出任何意见。

最佳答案

在查看您的代码之前,我已经解决了编写自己的实现的问题。我的第一次尝试与您已经拥有的非常相似:)

%# some parameters
NUM_ITER = 100000; %# number of simulations to run
DRAW_SZ = 12; %# number of cards we are dealing
SET_SZ = 3; %# number of cards in a set
FEAT_NUM = 4; %# number of features (symbol,color,number,shading)
FEAT_SZ = 3; %# number of values per feature (eg: red/purple/green, ...)

%# cards features
features = {
'oval' 'squiggle' 'diamond' ; %# symbol
'red' 'purple' 'green' ; %# color
'one' 'two' 'three' ; %# number
'solid' 'striped' 'open' %# shading
};
fIdx = arrayfun(@(k) grp2idx(features(k,:)), 1:FEAT_NUM, 'UniformOutput',0);

%# list of all cards. Each card: [symbol,color,number,shading]
[W X Y Z] = ndgrid(fIdx{:});
cards = [W(:) X(:) Y(:) Z(:)];

%# all possible sets: choose 3 from 12
setsInd = nchoosek(1:DRAW_SZ,SET_SZ);

%# count number of valid sets in random draws of 12 cards
counterValidSet = 0;
for i=1:NUM_ITER
%# pick 12 cards
ord = randperm( size(cards,1) );
cardsDrawn = cards(ord(1:DRAW_SZ),:);

%# check for valid sets: features are all the same or all different
for s=1:size(setsInd,1)
%# set of 3 cards
set = cardsDrawn(setsInd(s,:),:);

%# check if set is valid
count = arrayfun(@(k) numel(unique(set(:,k))), 1:FEAT_NUM);
isValid = (count==1|count==3);

%# increment counter
if isValid
counterValidSet = counterValidSet + 1;
break %# break early if found valid set among candidates
end
end
end

%# ratio of found-to-notfound
fprintf('Size=%d, Set=%d, NoSet=%d, Set:NoSet=%g\n', ...
DRAW_SZ, counterValidSet, (NUM_ITER-counterValidSet), ...
counterValidSet/(NUM_ITER-counterValidSet))

在使用 Profiler 发现热点后,可以通过尽可能早地跳出循环来进行一些改进。主要瓶颈是对 UNIQUE 函数的调用。上面我们检查有效集合的那两行可以重写为:

%# check if set is valid
isValid = true;
for k=1:FEAT_NUM
count = numel(unique(set(:,k)));
if count~=1 && count~=3
isValid = false;
break %# break early if one of the features doesnt meet conditions
end
end

不幸的是,对于较大的模拟,模拟仍然很慢。因此,我的下一个解决方案是矢量化版本,对于每次迭代,我们从 12 张手牌中构建一个包含所有可能的 3 张牌组的单一矩阵。对于所有这些候选集,我们使用逻辑向量来指示存在的特征,从而避免调用 UNIQUE/NUMEL(我们希望该组的每张卡片上的特征都相同或不同)。

我承认现在的代码可读性较差且难以遵循(因此我发布了两个版本以进行比较)。原因是我尝试尽可能地优化代码,以便每个迭代循环都完全矢量化。这是最终代码:

%# some parameters
NUM_ITER = 100000; %# number of simulations to run
DRAW_SZ = 12; %# number of cards we are dealing
SET_SZ = 3; %# number of cards in a set
FEAT_NUM = 4; %# number of features (symbol,color,number,shading)
FEAT_SZ = 3; %# number of values per feature (eg: red/purple/green, ...)

%# cards features
features = {
'oval' 'squiggle' 'diamond' ; %# symbol
'red' 'purple' 'green' ; %# color
'one' 'two' 'three' ; %# number
'solid' 'striped' 'open' %# shading
};
fIdx = arrayfun(@(k) grp2idx(features(k,:)), 1:FEAT_NUM, 'UniformOutput',0);

%# list of all cards. Each card: [symbol,color,number,shading]
[W X Y Z] = ndgrid(fIdx{:});
cards = [W(:) X(:) Y(:) Z(:)];

%# all possible sets: choose 3 from 12
setsInd = nchoosek(1:DRAW_SZ,SET_SZ);

%# optimizations: some calculations taken out of the loop
ss = setsInd(:);
set_sz2 = numel(ss)*FEAT_NUM/SET_SZ;
col = repmat(1:set_sz2,SET_SZ,1);
col = FEAT_SZ.*(col(:)-1);
M = false(FEAT_SZ,set_sz2);

%# progress indication
%#hWait = waitbar(0./NUM_ITER, 'Simulation...');

%# count number of valid sets in random draws of 12 cards
counterValidSet = 0;
for i=1:NUM_ITER
%# update progress
%#waitbar(i./NUM_ITER, hWait);

%# pick 12 cards
ord = randperm( size(cards,1) );
cardsDrawn = cards(ord(1:DRAW_SZ),:);

%# put all possible sets of 3 cards next to each other
set = reshape(cardsDrawn(ss,:)',[],SET_SZ)';
set = set(:);

%# check for valid sets: features are all the same or all different
M(:) = false; %# if using PARFOR, it will complain about this
M(set+col) = true;
isValid = all(reshape(sum(M)~=2,FEAT_NUM,[]));

%# increment counter if there is at least one valid set in all candidates
if any(isValid)
counterValidSet = counterValidSet + 1;
end
end

%# ratio of found-to-notfound
fprintf('Size=%d, Set=%d, NoSet=%d, Set:NoSet=%g\n', ...
DRAW_SZ, counterValidSet, (NUM_ITER-counterValidSet), ...
counterValidSet/(NUM_ITER-counterValidSet))

%# close progress bar
%#close(hWait)

如果您有并行处理工具箱,您可以轻松地将普通的 FOR 循环替换为并行 PARFOR(您可能希望再次将矩阵 M 的初始化移动到循环内:替换 M(:) = false;M = false(FEAT_SZ,set_sz2);)

以下是 50000 次模拟的一些示例输出(PARFOR 与 2 个本地实例池一起使用):

» tic, SET_game2, toc
Size=12, Set=48376, NoSet=1624, Set:NoSet=29.7882
Elapsed time is 5.653933 seconds.

» tic, SET_game2, toc
Size=15, Set=49981, NoSet=19, Set:NoSet=2630.58
Elapsed time is 9.414917 seconds.

经过一百万次迭代(12 次为 PARFOR,15 次为无 PARFOR):

» tic, SET_game2, toc
Size=12, Set=967516, NoSet=32484, Set:NoSet=29.7844
Elapsed time is 110.719903 seconds.

» tic, SET_game2, toc
Size=15, Set=999630, NoSet=370, Set:NoSet=2701.7
Elapsed time is 372.110412 seconds.

优势比与Peter Norvig报道的结果一致.

关于matlab - SET游戏赔率模拟(MATLAB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2792511/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com