在刷手机的时候刷到了猫猫围棋小游戏https://puyogo.app/,能够非常直观的教大家围棋的基础规则,甚至网友在学会规则后,柯洁需要经过六个小时深思熟虑才敢应战:

于是我复刻了一个MATLAB版本,运行效果如下:



完整代码
matlab
function catgo
% 坐标区域创建
fig = figure('Name','Cat go by slandarer', 'Units','normalized', ...
'Position',[.1,.1,.55,.8], 'WindowButtonDownFcn', @gogogo, 'WindowKeyPressFcn',@tbam);
ax = axes('Parent',fig, 'Color',[215,177,116]./255, 'PlotBoxAspectRatio',[1,1,1], ...
'XLim',[1 - .6, 9 + .6], 'YLim',[1 - .6, 9 + .6], 'NextPlot','add', 'XColor','none', 'YColor','none');
% 绘制棋盘
tx = [1:9; 1:9; nan(1,9)]; ty = [ones(1,9); 9.*ones(1,9); nan(1,9)];
plot(ax, tx(:), ty(:), 'LineWidth',1, 'Color','k')
plot(ax, ty(:), tx(:), 'LineWidth',1, 'Color','k')
tx = [.9, .9, 9.1, 9.1, .9, .9];
ty = [.9, 9.1, 9.1, .9, .9, 9.1];
plot(ax, tx, ty, 'LineWidth',3, 'Color','k')
tt = linspace(0, 2*pi, 50); tx = cos(tt).*.08; ty = sin(tt).*.08;
fill(ax, tx + 3, ty + 3, [0,0,0]); fill(ax, tx + 7, ty + 3, [0,0,0])
fill(ax, tx + 3, ty + 7, [0,0,0]); fill(ax, tx + 7, ty + 7, [0,0,0])
% 数据初始化
goMat = zeros(9,9); turn = 1; emojiMap = zeros(0,3);
PMat{9,9} = []; LMat{9,9}=[];
GMat{1} = goMat;
EMat{1} = emojiMap;
function gogogo(~, ~)
xxyy = get(ax, 'CurrentPoint');
pos = [round(xxyy(1,1)), round(xxyy(1,2))];
pos(pos < 1) = 1; pos(pos > 9) = 9;
if (goMat(pos(1), pos(2)) == 0)
[SX, SY] = find(sign(goMat) == turn); SSet = [[SX, SY]; pos];
[OX, OY] = find(sign(goMat) == -turn); OSet = [OX, OY];
SNum = [0; unique(goMat(sign(goMat) == turn))];
PSet = repmat(pos, [4,1]) + [-1,0;1,0;0,-1;0,1];
ISSet = intersect(PSet, SSet, 'rows');
IOSet = intersect(PSet, OSet, 'rows');
flag = true;
if size(IOSet,1) == 4
flag = false;
end
newNum = min(setdiff(1:(max(abs(SNum))+1), abs(SNum)));
% 落子
switch size(ISSet,1)
case 0
goMat(pos(1), pos(2)) = turn*newNum;
drawStone(pos);
emojiMap = [emojiMap; pos, turn*newNum];
case 1
goMat(pos(1), pos(2)) = goMat(ISSet(1), ISSet(2));
drawStone(pos); drawStone(ISSet);
emojiMap(emojiMap(:,3) == goMat(ISSet(1), ISSet(2)),:) = [pos, goMat(ISSet(1), ISSet(2))];
case {2,3,4}
goMat(pos(1), pos(2)) = turn*newNum;
drawStone(pos);
for i = 1:size(ISSet,1)
emojiMap(emojiMap(:,3) == goMat(ISSet(i,1), ISSet(i,2)),:) = [];
goMat(goMat == goMat(ISSet(i,1), ISSet(i,2))) = turn*newNum;
drawStone([ISSet(i,1), ISSet(i,2)])
end
emojiMap = [emojiMap; pos, turn*newNum];
end
% 提对方子
[EX, EY] = find(goMat == 0); ESet = [EX, EY];
for i = 1:size(IOSet,1)
tind = goMat(IOSet(i,1), IOSet(i,2));
[tX, tY] = find(goMat == tind); tSet = [tX, tY];
tN = size(tSet, 1);
TSet = unique([tSet + repmat([-1,0], [tN,1]);
tSet + repmat([1,0], [tN,1]);
tSet + repmat([0,-1], [tN,1]);
tSet + repmat([0,1], [tN,1])],'rows');
ITSet = intersect(TSet, ESet, 'rows');
switch size(ITSet, 1)
case 0
flag = true;
emojiMap(emojiMap(:,3) == tind, :) = [];
for j = 1:size(tSet, 1)
goMat(tSet(j,1), tSet(j,2)) = 0;
delete(PMat{tSet(j,1), tSet(j,2)});
delete(LMat{tSet(j,1), tSet(j,2)});
end
case 1
emojiMap(emojiMap(:,3) == tind, :) = [IOSet(i,:), tind];
end
end
% 提己方子
[EX, EY] = find(goMat == 0); ESet = [EX, EY];
tind = goMat(pos(1), pos(2));
[tX, tY] = find(goMat == tind); tSet = [tX, tY];
tN = size(tSet, 1);
TSet = unique([tSet + repmat([-1,0], [tN,1]);
tSet + repmat([1,0], [tN,1]);
tSet + repmat([0,-1], [tN,1]);
tSet + repmat([0,1], [tN,1])],'rows');
ITSet = intersect(TSet, ESet, 'rows');
switch size(ITSet, 1)
case 0
emojiMap(emojiMap(:,3) == tind, :) = [];
for j = 1:size(tSet, 1)
goMat(tSet(j,1), tSet(j,2)) = 0;
delete(PMat{tSet(j,1), tSet(j,2)});
delete(LMat{tSet(j,1), tSet(j,2)});
end
case 1
emojiMap(emojiMap(:,3) == tind, :) = [pos, tind];
end
if flag
turn = - turn;
GMat{end + 1} = goMat;
EMat{end + 1} = emojiMap;
end
drawEar()
drawEmojiS()
end
end
function tbam(~, key)
if strcmp(key.Key, 'b')
if length(EMat) >= 2
GMat(end) = [];
EMat(end) = [];
goMat = GMat{end};
emojiMap = EMat{end};
turn = - turn;
for i = 1:9
for j = 1:9
drawStone([i,j])
end
end
drawEar()
drawEmojiS()
end
end
end
% 绘制猫耳朵
function drawEar(~, ~)
tobj = findobj(ax, 'UserData', 'slan');
for i = length(tobj):-1:1
delete(tobj(i))
end
baseMat = goMat;
ruMat = [[zeros(1,8);goMat(1:(end-1), 2:end)],zeros(9,1)];
rdMat = [[goMat(2:end, 2:end);zeros(1,8)],zeros(9,1)];
tmapru = (baseMat ~= ruMat) & (sign(baseMat) == sign(ruMat)) & (baseMat ~= 0);
tmaprd = (baseMat ~= rdMat) & (sign(baseMat) == sign(rdMat)) & (baseMat ~= 0);
tgoru = goMat(2:end, :);
tgord = goMat(1:(end-1), :);
tru = tmapru(2:end, :);
trd = tmaprd(1:(end-1), :);
tbool = tru & trd & (sign(tgoru) ~= sign(tgord));
tru(tbool) = 0;
trd(tbool) = 0;
tmapru(2:end, :) = tru;
tmaprd(1:(end-1), :) = trd;
[rux, ruy] = find(tmapru == 1);
for i = 1:length(rux)
tturn = sign(goMat(rux(i), ruy(i))); C = [105,105,107]./255.*(tturn>0) + [228,228,228]./255.*(tturn<0);
fill(ax, [(rux(i)-1+.2), (rux(i)-.5-.03), (rux(i)-.45), (rux(i)-.2), (rux(i)-.5+.03), (rux(i)-1+.45)], ...
[(ruy(i)+1-.45), (ruy(i)+.5-.03), (ruy(i)+.2), (ruy(i)+.45), (ruy(i)+.5+.03), (ruy(i)+1-.2)], C, 'EdgeColor','none','UserData','slan')
plot(ax, [(rux(i)-1+.2), (rux(i)-.5-.03), (rux(i)-.45)], [(ruy(i)+1-.45), (ruy(i)+.5-.03), (ruy(i)+.2)], 'Color','k', 'LineWidth',2,'UserData','slan')
plot(ax, [(rux(i)-1+.45), (rux(i)-.5+.03), (rux(i)-.2)], [(ruy(i)+1-.2), (ruy(i)+.5+.03), (ruy(i)+.45)], 'Color','k', 'LineWidth',2,'UserData','slan')
end
[rdx, rdy] = find(tmaprd == 1);
for i = 1:length(rdx)
tturn = sign(goMat(rdx(i), rdy(i)));
C = [105,105,107]./255.*(tturn>0) + [228,228,228]./255.*(tturn<0);
fill(ax, [(rdx(i)+.2), (rdx(i)+.5-.03), (rdx(i)+1-.45), (rdx(i)+1-.2), (rdx(i)+.5+.03), (rdx(i)+.45)], ...
[(rdy(i)+.45), (rdy(i)+.5+.03), (rdy(i)+1-.2), (rdy(i)+1-.45), (rdy(i)+.5-.03), (rdy(i)+.2)], C, 'EdgeColor','none','UserData','slan')
plot(ax, [(rdx(i)+.2), (rdx(i)+.5-.03), (rdx(i)+1-.45)], [(rdy(i)+.45), (rdy(i)+.5+.03), (rdy(i)+1-.2)], 'Color','k', 'LineWidth',2,'UserData','slan')
plot(ax, [(rdx(i)+.45), (rdx(i)+.5+.03), (rdx(i)+1-.2)], [(rdy(i)+.2), (rdy(i)+.5-.03), (rdy(i)+1-.45)], 'Color','k', 'LineWidth',2,'UserData','slan')
end
end
% 绘制表情
function drawEmojiS(~,~)
tobj = findobj(ax, 'UserData', 'emoji');
for i = length(tobj):-1:1
delete(tobj(i))
end
ttype = ones(size(emojiMap,1), 1);
[EX, EY] = find(goMat == 0); ESet = [EX, EY];
for i = 1:size(emojiMap,1)
tind = emojiMap(i,3);
[tX, tY] = find(goMat == tind); tSet = [tX, tY];
tN = size(tSet, 1);
TSet = unique([tSet + repmat([-1,0], [tN,1]);
tSet + repmat([1,0], [tN,1]);
tSet + repmat([0,-1], [tN,1]);
tSet + repmat([0,1], [tN,1])],'rows');
ITSet = intersect(TSet, ESet, 'rows');
if size(ITSet,1) == 1
ttype(i) = 3;
[OX, OY] = find(sign(goMat) == -sign(tind)); OSet = [OX, OY];
IOOSet = intersect(TSet, OSet, 'rows');
for j = 1:size(IOOSet, 1)
if ttype(emojiMap(:,3) == goMat(IOOSet(j,1),IOOSet(j,2))) ~= 3
ttype(emojiMap(:,3) == goMat(IOOSet(j,1),IOOSet(j,2))) = 2;
end
end
end
end
for i = 1:size(emojiMap,1)
drawEmoji(emojiMap(i,1:2), ttype(i))
end
end
function drawEmoji(pos, type)
switch type
case 1
ttt1 = linspace(pi - pi/12, 2*pi - pi/12, 50);
ttt2 = linspace(pi + pi/12, 2*pi + pi/12, 50);
ttt3 = linspace(0, 2*pi, 50);
ttx = [cos(ttt1).*.05-.05, cos(ttt2).*.05+.05] + pos(1);
tty = [sin(ttt1).*.05, sin(ttt2).*.05] + pos(2) -.02;
plot(ax, ttx, tty, 'Color','k', 'LineWidth',1.5, 'UserData','emoji')
fill(ax, cos(ttt3).*.06 + pos(1) - .25, sin(ttt3).*.06 + pos(2), [0,0,0], 'UserData','emoji')
fill(ax, cos(ttt3).*.06 + pos(1) + .25, sin(ttt3).*.06 + pos(2), [0,0,0], 'UserData','emoji')
case 2
ttt1 = linspace(0+pi/5, pi-pi/5, 50);
ttt3 = linspace(0, 2*pi, 50);
plot(ax, cos(ttt1).*.15 + pos(1), sin(ttt1).*.12 + pos(2) - .25, 'Color','k', 'LineWidth',1.5, 'UserData','emoji')
plot(ax, [.16,.35] + pos(1), [.12,.16] + pos(2), 'Color','k', 'LineWidth',2, 'UserData','emoji')
plot(ax, [-.16,-.35] + pos(1), [.12,.16] + pos(2), 'Color','k', 'LineWidth',2, 'UserData','emoji')
fill(ax, cos(ttt3).*.06 + pos(1) - .25, sin(ttt3).*.06 + pos(2), [0,0,0], 'UserData','emoji')
fill(ax, cos(ttt3).*.06 + pos(1) + .25, sin(ttt3).*.06 + pos(2), [0,0,0], 'UserData','emoji')
case 3
ttt1 = linspace(0+pi/8, pi-pi/8, 50);
ttx = cos(ttt1).*.22 + pos(1); ttx = [ttx, ttx(1)];
tty = sin(ttt1).*.22 + pos(2) - .35; tty = [tty, tty(1)];
ttt3 = linspace(0, 2*pi, 50);
plot(ax, ttx, tty, 'Color','k', 'LineWidth',1.5, 'UserData','emoji')
ttx = [.1,.1, nan, .16, .16, nan, .22, .22, nan, .28, .28, nan, .34, .34] + pos(1);
tty = [.2,.4, nan, .14, .42, nan, .16, .36, nan, .01, .28, nan, .1, .25] + pos(2);
plot(ax, ttx, tty, 'Color','k', 'LineWidth',1, 'UserData','emoji')
ttx = [-.25,-.25, nan, -.3, -.3, nan, -.2, -.2] + pos(1);
tty = [-.21,-.08, nan, -.18,-.06, nan, -.15,-.06] + pos(2);
plot(ax, ttx, tty, 'Color','k', 'LineWidth',1, 'UserData','emoji')
plot(ax, cos(ttt3).*.06 + pos(1) - .25, sin(ttt3).*.06 + pos(2), 'Color','k', 'LineWidth',1.5, 'UserData','emoji')
plot(ax, cos(ttt3).*.06 + pos(1) + .25, sin(ttt3).*.06 + pos(2), 'Color','k', 'LineWidth',1.5, 'UserData','emoji')
end
end
% 绘制棋子
function drawStone(pos)
delete(PMat{pos(1), pos(2)});
delete(LMat{pos(1), pos(2)});
if goMat(pos(1), pos(2)) ~= 0
tturn = sign(goMat(pos(1), pos(2)));
C = [105,105,107]./255.*(tturn>0) + [228,228,228]./255.*(tturn<0);
[SX, SY] = find(sign(goMat) == tturn); SSet = [SX, SY];
PSet = repmat(pos, [4,1]) + [-1,0;1,0;0,-1;0,1];
[~, IInd, ~] = intersect(PSet, SSet,'rows'); IInd = sort(IInd);
if isempty(IInd)
ttt = linspace(0,2*pi,100);
ttx = cos(ttt).*.5 + pos(1);
tty = sin(ttt).*.5 + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty,C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
else
switch length(IInd)
case 1
switch IInd
case 1
ttt = linspace(-pi/2, pi/2, 100);
ttx = [-.5, cos(ttt).*.5, -.5] + pos(1);
tty = [-.5, sin(ttt).*.5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
case 2
ttt = linspace(pi/2, 3*pi/2, 100);
ttx = [.5, cos(ttt).*.5, .5] + pos(1);
tty = [.5, sin(ttt).*.5, -.5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
case 3
ttt = linspace(0, pi, 100);
ttx = [.5, cos(ttt).*.5, -.5] + pos(1);
tty = [-.5, sin(ttt).*.5, -.5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
case 4
ttt = linspace(pi, 2*pi, 100);
ttx = [-.5, cos(ttt).*.5, .5] + pos(1);
tty = [.5, sin(ttt).*.5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
end
case 2
switch true
case all(IInd == [1;2])
PMat{pos(1), pos(2)} = fill(ax, pos(1) + [-.5, .5, .5, -.5],...
pos(2) + [-.5, -.5, .5, .5], C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, pos(1) + [-.5, .5, nan, .5, -.5], ...
pos(2) + [-.5, -.5, nan .5, .5], 'Color','k', 'LineWidth',2);
case all(IInd == [3;4])
PMat{pos(1), pos(2)} = fill(ax, pos(1) + [-.5, -.5, .5, .5],...
pos(2) + [-.5, .5, .5, -.5], C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, pos(1) + [-.5, -.5, nan .5, .5], ...
pos(2) + [-.5, .5, nan, .5, -.5], 'Color','k', 'LineWidth',2);
case all(IInd == [1;3])
ttt = linspace(0, pi/2, 100);
ttx = [-.5, .5, cos(ttt).*.5, -.5] + pos(1);
tty = [-.5, -.5, sin(ttt).*.5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx(2:end), tty(2:end), 'Color','k', 'LineWidth',2);
case all(IInd == [1;4])
ttt = linspace(3*pi/2, 2*pi, 100);
ttx = [-.5, -.5, cos(ttt).*.5, .5] + pos(1);
tty = [.5, -.5, sin(ttt).*.5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx(2:end), tty(2:end), 'Color','k', 'LineWidth',2);
case all(IInd == [2;3])
ttt = linspace(pi/2, pi, 100);
ttx = [.5, .5, cos(ttt).*.5, -.5] + pos(1);
tty = [-.5, .5, sin(ttt).*.5, -.5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx(2:end), tty(2:end), 'Color','k', 'LineWidth',2);
case all(IInd == [2;4])
ttt = linspace(pi, 3*pi/2, 100);
ttx = [.5, -.5, cos(ttt).*.5, .5] + pos(1);
tty = [.5, .5, sin(ttt).*.5, -.5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = plot(ax, ttx(2:end), tty(2:end), 'Color','k', 'LineWidth',2);
end
case 3
ttx = [-.5, .5, .5, -.5] + pos(1);
tty = [-.5, -.5, .5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
switch true
case all(IInd == [2;3;4]), ttx = [-.5, -.5] + pos(1); tty = [-.5, .5] + pos(2);
case all(IInd == [1;3;4]), ttx = [.5, .5] + pos(1); tty = [-.5, .5] + pos(2);
case all(IInd == [1;2;4]), ttx = [-.5, .5] + pos(1); tty = [-.5, -.5] + pos(2);
case all(IInd == [1;2;3]), ttx = [-.5, .5] + pos(1); tty = [.5, .5] + pos(2);
end
LMat{pos(1), pos(2)} = plot(ax, ttx, tty, 'Color','k', 'LineWidth',2);
case 4
ttx = [-.5, .5, .5, -.5] + pos(1);
tty = [-.5, -.5, .5, .5] + pos(2);
PMat{pos(1), pos(2)} = fill(ax, ttx, tty, C, 'EdgeColor','none');
LMat{pos(1), pos(2)} = [];
end
end
end
end
end