Initial commit
16
meson.build
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
project('minesweeper', 'cpp',
|
||||||
|
version : '0.1',
|
||||||
|
default_options : ['warning_level=3'])
|
||||||
|
|
||||||
|
gnome = import('gnome')
|
||||||
|
|
||||||
|
res = gnome.compile_resources(
|
||||||
|
'resources', 'resources/gresource.xml',
|
||||||
|
source_dir: 'resources',
|
||||||
|
c_name: 'gresources'
|
||||||
|
)
|
||||||
|
|
||||||
|
deps = dependency(['gtkmm-4.0', 'sigc++-3.0'])
|
||||||
|
src = ['Window.cpp', 'window.hpp', 'MineField.hpp', 'MineField.cpp', res]
|
||||||
|
exe = executable('minesweeper', src, dependencies : deps, install : true)
|
||||||
|
|
||||||
38
resources/bomb-solid.svg
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="bomb-solid.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.5273438"
|
||||||
|
inkscape:cx="256"
|
||||||
|
inkscape:cy="256"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="M459.1 52.4L442.6 6.5C440.7 2.6 436.5 0 432.1 0s-8.5 2.6-10.4 6.5L405.2 52.4l-46 16.8c-4.3 1.6-7.3 5.9-7.2 10.4c0 4.5 3 8.7 7.2 10.2l45.7 16.8 16.8 45.8c1.5 4.4 5.8 7.5 10.4 7.5s8.9-3.1 10.4-7.5l16.5-45.8 45.7-16.8c4.2-1.5 7.2-5.7 7.2-10.2c0-4.6-3-8.9-7.2-10.4L459.1 52.4zm-132.4 53c-12.5-12.5-32.8-12.5-45.3 0l-2.9 2.9C256.5 100.3 232.7 96 208 96C93.1 96 0 189.1 0 304S93.1 512 208 512s208-93.1 208-208c0-24.7-4.3-48.5-12.2-70.5l2.9-2.9c12.5-12.5 12.5-32.8 0-45.3l-80-80zM200 192c-57.4 0-104 46.6-104 104v8c0 8.8-7.2 16-16 16s-16-7.2-16-16v-8c0-75.1 60.9-136 136-136h8c8.8 0 16 7.2 16 16s-7.2 16-16 16h-8z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ff0000" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/confetti.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
43
resources/explosion-flag.svg
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 576 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="explosion-flag.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.5273438"
|
||||||
|
inkscape:cx="287.75447"
|
||||||
|
inkscape:cy="256.32736"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1371"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="M499.6 11.3c6.7-10.7 20.5-14.5 31.7-8.5s15.8 19.5 10.6 31L404.8 338.6c2.2 2.3 4.3 4.7 6.3 7.1l97.2-54.7c10.5-5.9 23.6-3.1 30.9 6.4s6.3 23-2.2 31.5l-87 87H378.5c-13.2-37.3-48.7-64-90.5-64s-77.4 26.7-90.5 64H117.8L42.3 363.7c-9.7-6.7-13.1-19.6-7.9-30.3s17.4-15.9 28.7-12.4l97.2 30.4c3-3.9 6.1-7.7 9.4-11.3L107.4 236.3c-6.1-10.1-3.9-23.1 5.1-30.7s22.2-7.5 31.1 .1L246 293.6c1.5-.4 3-.8 4.5-1.1l13.6-142.7c1.2-12.3 11.5-21.7 23.9-21.7s22.7 9.4 23.9 21.7l13.5 141.9L499.6 11.3zM64 448v0H512v0h32c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H64zM288 0c13.3 0 24 10.7 24 24V72c0 13.3-10.7 24-24 24s-24-10.7-24-24V24c0-13.3 10.7-24 24-24z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ff0000" />
|
||||||
|
<path
|
||||||
|
style="fill:#000000;stroke:#000000;stroke-width:50;stroke-linecap:square;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 11.130434,11.130434 C 557.17645,493.01278 566.3427,501.52428 566.3427,501.52428 M 3.2736572,509.38106 C 575.50893,0.65473144 575.50893,0.65473144 575.50893,0.65473144"
|
||||||
|
id="path4"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.2 KiB |
38
resources/explosion-solid.svg
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 576 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="explosion-solid.svg"
|
||||||
|
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.5273438"
|
||||||
|
inkscape:cx="288.08184"
|
||||||
|
inkscape:cy="256"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="M499.6 11.3c6.7-10.7 20.5-14.5 31.7-8.5s15.8 19.5 10.6 31L404.8 338.6c2.2 2.3 4.3 4.7 6.3 7.1l97.2-54.7c10.5-5.9 23.6-3.1 30.9 6.4s6.3 23-2.2 31.5l-87 87H378.5c-13.2-37.3-48.7-64-90.5-64s-77.4 26.7-90.5 64H117.8L42.3 363.7c-9.7-6.7-13.1-19.6-7.9-30.3s17.4-15.9 28.7-12.4l97.2 30.4c3-3.9 6.1-7.7 9.4-11.3L107.4 236.3c-6.1-10.1-3.9-23.1 5.1-30.7s22.2-7.5 31.1 .1L246 293.6c1.5-.4 3-.8 4.5-1.1l13.6-142.7c1.2-12.3 11.5-21.7 23.9-21.7s22.7 9.4 23.9 21.7l13.5 141.9L499.6 11.3zM64 448v0H512v0h32c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H64zM288 0c13.3 0 24 10.7 24 24V72c0 13.3-10.7 24-24 24s-24-10.7-24-24V24c0-13.3 10.7-24 24-24z"
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ff0000" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
40
resources/flag-bomb.svg
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 448 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="flag-bomb.svg"
|
||||||
|
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="1.7148438"
|
||||||
|
inkscape:cx="223.92711"
|
||||||
|
inkscape:cy="256"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1131"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
|
||||||
|
<path
|
||||||
|
d="M64 32C64 14.3 49.7 0 32 0S0 14.3 0 32V64 368 480c0 17.7 14.3 32 32 32s32-14.3 32-32V352l64.3-16.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30V66.1c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L64 48V32z"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0000;stroke-width:0.583144"
|
||||||
|
d="M 24.002945,510.52324 C 13.21861,507.69839 4.8232184,499.37977 1.3638007,488.09112 0.33069841,484.71993 0.29157175,476.25071 0.29157175,256 0.29157175,35.749294 0.33069841,27.280068 1.3638007,23.908884 3.8564107,15.775083 9.6354551,8.3117234 16.41394,4.4723476 20.409465,2.2092575 27.594333,0.28848795 32.020388,0.30019126 44.896724,0.33423867 57.032014,8.8710636 61.729076,21.199391 c 1.359535,3.568369 1.494993,4.789267 1.707846,15.392864 0.129971,6.474936 0.466638,11.517084 0.768992,11.517084 0.295794,0 16.344958,-3.95457 35.664806,-8.787934 19.31985,-4.833364 37.59233,-9.296286 40.60552,-9.917605 27.84381,-5.741399 57.68011,-3.790361 85.37172,5.582578 6.4206,2.173217 11.56284,4.355341 25.44574,10.797957 14.52905,6.74248 32.84346,11.908829 49.89992,14.076378 7.49095,0.951953 30.3487,0.939217 37.90433,-0.02111 12.71487,-1.616089 26.86107,-5.01295 37.98594,-9.12138 3.1624,-1.16788 11.17831,-4.735815 17.81313,-7.928743 12.03196,-5.790241 17.06777,-7.476553 22.39467,-7.499167 3.39719,-0.01442 10.8825,2.016626 14.42243,3.91335 4.39316,2.353896 10.34756,8.530179 12.55407,13.021891 3.8329,7.80248 3.6198,-0.833589 3.44921,139.780136 l -0.15476,127.55695 -1.27029,3.49886 c -2.69816,7.43171 -6.95319,13.05442 -12.83196,16.95653 -3.52033,2.33665 -39.12224,16.06062 -51.50139,19.85294 -26.16159,8.01455 -54.06415,9.88627 -80.76538,5.41777 -16.84937,-2.81977 -31.07217,-7.40601 -49.5672,-15.98329 -12.81271,-5.94206 -19.31432,-8.49504 -29.44874,-11.56365 -24.95569,-7.55634 -53.54731,-9.34357 -79.89066,-4.99386 -4.00912,0.66197 -23.29659,5.19681 -42.861052,10.07741 l -35.571754,8.87384 -0.291572,67.61281 -0.291571,67.61283 -1.509327,3.87578 c -6.026376,15.47501 -22.040715,23.83982 -37.758799,19.72263 z"
|
||||||
|
id="path2" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
1
resources/flag-regular.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M48 24C48 10.7 37.3 0 24 0S0 10.7 0 24V64 350.5 400v88c0 13.3 10.7 24 24 24s24-10.7 24-24V388l80.3-20.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30V66.1c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L48 52V24zm0 77.5l96.6-24.2c27-6.7 55.5-3.6 80.4 8.8c54.9 27.4 118.7 29.7 175 6.8V334.7l-24.4 9.1c-33.7 12.6-71.2 10.7-103.4-5.4c-48.2-24.1-103.3-30.1-155.6-17.1L48 338.5v-237z"/></svg>
|
||||||
|
After Width: | Height: | Size: 719 B |
1
resources/flag-solid.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M64 32C64 14.3 49.7 0 32 0S0 14.3 0 32V64 368 480c0 17.7 14.3 32 32 32s32-14.3 32-32V352l64.3-16.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30V66.1c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L64 48V32z"/></svg>
|
||||||
|
After Width: | Height: | Size: 548 B |
11
resources/gresource.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/minesweeper">
|
||||||
|
<file alias="bomb-solid">bomb-solid.svg</file>
|
||||||
|
<file alias="explosion-solid">explosion-solid.svg</file>
|
||||||
|
<file alias="flag-regular">flag-regular.svg</file>
|
||||||
|
<file alias="flag-solid">flag-solid.svg</file>
|
||||||
|
<file alias="explosion-flag">explosion-flag.svg</file>
|
||||||
|
<file alias="flag-bomb">flag-bomb.svg</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
||||||
115
src/MineField.cpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#include "MineField.hpp"
|
||||||
|
|
||||||
|
MineField::MineField(int cols, int rows, int mines): m_rows(rows),
|
||||||
|
m_cols(cols),
|
||||||
|
m_totalMines(mines),
|
||||||
|
m_remainingFlags(mines),
|
||||||
|
m_exploded(false) {
|
||||||
|
for(int i=0; i< m_cols*m_rows; i++) {
|
||||||
|
std::shared_ptr<Cell> cell = std::make_shared<Cell>();
|
||||||
|
m_cells.push_back(cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MineField::initBombs(int x, int y) {
|
||||||
|
|
||||||
|
int remainingMines = m_totalMines;
|
||||||
|
int startPos = x + y * m_rows;
|
||||||
|
|
||||||
|
srand(time(NULL)); //initialize rand()
|
||||||
|
|
||||||
|
while(remainingMines > 0) {
|
||||||
|
int position = rand() % (m_cols * m_rows);
|
||||||
|
if(isBomb(position % m_cols, position / m_rows) || position == startPos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_cells.at(position)->isBomb = true;
|
||||||
|
--remainingMines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MineField::clearCell(int x, int y) {
|
||||||
|
setClearCell(x, y);
|
||||||
|
|
||||||
|
if(isBomb(x, y)) {
|
||||||
|
m_exploded = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bombsNearby(x, y) == 0) {
|
||||||
|
openNeighboorhood(x, y);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MineField::computeBombsNearby(int x, int y) {
|
||||||
|
int total = 0;
|
||||||
|
//compute bombs in neighboorhood
|
||||||
|
for(int i=-1; i<2; i++) {
|
||||||
|
for(int j=-1; j<2; j++) {
|
||||||
|
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) {
|
||||||
|
if(isBomb(x+i, y+j)){
|
||||||
|
++total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_cells.at(x + y * m_rows)->bombsNearby = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MineField::openNeighboorhood(int x, int y) {
|
||||||
|
//compute bombs in neighboorhood
|
||||||
|
for(int i=-1; i<2; i++) {
|
||||||
|
for(int j=-1; j<2; j++) {
|
||||||
|
if(x+i >= 0 && x+i < m_cols && y+j >= 0 && y+j < m_rows) {
|
||||||
|
if((isCleared(x+i, y+j) == false) && (isBomb(x+i, y+j) == false)){
|
||||||
|
setClearCell((x+i), (y+j));
|
||||||
|
if(bombsNearby(x+i, y+j) == 0) {
|
||||||
|
openNeighboorhood(x+i, y+j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MineField::isCleared(int x, int y) {
|
||||||
|
return m_cells.at(x + y * m_rows)->isCleared;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MineField::isFlagged(int x, int y) {
|
||||||
|
return m_cells.at(x + y * m_rows)->isFlagged;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MineField::isBomb(int x, int y) {
|
||||||
|
return m_cells.at(x + y * m_rows)->isBomb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MineField::bombsNearby(int x, int y) {
|
||||||
|
if(m_cells.at(x + y * m_rows)->bombsNearby == -1) {
|
||||||
|
computeBombsNearby(x, y);
|
||||||
|
}
|
||||||
|
return m_cells.at(x + y * m_rows)->bombsNearby;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MineField::setClearCell(int x, int y) {
|
||||||
|
m_cells.at(x + y * m_rows)->isCleared = true;
|
||||||
|
clearCellSignal.emit(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MineField::toggleFlag(int x, int y) {
|
||||||
|
if(m_cells.at(x + y * m_rows)->isFlagged == true) {
|
||||||
|
m_cells.at(x + y * m_rows)->isFlagged = false;
|
||||||
|
++m_remainingFlags;
|
||||||
|
remainingFlagsChangedSignal.emit(m_remainingFlags);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(m_remainingFlags > 0) {
|
||||||
|
m_cells.at(x + y * m_rows)->isFlagged = true;
|
||||||
|
--m_remainingFlags;
|
||||||
|
remainingFlagsChangedSignal.emit(m_remainingFlags);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
46
src/MineField.hpp
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#include <emmintrin.h>
|
||||||
|
#include <sigc++/signal.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct Cell {
|
||||||
|
bool isFlagged;
|
||||||
|
bool isCleared;
|
||||||
|
bool isBomb;
|
||||||
|
int bombsNearby;
|
||||||
|
Cell(): isFlagged(false), isCleared(false), isBomb(false), bombsNearby(-1) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class MineField {
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Cell>> m_cells;
|
||||||
|
int m_rows;
|
||||||
|
int m_cols;
|
||||||
|
int m_totalMines;
|
||||||
|
int m_remainingFlags;
|
||||||
|
bool m_exploded;
|
||||||
|
void computeBombsNearby(int x, int y);
|
||||||
|
void openNeighboorhood(int x, int y);
|
||||||
|
void setClearCell(int x, int y);
|
||||||
|
|
||||||
|
public:
|
||||||
|
MineField(int cols, int rows, int mines);
|
||||||
|
void initBombs(int x, int y);
|
||||||
|
bool isBomb(int x, int y);
|
||||||
|
bool isFlagged(int x, int y);
|
||||||
|
bool isCleared(int x, int y);
|
||||||
|
bool clearCell(int x, int y);
|
||||||
|
int bombsNearby(int x, int y);
|
||||||
|
bool isGameOver() {return m_exploded; };
|
||||||
|
int getCols() {return m_cols; };
|
||||||
|
int getRows() {return m_rows; };
|
||||||
|
bool toggleFlag(int x, int y);
|
||||||
|
int getRemainingFlags() {return m_remainingFlags; };
|
||||||
|
int getTotalMines() {return m_totalMines; };
|
||||||
|
sigc::signal<void(int, int)> clearCellSignal;
|
||||||
|
sigc::signal<void(int)> remainingFlagsChangedSignal;
|
||||||
|
};
|
||||||
339
src/Window.cpp
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
#include "window.hpp"
|
||||||
|
#include "gdkmm/pixbuf.h"
|
||||||
|
#include "gtkmm/cssprovider.h"
|
||||||
|
#include "gtkmm/image.h"
|
||||||
|
#include "sigc++/adaptors/bind.h"
|
||||||
|
#include "sigc++/functors/mem_fun.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
//}
|
||||||
|
// void MainWindow::ApplyStyles() {
|
||||||
|
// // Load and apply the CSS file
|
||||||
|
// auto css_provider = Gtk::CssProvider::create();
|
||||||
|
// css_provider->load_from_path("style.css");
|
||||||
|
// Gtk::StyleContext::add_provider_for_display(Gdk::Display::get_default(), css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
// }
|
||||||
|
|
||||||
|
void MainWindow::OnCellRightClick(int n_press, double n_x, double n_y, int index) {
|
||||||
|
(void)n_press, (void)n_x, (void)n_y;
|
||||||
|
int x = index % field.getCols();
|
||||||
|
int y = index / field.getRows();
|
||||||
|
|
||||||
|
if(field.isCleared(x, y) == false) {
|
||||||
|
field.toggleFlag(x, y);
|
||||||
|
if(field.isFlagged(x, y)) {
|
||||||
|
auto imgflag = Gtk::make_managed<Gtk::Image>();
|
||||||
|
imgflag->set(m_pixbufFlag);
|
||||||
|
buttons.at(x + y * field.getRows())->set_child(*imgflag);
|
||||||
|
buttons.at(x + y * field.getRows())->set_active(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buttons.at(x + y * field.getRows())->unset_child();
|
||||||
|
buttons.at(x+ y * field.getRows())->queue_draw();
|
||||||
|
buttons.at(x + y * field.getRows())->set_active(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
|
||||||
|
// flagLabel.set_label(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateFlagsLabel(int flags) {
|
||||||
|
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", flags);
|
||||||
|
flagLabel.set_label(msg);
|
||||||
|
}
|
||||||
|
// void MainWindow::OnNewButtonClick() {
|
||||||
|
// newGame = true;
|
||||||
|
// gameOver = false;
|
||||||
|
|
||||||
|
// for (auto &button : buttons) {
|
||||||
|
// button->set_active(false);
|
||||||
|
// button->set_sensitive(true);
|
||||||
|
// button->set_label("");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// field->remainingFlags = MINES;
|
||||||
|
// Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field->remainingFlags);
|
||||||
|
// flagLabel.set_label(msg);
|
||||||
|
|
||||||
|
// if (clockConn.connected()) clockConn.disconnect();
|
||||||
|
// elapsedTime = 0;
|
||||||
|
// clockConn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::UpdateClockLabel), 100);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// void MainWindow::OpenNearCells(int index, std::set<int> &visited) {
|
||||||
|
// int cols = field->Cols();
|
||||||
|
// int x = index % cols;
|
||||||
|
// int y = index / cols;
|
||||||
|
|
||||||
|
// if (visited.count(index)) return;
|
||||||
|
|
||||||
|
// Cell* cell = field->GetCell(x, y);
|
||||||
|
// if (!cell || cell->bombsNearby > 0 || cell->type == CellType::Bomb) return;
|
||||||
|
|
||||||
|
// visited.insert(index);
|
||||||
|
// buttons[index]->set_active(true);
|
||||||
|
|
||||||
|
// for (int i = -1; i <= 1; i++) {
|
||||||
|
// for (int j = -1; j <= 1; j++) {
|
||||||
|
// if (i == 0 && j == 0) continue; // Skip the current cell
|
||||||
|
|
||||||
|
// int nx = x + i;
|
||||||
|
// int ny = y + j;
|
||||||
|
// int newIndex = ny * cols + nx;
|
||||||
|
// Cell* neighborCell = field->GetCell(nx, ny);
|
||||||
|
|
||||||
|
// // Bounds check before recursive call
|
||||||
|
// if (nx >= 0 && nx < cols && ny >= 0 && ny < cols) {
|
||||||
|
// if (visited.count(newIndex) == 0) {
|
||||||
|
// OpenNearCells(newIndex, visited);
|
||||||
|
// }
|
||||||
|
// if (neighborCell && !buttons[newIndex]->get_active() && !neighborCell->isFlag) {
|
||||||
|
// OpenNearCells(newIndex, visited);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::OnCellClick(int x, int y) {
|
||||||
|
if (newGame) {
|
||||||
|
field.initBombs(x, y);
|
||||||
|
newGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(field.isFlagged(x, y)) {
|
||||||
|
buttons.at(x + y * field.getRows())->set_active(true);
|
||||||
|
}
|
||||||
|
else if(field.isBomb(x, y)) {
|
||||||
|
openBombs();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
field.clearCell(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::openBombs() {
|
||||||
|
for(int i=0; i < field.getCols() * field.getRows(); i++) {
|
||||||
|
int x = i % field.getCols();
|
||||||
|
int y = i / field.getRows();
|
||||||
|
|
||||||
|
buttons.at(i)->set_sensitive(false);
|
||||||
|
|
||||||
|
if(field.isBomb(x, y)) {
|
||||||
|
if(field.isFlagged(x, y)) {
|
||||||
|
auto imgFlagBomb = std::make_shared<Gtk::Image>();
|
||||||
|
imgFlagBomb->set(m_pixbufFlagBomb);
|
||||||
|
buttons.at(i)->set_child(*imgFlagBomb);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto imgBomb = std::make_shared<Gtk::Image>();
|
||||||
|
imgBomb->set(m_pixbufBomb);
|
||||||
|
buttons.at(i)->set_child(*imgBomb);
|
||||||
|
}
|
||||||
|
buttons.at(i)->set_active(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateCell(int x, int y) {
|
||||||
|
if(field.isCleared(x, y)) {
|
||||||
|
if (field.bombsNearby(x, y) > 0) {
|
||||||
|
switch(field.bombsNearby(x, y)) {
|
||||||
|
case 1:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-1");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-2");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-3");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-4");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-5");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-6");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-7");
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
buttons.at(x + y * field.getRows())->get_style_context()->add_class("label-8");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buttons.at(x + y * field.getRows())->set_label(Glib::ustring::format(field.bombsNearby(x, y)));
|
||||||
|
}
|
||||||
|
buttons.at(x + y * field.getRows())->set_active(true);
|
||||||
|
buttons.at(x + y * field.getRows())->set_sensitive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// void MainWindow::ShowGameWonAnimation() {
|
||||||
|
// // Limit the number of confetti images to 10
|
||||||
|
// int confettiCount = 10;
|
||||||
|
// for (int i = 0; i < confettiCount; ++i) {
|
||||||
|
// Glib::signal_timeout().connect_once([this]() {
|
||||||
|
// auto confetti = Gtk::make_managed<Gtk::Image>();
|
||||||
|
// confetti->set_from_resource("/mineSweeper/confetti");
|
||||||
|
// // Randomize position on the grid or overlay.
|
||||||
|
// grid->attach(*confetti, rand() % COLS, rand() % COLS);
|
||||||
|
// grid->queue_draw();
|
||||||
|
// }, i * 100); // Add confetti with a delay of 100ms each
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// bool MainWindow::AllCellsOpened()
|
||||||
|
// {
|
||||||
|
// for(int i=0; i<COLS * COLS; i++) {
|
||||||
|
// if (!buttons[i]->get_active())
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// bool MainWindow::UpdateClockLabel()
|
||||||
|
// {
|
||||||
|
// if(gameOver) return false;
|
||||||
|
|
||||||
|
// elapsedTime++;
|
||||||
|
|
||||||
|
// int deciseconds = elapsedTime % 10;
|
||||||
|
// int seconds = (elapsedTime / 10) % 60;
|
||||||
|
// int minutes = (elapsedTime /600) % 60;
|
||||||
|
|
||||||
|
// Glib::ustring msg = Glib::ustring::compose("Elapsed time: %1:%2.%3", \
|
||||||
|
// Glib::ustring::format(std::setfill(L'0'), std::setw(2), minutes), \
|
||||||
|
// Glib::ustring::format(std::setfill(L'0'), std::setw(2), seconds), \
|
||||||
|
// Glib::ustring::format(std::setfill(L'0'), std::setw(1), deciseconds));
|
||||||
|
// clockLabel.set_label(msg);
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
MainWindow::MainWindow()
|
||||||
|
{
|
||||||
|
// ApplyStyles(); // Load the CSS file
|
||||||
|
elapsedTime = 0;
|
||||||
|
newGame = true;
|
||||||
|
set_title("MineSweeper");
|
||||||
|
set_default_size(400, 400);
|
||||||
|
set_resizable(false);
|
||||||
|
|
||||||
|
boxV = Gtk::Box(Gtk::Orientation::VERTICAL);
|
||||||
|
boxH = Gtk::Box(Gtk::Orientation::HORIZONTAL);
|
||||||
|
|
||||||
|
boxH.set_hexpand(true);
|
||||||
|
|
||||||
|
boxV.append(boxH);
|
||||||
|
boxH.set_expand(true);
|
||||||
|
|
||||||
|
Gtk::Label labelMines;
|
||||||
|
labelMines.set_margin_top(12);
|
||||||
|
labelMines.set_margin_start(12);
|
||||||
|
labelMines.set_label(Glib::ustring::compose("Total mines: %1", field.getTotalMines()));
|
||||||
|
//labelMines.set_hexpand(true);
|
||||||
|
|
||||||
|
Glib::ustring msg = Glib::ustring::compose("Remaining flags: %1", field.getRemainingFlags());
|
||||||
|
flagLabel = Gtk::Label(msg);
|
||||||
|
flagLabel.set_margin_top(12);
|
||||||
|
flagLabel.set_margin_start(12);
|
||||||
|
flagLabel.set_margin_end(12);
|
||||||
|
//flagLabel.set_hexpand(true);
|
||||||
|
|
||||||
|
clockLabel.set_margin_top(12);
|
||||||
|
clockLabel.set_margin_start(12);
|
||||||
|
clockLabel.set_margin_end(12);
|
||||||
|
clockLabel.set_hexpand(true);
|
||||||
|
Glib::ustring clockmsg = Glib::ustring::compose("Elapsed time: 00:00.0");
|
||||||
|
clockLabel.set_label(clockmsg);
|
||||||
|
|
||||||
|
boxH.append(labelMines);
|
||||||
|
boxH.append(clockLabel);
|
||||||
|
boxH.append(flagLabel);
|
||||||
|
|
||||||
|
|
||||||
|
//TODO check if it's okay to mix std::shared_ptr with Gdk::ptr
|
||||||
|
m_pixbufBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/bomb-solid");
|
||||||
|
m_pixbufFlag = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-solid");
|
||||||
|
m_pixbufFlagBomb = Gdk::Pixbuf::create_from_resource("/minesweeper/flag-bomb");
|
||||||
|
|
||||||
|
// bombPix.set_from_resource("/minesweeper/bomb-solid");
|
||||||
|
|
||||||
|
auto css_provider = Gtk::CssProvider::create();
|
||||||
|
css_provider->load_from_data(
|
||||||
|
".label-1 { font-weight: bold; font-size: 1.5em; color: Blue; }\
|
||||||
|
.label-2 { font-weight: bold; font-size: 1.5em; color: Green; }\
|
||||||
|
.label-3 { font-weight: bold; font-size: 1.5em; color: Darkorange; }\
|
||||||
|
.label-4 { font-weight: bold; font-size: 1.5em; color: Purple; }\
|
||||||
|
.label-5 { font-weight: bold; font-size: 1.5em; color: Red; }\
|
||||||
|
.label-6 { font-weight: bold; font-size: 1.5em; color: Salmon; }\
|
||||||
|
.label-7 { font-weight: bold; font-size: 1.5em; color: Turquoise; }\
|
||||||
|
.label-8 { font-weight: bold; font-size: 1.5em; color: Magenta; }");
|
||||||
|
|
||||||
|
auto display = Gdk::Display::get_default();
|
||||||
|
Gtk::StyleContext::add_provider_for_display(display, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||||
|
|
||||||
|
for (int i = 0; i < field.getCols() * field.getRows(); i++) {
|
||||||
|
auto button = std::make_shared<Gtk::ToggleButton>();
|
||||||
|
button->set_size_request(50, 40);
|
||||||
|
button->set_sensitive(true);
|
||||||
|
button->set_active(false);
|
||||||
|
int x = i % field.getCols();
|
||||||
|
int y = i / field.getRows();
|
||||||
|
button->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::OnCellClick), x, y));
|
||||||
|
|
||||||
|
//button->get_style_context()->add_class("fixed-button");
|
||||||
|
|
||||||
|
auto gesture = Gtk::GestureClick::create();
|
||||||
|
gesture->set_button(3);
|
||||||
|
gesture->signal_released().connect(sigc::bind(sigc::mem_fun(*this, \
|
||||||
|
&MainWindow::OnCellRightClick), i));
|
||||||
|
button->add_controller(gesture);
|
||||||
|
|
||||||
|
buttons.push_back(button);
|
||||||
|
|
||||||
|
grid.attach(*button, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
field.clearCellSignal.connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::updateCell)));
|
||||||
|
field.remainingFlagsChangedSignal.connect(sigc::bind(sigc::mem_fun(*this, \
|
||||||
|
&MainWindow::updateFlagsLabel)));
|
||||||
|
//newGameButton.set_label("New");
|
||||||
|
//newGameButton.add_css_class("suggested-action");
|
||||||
|
//newGameButton.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnNewButtonClick));
|
||||||
|
|
||||||
|
//optionButton.set_icon_name("open-menu");
|
||||||
|
|
||||||
|
//create the minefield
|
||||||
|
//field = new MineField(COLS, MINES);
|
||||||
|
|
||||||
|
//bar.pack_start(newGameButton);
|
||||||
|
//bar.pack_end(optionButton);
|
||||||
|
|
||||||
|
//grid.set_row_homogeneous(false);
|
||||||
|
//grid.set_column_homogeneous(false);
|
||||||
|
grid.set_margin(10);
|
||||||
|
//grid.set_vexpand(true);
|
||||||
|
//grid.set_hexpand(true);
|
||||||
|
// grid.set_fill(false);
|
||||||
|
|
||||||
|
boxV.append(grid);
|
||||||
|
|
||||||
|
this->set_titlebar(bar);
|
||||||
|
this->set_child(boxV);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
auto app = Gtk::Application::create("eu.minesweeper");
|
||||||
|
return app->make_window_and_run<MainWindow>(argc, argv);
|
||||||
|
}
|
||||||
30
src/main.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#include "MineField.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
MineField field(160,160, 100);
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
int x = rand() % 160;
|
||||||
|
int y = rand() % 160;
|
||||||
|
|
||||||
|
field.initBombs(x, y);
|
||||||
|
|
||||||
|
printf("Opened cell: %i %i\n", x, y);
|
||||||
|
printf("Neighboor bombs: %i\n", field.bombsNearby(x,y));
|
||||||
|
|
||||||
|
while(!field.isGameOver()) {
|
||||||
|
x = rand() % 160;
|
||||||
|
y = rand() % 160;
|
||||||
|
|
||||||
|
if(field.clearCell(x, y)) {
|
||||||
|
printf("Opened cell: %i %i\n", x, y);
|
||||||
|
printf("Neighboor bombs: %i\n", field.bombsNearby(x,y));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Bomb found in cell: %i %i\n", x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/window.hpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MineField.hpp"
|
||||||
|
#include "gdkmm/pixbuf.h"
|
||||||
|
#include <memory>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/window.h>
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include <glibmm.h>
|
||||||
|
#include <gdkmm.h>
|
||||||
|
#include <sigc++/sigc++.h>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/togglebutton.h>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/grid.h>
|
||||||
|
#include <gtkmm-4.0/gtkmm/gestureclick.h>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/headerbar.h>
|
||||||
|
// #include <gdk-pixbuf-2.0/gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
// #include <gtkmm-4.0/gtkmm/image.h>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/box.h>
|
||||||
|
//#include <gtkmm-4.0/gtkmm/label.h>
|
||||||
|
// #include <glibmm-2.68/glibmm/ustring.h>
|
||||||
|
// #include <glibmm-2.68/glibmm/main.h>
|
||||||
|
// #include <gtkmm-4.0/gtkmm/cssprovider.h>
|
||||||
|
// #include <gtkmm-4.0/gtkmm.h>
|
||||||
|
// #include <gtkmm-4.0/gtkmm/application.h>
|
||||||
|
|
||||||
|
#define PROJECT_NAME "minesweeper"
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow : public Gtk::Window
|
||||||
|
{
|
||||||
|
Gtk::Box boxV{Gtk::Orientation::VERTICAL};
|
||||||
|
Gtk::Box boxH{Gtk::Orientation::HORIZONTAL};
|
||||||
|
std::vector<std::shared_ptr<Gtk::ToggleButton>> buttons;
|
||||||
|
Gtk::Grid grid;
|
||||||
|
Gtk::HeaderBar bar;
|
||||||
|
Gtk::Button newGameButton;
|
||||||
|
Gtk::Button optionButton;
|
||||||
|
Gtk::Label flagLabel;
|
||||||
|
Gtk::Label clockLabel;
|
||||||
|
MineField field {16, 16, 40};
|
||||||
|
int elapsedTime;
|
||||||
|
bool newGame;
|
||||||
|
std::shared_ptr<Gdk::Pixbuf> m_pixbufBomb;
|
||||||
|
std::shared_ptr<Gdk::Pixbuf> m_pixbufFlag;
|
||||||
|
std::shared_ptr<Gdk::Pixbuf> m_pixbufFlagBomb;
|
||||||
|
void updateCell(int x, int y);
|
||||||
|
void openBombs();
|
||||||
|
void updateFlagsLabel(int flags);
|
||||||
|
|
||||||
|
// sigc::connection clockConn;
|
||||||
|
// void OpenNearCells(int index);
|
||||||
|
// void Explode();
|
||||||
|
// bool AllCellsOpened();
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow();
|
||||||
|
// void OnNewButtonClick();
|
||||||
|
void OnCellClick(int x, int y);
|
||||||
|
void OnCellRightClick(int n_press, double n_x, double n_y, int index);
|
||||||
|
// void ShowGameWonAnimation();
|
||||||
|
// void ApplyStyles();
|
||||||
|
// bool UpdateClockLabel();
|
||||||
|
};
|
||||||