Recently I've implemented Minesweeper in Mathematica.
Clear["Global`*"]
path = "https://i.sstatic.net//" <> # &;
filenames1 = {"P22Go.jpg", "Zh27M.jpg", "vKZZr.jpg", "2CYDF.png"};
{TL, BR, clock, mine} = Import /@ path /@ filenames1;
{topleft, bottomright} = ImageData /@ {TL, BR};
filenames2 = {"VngIV.jpg", "WeIqo.jpg", "fvub6.jpg", "rb5P7.jpg",
"fl5W2.jpg", "NowyY.jpg", "5Pp3F.jpg", "9pNCj.jpg", "vMIXr.jpg"};
numberpictures[n_] :=
numberpictures[n] = Import[path@filenames2[[n + 1]]];
backgroundcolor = RGBColor[0.698, 0.757, 0.831];
spacecolor = RGBColor[0.839, 0.890, 0.953];
numbercolor =
RGBColor @@@ {{0.247, 0.314, 0.737}, {0.122, 0.408, 0.004}, {0.682, 0.008, 0.020},
{0.027, 0.004, 0.502}, {0.49, 0, 0}, {0, 0.49, 0.495}, {0, 0, 0}, {0, 0, 0}};
back[i_, j_] := back[i, j] =
With[{ii = Rescale[i, {1, 16}], jj = Rescale[j, {1, 30}]},
Image[(1 - (ii + jj)/2) topleft + (ii + jj)/2 bottomright]];
block[{i_, j_, type1_, type2_}] := block[i, j, type1, type2] =
Switch[type1,
0, back[i, j],
1, Switch[type2,
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8, numberpictures[type2],
9, ImageCompose[back[i, j], mine]
]
];
ini := Module[{mat1, mat2, modify},
modify[mat_, {i_, j_}] :=
If[mat[[i, j]] != 9,
ReplacePart[mat, {i, j} ->
Count[mat[[Max[1, i - 1] ;; Min[16, i + 1],
Max[1, j - 1] ;; Min[30, j + 1]]], 9, 2]], mat];
mat1 = Table[{i, j, 0}, {i, 16}, {j, 30}];
mat2 = Partition[RandomSample[
Flatten@{9 & /@ Range[99], 0 & /@ Range[16*30 - 99]}], 30];
mat2 = Map[List, Fold[modify[#1, #2] &, mat2,
Flatten[Array[{#1, #2} &, {16, 30}], 1]], {2}];
Join[mat1, mat2, 3]];
CreateDialog[
DynamicModule[{board = ini},
Dynamic@Column@{Spacer[30],
GraphicsGrid[Map[block, board, {2}], ImageSize -> 1200,
Spacings -> {0, 0}, Frame -> All,
FrameStyle -> Directive[Black, Thick]],
Row[{Spacer[60], clock, Spacer[700], mine, Spacer[30]}]},
Initialization :> (
getpos[] :=
With[{pos = MousePosition["Graphics"]},
If[pos === None,
None, {-1, 1}*Quotient[Reverse@pos, 360] + {0, 1}]];
click[board_, "Left"] :=
With[{coor = getpos[]},
If[coor === None, board,
ReplacePart[board, Flatten[{coor, 3}] -> 1]]];
SetOptions[EvaluationNotebook[],
NotebookEventActions -> {{"MouseUp",
1} :> (board = click[board, "Left"]), {"MouseUp",
2} :> {"Right ", Print@getpos[]}}])],
Background -> backgroundcolor, WindowTitle -> "Minesweeper By apple",
WindowMargins -> {{0, Automatic}, {Automatic, 0}}]
There are 16*30 = 480
blocks in the final interface. If I write that Dynamic[...(*480 blocks*)]
, when I click any cell, it will redraw all the interface (480 blocks or more) and will respond after 2 seconds. I don't know how to just dynamic small part of the final interface. How to make it response with high-speed?
Update 1
Since it is not a good idea to put Dynamic
over the whole application, I rewrote my code in ugly way:
DynamicModule[{board = ini},
GraphicsGrid[
{{Dynamic@block@var[1, 1], Dynamic@block@var[1, 2], Dynamic@block@var[1, 3],and so on},
{Dynamic@block@var[2, 1], Dynamic@block@var[2, 2], Dynamic@block@var[2, 3],and so on},
and so on}}}],
Initialization :> (
getpos[] := some code;
click["Left"] := somecode;
SetOptions[EvaluationNotebook[], NotebookEventActions -> somecode])]
var[1, 1]
maybe equal to {1,1,0,3}
, {1,1}
means this block is in row 1, column 1, 0 means this block was not clicked yet, 3 means there are 3 mines around this block.
Now click will be:
click["Left"]:= With[{coor=getpos[]},board[Sequence@@coor][[3]]=1]
But this is not allowed.
Block[{x}, x[1] = {0, 0, 0}; x[1][[2]] = 11; x[1]]
Set::setps: "x[1] in the part assignment is not a symbol."
We only can do something like this:
Block[{x1}, x1 = {0, 0, 0}; x1[[2]] = 11; x1]
{0, 11, 0}
Then I rewrote my code again..
vars = Table[ToExpression["boardR" <> ToString[i] <> "C" <> ToString[j]], {i, 16}, {j, 30}];
Evaluate@vars = ini;
DynamicModule[{},
GraphicsGrid[
{{Dynamic@block@boardR1C1, Dynamic@block@boardR1C2, Dynamic@block@boardR1C3,and so on},
{Dynamic@block@boardR2C1, Dynamic@block@boardR2C2, Dynamic@block@boardR2C3,and so on},
and so on}}}],
Initialization :> (
getpos[] := some code;
click["Left"] := somecode;
SetOptions[EvaluationNotebook[], NotebookEventActions -> somecode])]
now click will be more complex:
click["Left"]:=With[{coor=getpos[]},Set[(ToExpression[
"boardR" <> ToString[coor[[1]]] <> "C" <> ToString[coor[[2]]]])[[3]], 1]]
But this will also cause other problems, since:
a=3;
Set[ToExpression["a"],2]
Set::write: Tag ToExpression in ToExpression[a] is Protected.
So currently all the efforts I did have failed.
Update 2
1:
x[1] = {1, 2, 3};
Module[{temp},
temp = x[1];
temp[[2]] = 4;
x[1] = temp;
]
x[1]
{1, 4, 3}
2:
a=3;
ToExpression["a"<>"=2"]
a
2
Now maybe I can finish my code.
Update 3
This game is not finished (now 2014.11.24). There are a lot of features not included.
NotebookPut@
ImportString[
Uncompress@FromCharacterCode@Drop[#, -Last@#] &@
Flatten@ImageData[
Import["https://i.sstatic.net/3wGyI.png"], "Byte"],
"NB"]
(# = 3) &@ToExpression["a", InputForm, Unevaluated]
$\endgroup$ToExpression["a=" <> ToString[3]]
$\endgroup$