一、程序介绍
71115304 邓雨田
二、主程序代码及子函数
function start2048()
handles = initFigure();
field = Field(4);
draw(handles, field, 1);
set(handles.figure, 'UserData', field, ...
'WindowKeyPressFcn', {@keyPress, handles});
function handles = initFigure()
set(0, 'Units', 'Pixels');
screen = get(0, 'ScreenSize');
scw = screen(3);
sch = screen(4);
width = 0.6 * scw;
sideMargin = 0.02 * width;
axWidth = (width - 3 * sideMargin) / 2;
axHeight = axWidth;
topMargin = 2 * sideMargin;
bottomMargin = sideMargin;
height = axHeight + topMargin + bottomMargin;
windowPosx = (scw - width) / 2;
windowPosy = (sch - height) / 2;
fig = figure('Name', '2048', ...
'Menubar', 'none', ...
'Toolbar', 'none', ...
'NumberTitle', 'off', ...
'Resize', 'off', ...
'Tag', 'mainwindow', ...
'Position', [windowPosx, windowPosy, width, height]);
ax1 = axes('Parent', fig, ...
'Units', 'pixels', ...
'Position', [sideMargin, bottomMargin, axWidth, axHeight], ...
'Units', 'normalized', ...
'Visible', 'on', ...
'Tag', 'mainaxes', ...
'XTickLabel', [], ...
'YTickLabel', [], ...
'XTick', [], ...
'YTick', [], ...
'Color', [252, 255, 222]/255);
ax2 = axes('Parent', fig, ...
'Units', 'pixels', ...
'Position', [2 * sideMargin + axWidth, bottomMargin, axWidth, axHeight], ...
'Units', 'normalized', ...
'Visible', 'on', ...
'Tag', 'mainaxes', ...
'XTickLabel', [], ...
'YTickLabel', [], ...
'XTick', [], ...
'YTick', [], ...
'Color', [252, 255, 222]/255);
boxWidth = 200;
boxHeight = 0.8 * topMargin;
scoreBox = uicontrol('style', 'edit', ...
'Enable', 'inactive', ...
'Parent', fig, ...
'Units', 'pixels', ...
'Position', [sideMargin + (axWidth - boxWidth) / 2, height - (topMargin + boxHeight) / 2, boxWidth, boxHeight], ...
'String', 'Score: 0', ...
'BackGroundColor', get(fig, 'Color'),...
'FontSize', 12, 'FontWeight', 'bold');
moveBox = uicontrol('style', 'edit', ...
'Enable', 'inactive', ...
'Parent', fig, ...
'Units', 'pixels', ...
'Position', [2 * sideMargin + (3 * axWidth - boxWidth) / 2, height - (topMargin + boxHeight) / 2, boxWidth, boxHeight], ...
'String', 'Moves: 0', ...
'BackGroundColor', get(fig, 'Color'),...
'FontSize', 12, 'FontWeight', 'bold');
handles = struct('figure', fig, ...
'field', ax1, ...
'graph', ax2, ...
'scoreBox', scoreBox, ...
'moveBox', moveBox);
classdef Field
properties(GetAccess = 'public', SetAccess = 'private')
mat;
n;
lost = false;
won = false;
score = 0;
scoreHistory = 0;
moves = 0;
changed = true;
end
methods(Access = 'public')
function obj = Field(n)
if nargin == 0
n = 4;
end
i = zeros(1,2);
while i(1) == i(2)
i = randi(n^2, 1, 2);
end
obj.mat = zeros(n);
obj.mat(i) = 2;
obj.n = n;
end
function show(obj)
disp(obj.mat);
end
function obj = move(obj, dir)
if ~any('LRUD' == dir)
return
end
if ~(obj.lost || obj.won)
[obj, obj.changed] = collapse(obj, dir);
if obj.changed
obj.moves = obj.moves + 1;
obj = insertRandom(obj);
obj.won = max(obj.mat(:)) == 2048;
end
obj = checkForPossibleMoves(obj);
end
end
end
methods(Access = 'private')
function [obj, succes] = collapse(obj, dir)
succes = 0;
for i = 1:obj.n
switch dir
case 'L'
[vec, sc, effect] = Field.merge(obj.mat(i,:));
obj.mat(i,:) = vec;
case 'R'
[vec, sc, effect] = Field.merge(fliplr(obj.mat(i,:)));
vec = fliplr(vec);
obj.mat(i,:) = vec;
case 'U'
[vec, sc, effect] = Field.merge(obj.mat(:,i));
obj.mat(:,i) = vec;
case 'D'
[vec, sc, effect] = Field.merge(flipud(obj.mat(:,i)));
vec = flipud(vec);
obj.mat(:,i) = vec;
otherwise
return;
end
obj.score = obj.score + sc;
obj.scoreHistory = [obj.scoreHistory, obj.score];
succes = succes + effect;
end
end
function obj = insertRandom(obj)
cand = find(~obj.mat);
i = randi(numel(cand));
if rand()
value = 2;
else
value = 4;
end
obj.mat(cand(i)) = value;
end
function obj = checkForPossibleMoves(obj)
copy = obj;
allMoves = 'LRUD';
for m = allMoves
[~, succes] = collapse(copy, m);
if succes
return
end
end
obj.lost = true;
end
end
methods(Access = 'public', Static = true)
function [vec, sc, effect] = merge(vec)
effect = 0;
sc = 0;
m = numel(vec);
action = zeros(size(vec));
for i = 2:m
if ~vec(i)
continue
end
j = find(vec(1:i-1), 1, 'last'); % first nonzero left of i
x = vec(i);
y = vec(j);
vec(i) = 0;
if isempty(j) % move all the way to the edge
vec(1) = x;
effect = 1;
elseif x == y && ~action(j) % merge them -> mark action
vec(j) = 2 * x;
action(j) = 1;
sc = sc + 2 * x;
effect = 1;
else
vec(j + 1) = x;
if j + 1 ~= i
effect = 1;
end
end
end
end
end
end
function draw(handles, field, drawgrid)
axes(handles.field)
%% GRID
n = size(field.mat, 1);
xlm = get(handles.field, 'XLim');
ylm = get(handles.field, 'YLim');
xwidth = diff(xlm) / n;
ywidth = diff(ylm) / n;
if isempty(get(handles.field, 'UserData'))
patches = zeros(n);
else
patches = get(handles.field, 'UserData');
end
if drawgrid
delete(findobj('type', 'patch', 'Parent', handles.field));
for i = 1:n
for j = 1:n
x = [j - 1, j, j, j - 1] * xwidth;
y = ylm(2) - [i - 1, i - 1, i, i] * ywidth;
patches(i,j) = patch(x, y, 0);
end
end
set(handles.field, 'UserData', patches);
end
%% NUMBERS
delete(findobj('type', 'text', 'Parent', handles.field));
cmap = [0.3686 0.3098 0.6353;
0.1961 0.5333 0.7412;
0.4000 0.7608 0.6471;
0.6706 0.8667 0.6431;
0.9020 0.9608 0.5961;
0.9500 0.9500 0.7116;
0.9961 0.8784 0.5451;
0.9922 0.6824 0.3804;
0.9569 0.4275 0.2627;
0.8353 0.2431 0.3098;
0.6196 0.0039 0.2588];
for i = 1:n
for j = 1:n
x = (j - 1 + 1/2) * xwidth;
y = ylm(2) - (i - 1 + 1/2) * ywidth;
value = field.mat(i,j);
if value
index = min(11, log(value) / log(2));
text(x,y, num2str(value), ...
'FontSize', 14, ...
'FontWeight', 'bold', ...
'Color', 'white', ...
'HorizontalAlignment', 'Center');
set(patches(i,j), 'FaceColor', cmap(index, :))
else
set(patches(i,j), 'FaceColor', [1 1 1]);
end
end
end
%% SCORE
set(handles.scoreBox, 'String', sprintf('Score: %d', field.score));
set(handles.moveBox, 'String', sprintf('Moves: %d', field.moves));
%% GRAPH
axes(handles.graph)
plot(field.scoreHistory)
set(handles.graph, 'XTickLabel', [], 'YTickLabel', [], 'XTick', [], 'YTick', [])
function keyPress(fig, event, handles)
dir = upper(event.Key(1));
field = get(handles.figure, 'UserData');
field = field.move(dir);
if ~field.changed
return
end
set(handles.figure, 'UserData', field);
draw(handles, field, 0);
if field.won
uiwait(msgbox('You Won!!'));
close(fig);
elseif field.lost
uiwait(msgbox('You Lost!!'));
close(fig)
end