26 #include <kglobalsettings.h>
28 #include <kstandarddirs.h>
30 #include <QMouseEvent>
38 #define SEASONS_START 28
39 #define FLOWERS_START 39
41 static int s_delay[5] = {1000, 750, 500, 250, 125};
48 kDebug() <<
"isInPath:" << x <<
"," << y;
58 if ((x == iter->x && ((y > pathY && y <= iter->y) || (y < pathY && y >= iter->y)))
59 || (y == iter->y && ((x > pathX && x <= iter->x) || (x < pathX && x >= iter->x)))) {
60 kDebug() <<
"isInPath:" << x <<
"," << y <<
"found in path" << pathX <<
"," << pathY <<
" => " << iter->x <<
"," << iter->y;
71 m_markX(0), m_markY(0),
73 m_xTiles(0), m_yTiles(0),
74 m_delay(0), m_level(0), m_shuffle(0),
75 m_gameState(Normal), m_cheat(false),
76 m_gravityFlag(true), m_solvableFlag(false), m_chineseStyleFlag(false), m_tilesCanSlideFlag(false),
77 m_highlightedTile(-1),
78 m_paintConnection(false), m_paintPossibleMoves(false), m_paintInProgress(false),
79 m_soundPick(KStandardDirs::locate(
"sound",
"kshisen/tile-touch.ogg")),
80 m_soundFall(KStandardDirs::locate(
"sound",
"kshisen/tile-fall-tile.ogg"))
82 m_tileRemove1.first = -1;
102 kDebug() <<
"An error occurred when loading the tileset" <<
Prefs::tileSet() <<
"KShisen will continue with the default tileset.";
107 kDebug() <<
"An error occurred when loading the background" <<
Prefs::background() <<
"KShisen will continue with the default background.";
139 if (m_tiles.loadTileset(pathToTileset)) {
140 if (m_tiles.loadGraphics()) {
148 if (m_tiles.loadDefault()) {
149 if (m_tiles.loadGraphics()) {
160 if (m_background.load(pathToBackground,
width(),
height())) {
161 if (m_background.loadGraphics()) {
169 if (m_background.loadDefault()) {
170 if (m_background.loadGraphics()) {
189 void Board::setField(
int x,
int y,
int value)
192 kFatal() <<
"Attempted write to invalid field position "
193 "(" << x <<
"," << y <<
")";
196 m_field[y *
xTiles() +
x] = value;
200 int Board::field(
int x,
int y)
const
204 kFatal() <<
"Attempted read from invalid field position "
205 "(" << x <<
"," << y <<
")";
213 return m_field[y *
xTiles() +
x];
216 void Board::gravity(
bool update)
219 if (!m_gravityFlag) {
222 bool fallingTiles =
false;
223 for (
int i = 0; i <
xTiles(); ++i) {
224 if (gravity(i, update)) {
234 bool Board::gravity(
int column,
bool update)
236 bool isAffected =
false;
241 if (field(column, wptr) !=
EMPTY) {
245 if (field(column, rptr) !=
EMPTY) {
246 setField(column, wptr, field(column, rptr));
247 setField(column, rptr,
EMPTY);
250 updateField(column, rptr);
251 updateField(column, wptr);
264 void Board::unmarkTile()
267 if (m_markX == -1 || m_markY == -1) {
270 drawPossibleMoves(
false);
271 m_possibleMoves.
clear();
274 int oldMarkX = m_markX;
275 int oldMarkY = m_markY;
278 updateField(oldMarkX, oldMarkY);
288 if (m_paintInProgress) {
291 switch (m_gameState) {
304 int posX = (e->
pos().
x() - xOffset()) / (m_tiles.qWidth() * 2);
305 int posY = (e->
pos().
y() - yOffset()) / (m_tiles.qHeight() * 2);
307 if (e->
pos().
x() < xOffset() || e->
pos().
y() < yOffset() ||
314 if (e->
button() == Qt::LeftButton) {
326 if (e->
button() == Qt::RightButton) {
327 int clickedTile = field(posX, posY);
330 if (m_markX != -1 && field(m_markX, m_markY) != clickedTile) {
338 if (clickedTile != m_highlightedTile) {
339 int oldHighlighted = m_highlightedTile;
340 m_highlightedTile = clickedTile;
341 for (
int i = 0; i <
xTiles(); ++i) {
342 for (
int j = 0; j <
yTiles(); ++j) {
343 const int fieldTile = field(i, j);
344 if (fieldTile !=
EMPTY) {
345 if (fieldTile == oldHighlighted) {
347 }
else if (fieldTile == clickedTile) {
349 }
else if (m_chineseStyleFlag) {
369 int Board::xOffset()
const
371 int tw = m_tiles.qWidth() * 2;
375 int Board::yOffset()
const
377 int th = m_tiles.qHeight() * 2;
389 m_field =
new int[ x *
y ];
392 for (
int i = 0; i <
x; ++i) {
393 for (
int j = 0; j <
y; ++j) {
394 setField(i, j,
EMPTY);
399 const double MINIMUM_SCALE = 0.2;
400 int w = qRound(m_tiles.qWidth() * 2.0 * MINIMUM_SCALE) *
xTiles();
401 int h = qRound(m_tiles.qHeight() * 2.0 * MINIMUM_SCALE) *
yTiles();
402 w += m_tiles.width();
403 h += m_tiles.width();
414 kDebug() <<
"[resizeEvent]";
416 kDebug() <<
"[resizeEvent] spontaneous";
426 m_tiles.reloadTileset(newsize);
438 m_gameState = Normal;
443 m_highlightedTile = -1;
447 m_connection.
clear();
448 m_possibleMoves.
clear();
462 for (
int y = 0; y <
yTiles(); ++
y) {
463 for (
int x = 0; x <
xTiles(); ++
x) {
466 setField(x, y, curTile);
467 if (++tileCount >= 4) {
473 setField(x, y, curTile++);
481 if (m_shuffle == 0) {
492 for (
int i = 0; i < tx * ty * m_shuffle; ++i) {
493 int x1 = m_random.getLong(tx);
494 int y1 = m_random.getLong(ty);
495 int x2 = m_random.getLong(tx);
496 int y2 = m_random.getLong(ty);
500 int t = field(x1, y1);
501 setField(x1, y1, field(x2, y2));
506 if (!m_solvableFlag) {
517 memcpy(oldfield, m_field, fsize);
521 int maxAttempts = 200;
523 while (!
solvable(
true) && maxAttempts > 0) {
525 int numberOfTiles = 0;
527 if (m_field[i] !=
EMPTY) {
528 pos[numberOfTiles] = i;
529 tiles[numberOfTiles] = m_field[i];
535 memcpy(m_field, oldfield, fsize);
538 while (numberOfTiles > 0) {
540 int r1 = m_random.getLong(numberOfTiles);
541 int r2 = m_random.getLong(numberOfTiles);
542 int tile = tiles[r1];
546 tiles[r1] = tiles[numberOfTiles-1];
547 pos[r2] = pos[numberOfTiles-1];
551 m_field[apos] = tile;
555 memcpy(oldfield, m_field, fsize);
559 if (maxAttempts == 0) {
560 kDebug() <<
"NewGame make solvable failed";
565 memcpy(m_field, oldfield, fsize);
575 bool Board::tilesMatch(
int tile1,
int tile2)
const
578 if (tile1 == tile2) {
583 if (m_chineseStyleFlag) {
598 bool Board::isTileHighlighted(
int x,
int y)
const
600 if (x == m_markX && y == m_markY) {
604 if (tilesMatch(m_highlightedTile, field(x, y))) {
610 if (!m_connection.
isEmpty() && m_tileRemove1.first != -1) {
611 if (x == m_connection.
first().x && y == m_connection.
first().y) {
615 if (x == m_connection.
last().x && y == m_connection.
last().y) {
623 void Board::updateField(
int x,
int y)
625 QRect r(xOffset() + x * m_tiles.qWidth() * 2,
626 yOffset() + y * m_tiles.qHeight() * 2,
635 int boxWidth =
width() * 0.6;
636 int boxHeight =
height() * 0.6;
639 int fontsize = boxHeight / 13;
646 p.
drawText(contentsRect, Qt::AlignCenter | Qt::TextWordWrap, message);
651 int w = m_tiles.width();
652 int h = m_tiles.height();
653 int fw = m_tiles.qWidth() * 2;
654 int fh = m_tiles.qHeight() * 2;
655 for (
int i = 0; i <
xTiles(); ++i) {
656 for (
int j = 0; j <
yTiles(); ++j) {
657 int tile = field(i, j);
662 int xpos = xOffset() + i * fw;
663 int ypos = yOffset() + j * fh;
664 QRect r(xpos, ypos, w, h);
666 if (isTileHighlighted(i, j)) {
667 p.
drawPixmap(xpos, ypos, m_tiles.selectedTile(1));
669 p.
drawPixmap(xpos, ypos, m_tiles.unselectedTile(1));
673 p.
drawPixmap(xpos, ypos, m_tiles.tileface(tile - 1));
683 p.
fillRect(ur, m_background.getBackground());
685 switch (m_gameState) {
690 showInfoRect(p, i18n(
"Game Paused\nClick to resume game."));
694 showInfoRect(p, i18n(
"Game Stuck\nNo more moves possible."));
697 showInfoRect(p, i18n(
"Game Over\nClick to start a new game."));
701 if (m_paintConnection) {
704 Path::const_iterator pt1 = m_connection.
constBegin();
705 Path::const_iterator pt2 = pt1 + 1;
706 while (pt2 != m_connection.
constEnd()) {
707 p.
drawLine(midCoord(pt1->x, pt1->y), midCoord(pt2->x, pt2->y));
712 m_paintConnection =
false;
714 if (m_paintPossibleMoves) {
718 Path::const_iterator pt1 = iter->m_path.constBegin();
719 Path::const_iterator pt2 = pt1 + 1;
720 while (pt2 != iter->m_path.constEnd()) {
721 p.
drawLine(midCoord(pt1->x, pt1->y), midCoord(pt2->x, pt2->y));
726 m_paintConnection =
false;
731 void Board::reverseSlide(
int x,
int y,
int slideX1,
int slideY1,
int slideX2,
int slideY2)
736 int dx = slideX1 - slideX2;
737 int dy = slideY1 - slideY2;
742 for (
int i = y + 1; i <= slideY2; ++i) {
743 current_tile = field(x, i);
744 if (current_tile ==
EMPTY) {
747 setField(x, i,
EMPTY);
748 setField(x, i + dy, current_tile);
750 updateField(x, i + dy);
753 for (
int i = y - 1; i >= slideY2; --i) {
754 current_tile = field(x, i);
755 if (current_tile ==
EMPTY) {
758 setField(x, i,
EMPTY);
759 setField(x, i + dy, current_tile);
761 updateField(x, i + dy);
764 }
else if (dy == 0) {
766 for (
int i = x + 1; i <= slideX2; ++i) {
767 current_tile = field(i, y);
768 if (current_tile ==
EMPTY) {
771 setField(i, y,
EMPTY);
772 setField(i + dx, y, current_tile);
774 updateField(i + dx, y);
777 for (
int i = x - 1; i >= slideX2; --i) {
778 current_tile = field(i, y);
779 if (current_tile ==
EMPTY) {
782 setField(i, y,
EMPTY);
783 setField(i + dx, y, current_tile);
785 updateField(i + dx, y);
791 void Board::performSlide(
int x,
int y,
Path &slide)
801 int dx = slide.
last().x - slide.
first().x;
802 int dy = slide.
last().y - slide.
first().y;
806 if (y < slide.
first().y) {
807 for (
int i = slide.
first().y; i >
y; --i) {
808 current_tile = field(x, i);
809 setField(x, i,
EMPTY);
810 setField(x, i + dy, current_tile);
812 updateField(x, i + dy);
815 for (
int i = slide.
first().y; i <
y; ++i) {
816 current_tile = field(x, i);
817 setField(x, i,
EMPTY);
818 setField(x, i + dy, current_tile);
820 updateField(x, i + dy);
823 }
else if (dy == 0) {
824 if (x < slide.
first().x) {
825 for (
int i = slide.
first().x; i >
x; --i) {
826 current_tile = field(i, y);
827 setField(i, y,
EMPTY);
828 setField(i + dx, y, current_tile);
830 updateField(i + dx, y);
833 for (
int i = slide.
first().x; i <
x; ++i) {
834 current_tile = field(i, y);
835 setField(i, y,
EMPTY);
836 setField(i + dx, y, current_tile);
838 updateField(i + dx, y);
846 m_connection = possibleMoves.
m_path;
851 memcpy(saved1, m_field, fsize);
856 performSlide(m_markX, m_markY, possibleMoves.
m_slide);
861 drawPossibleMoves(
false);
867 m_possibleMoves.
clear();
875 memcpy(saved2, m_field, fsize);
877 bool errorFound =
false;
882 if (saved1[i] != m_field[i]) {
883 kDebug() <<
"[DEBUG Undo 1], tile (" << i <<
") was" << saved1[i] <<
"before more, it is" << m_field[i] <<
"after undo.";
888 memcpy(saved3, m_field, fsize);
895 if (saved2[i] != m_field[i]) {
896 kDebug() <<
"[DEBUG Undo 2], tile (" << i <<
") was" << saved2[i] <<
"after more, it is" << m_field[i] <<
"after redo.";
901 memcpy(saved4, m_field, fsize);
906 kDebug() <<
"[DEBUG] Before move";
908 kDebug() <<
"[DEBUG] After move";
910 kDebug() <<
"[DEBUG] Undo";
912 kDebug() <<
"[DEBUG] Redo";
924 void Board::marked(
int x,
int y)
926 if (field(x, y) ==
EMPTY) {
927 if (m_possibleMoves.
count() > 1) {
929 if (iter->isInPath(x, y)) {
948 if (x == m_markX && y == m_markY) {
958 drawPossibleMoves(
false);
959 m_possibleMoves.
clear();
963 }
else if (m_possibleMoves.
count() > 1) {
966 if (iter->isInPath(x, y)) {
974 int tile1 = field(m_markX, m_markY);
975 int tile2 = field(x, y);
978 if (!tilesMatch(tile1, tile2)) {
985 if (findPath(m_markX, m_markY, x, y, m_possibleMoves) > 0) {
986 if (m_possibleMoves.
count() > 1) {
990 if (iter->m_hasSlide) {
996 drawPossibleMoves(
true);
1003 performMove(m_possibleMoves.
first());
1010 m_connection.
clear();
1015 void Board::clearHighlight()
1017 if (m_highlightedTile == -1) {
1020 int oldHighlighted = m_highlightedTile;
1021 m_highlightedTile = -1;
1023 for (
int i = 0; i <
xTiles(); ++i) {
1024 for (
int j = 0; j <
yTiles(); ++j) {
1025 if (tilesMatch(oldHighlighted, field(i, j))) {
1032 bool Board::canMakePath(
int x1,
int y1,
int x2,
int y2)
const
1035 for (
int i = qMin(y1, y2) + 1; i < qMax(y1, y2); ++i) {
1036 if (field(x1, i) !=
EMPTY) {
1044 for (
int i = qMin(x1, x2) + 1; i < qMax(x1, x2); ++i) {
1045 if (field(i, y1) !=
EMPTY) {
1055 bool Board::canSlideTiles(
int x1,
int y1,
int x2,
int y2,
Path &path)
const
1063 int start_free = -1;
1066 for (
int i = y1 - 1; i >= 0; --i) {
1067 if (field(x1, i) ==
EMPTY) {
1074 if (start_free == -1 || start_free == (y1 - 1)) {
1078 for (
int i = start_free - 1; i >= 0; --i) {
1079 if (field(x1, i) !=
EMPTY) {
1087 if (distance <= (start_free - end_free)) {
1096 }
else if (y2 > y1) {
1099 int start_free = -1;
1102 for (
int i = y1 + 1; i <
yTiles(); ++i) {
1103 if (field(x1, i) ==
EMPTY) {
1110 if (start_free == -1 || start_free == y1 + 1) {
1114 for (
int i = start_free + 1; i <
yTiles(); ++i) {
1115 if (field(x1, i) !=
EMPTY) {
1123 if (distance <= (end_free - start_free)) {
1141 int start_free = -1;
1144 for (
int i = x1 - 1; i >= 0; --i) {
1145 if (field(i, y1) ==
EMPTY) {
1152 if (start_free == -1 || start_free == x1 - 1) {
1156 for (
int i = start_free - 1; i >= 0; --i) {
1157 if (field(i, y1) !=
EMPTY) {
1165 if (distance <= (start_free - end_free)) {
1174 }
else if (x2 > x1) {
1177 int start_free = -1;
1180 for (
int i = x1 + 1; i <
xTiles(); ++i) {
1181 if (field(i, y1) ==
EMPTY) {
1188 if (start_free == -1 || start_free == x1 + 1) {
1192 for (
int i = start_free + 1; i <
xTiles(); ++i) {
1193 if (field(i, y1) !=
EMPTY) {
1201 if (distance <= (end_free - start_free)) {
1217 int Board::findPath(
int x1,
int y1,
int x2,
int y2,
PossibleMoves &possibleMoves)
const
1219 possibleMoves.
clear();
1221 int numberOfPaths = 0;
1225 numberOfPaths = findSimplePath(x1, y1, x2, y2, possibleMoves);
1228 if (m_tilesCanSlideFlag) {
1229 return numberOfPaths;
1233 const int dx[4] = { 1, 0, -1, 0 };
1234 const int dy[4] = { 0, 1, 0, -1 };
1236 for (
int i = 0; i < 4; ++i) {
1237 int newX = x1 + dx[i];
1238 int newY = y1 + dy[i];
1239 while (newX >= -1 && newX <=
xTiles() &&
1240 newY >= -1 && newY <=
yTiles() &&
1241 field(newX, newY) ==
EMPTY) {
1242 if ((simplePath = findSimplePath(newX, newY, x2, y2, possibleMoves)) > 0) {
1244 numberOfPaths += simplePath;
1250 return numberOfPaths;
1253 int Board::findSimplePath(
int x1,
int y1,
int x2,
int y2,
PossibleMoves &possibleMoves)
const
1255 int numberOfPaths = 0;
1258 if (canMakePath(x1, y1, x2, y2)) {
1269 if (x1 == x2 || y1 == y2) {
1270 return numberOfPaths;
1275 if (m_tilesCanSlideFlag) {
1278 if (canSlideTiles(x1, y1, x2, y1, slidePath) && canMakePath(x2, y1, x2, y2)) {
1288 if (canSlideTiles(x1, y1, x1, y2, slidePath) && canMakePath(x1, y2, x2, y2)) {
1301 if (field(x2, y1) ==
EMPTY && canMakePath(x1, y1, x2, y1) &&
1302 canMakePath(x2, y1, x2, y2)) {
1312 if (field(x1, y2) ==
EMPTY && canMakePath(x1, y1, x1, y2) &&
1313 canMakePath(x1, y2, x2, y2)) {
1322 return numberOfPaths;
1325 void Board::drawPossibleMoves(
bool b)
1327 if (m_possibleMoves.
isEmpty()) {
1331 m_paintPossibleMoves = b;
1335 void Board::drawConnection()
1337 m_paintInProgress =
true;
1342 int x1 = m_connection.
first().x;
1343 int y1 = m_connection.
first().y;
1344 int x2 = m_connection.
last().x;
1345 int y2 = m_connection.
last().y;
1347 updateField(x1, y1);
1348 updateField(x2, y2);
1350 m_paintConnection =
true;
1354 void Board::undrawConnection()
1356 if (m_tileRemove1.first != -1) {
1357 setField(m_tileRemove1.first, m_tileRemove1.second,
EMPTY);
1358 setField(m_tileRemove2.first, m_tileRemove2.second,
EMPTY);
1359 m_tileRemove1.first = -1;
1371 Path oldConnection = m_connection;
1372 m_connection.
clear();
1373 m_paintConnection =
false;
1375 Path::const_iterator pt1 = oldConnection.
constBegin();
1376 Path::const_iterator pt2 = pt1 + 1;
1377 while (pt2 != oldConnection.
constEnd()) {
1378 if (pt1->y == pt2->y) {
1379 for (
int i = qMin(pt1->x, pt2->x); i <= qMax(pt1->x, pt2->x); ++i) {
1380 updateField(i, pt1->y);
1383 for (
int i = qMin(pt1->y, pt2->y); i <= qMax(pt1->y, pt2->y); ++i) {
1384 updateField(pt1->x, i);
1393 if (!
hint_I(dummyPossibleMoves)) {
1394 m_gameClock.pause();
1397 m_paintInProgress =
false;
1400 QPoint Board::midCoord(
int x,
int y)
const
1403 int w = m_tiles.qWidth() * 2;
1404 int h = m_tiles.qHeight() * 2;
1407 p.
setX(xOffset() - (w / 4));
1408 }
else if (x ==
xTiles()) {
1409 p.
setX(xOffset() + (w *
xTiles()) + (w / 4));
1411 p.
setX(xOffset() + (w * x) + (w / 2));
1415 p.
setY(yOffset() - (w / 4));
1416 }
else if (y ==
yTiles()) {
1417 p.
setY(yOffset() + (h *
yTiles()) + (w / 4));
1419 p.
setY(yOffset() + (h * y) + (h / 2));
1427 if (m_delay == newValue) {
1438 void Board::madeMove(
int x1,
int y1,
int x2,
int y2,
Path slide)
1441 if (slide.
empty()) {
1442 move =
new Move(x1, y1, x2, y2, field(x1, y1), field(x2, y2));
1444 move =
new Move(x1, y1, x2, y2, field(x1, y1), field(x2, y2), slide.
first().x, slide.
first().y, slide.
last().x, slide.
last().y);
1447 while (m_redo.
count()) {
1448 delete m_redo.
first();
1488 kDebug() <<
"[undo] gravity from a no slide move";
1491 for (y = 0; y < move->
m_y1; ++
y) {
1492 setField(move->
m_x1, y, field(move->
m_x1, y + 1));
1493 updateField(move->
m_x1, y);
1497 for (y = 0; y < move->
m_y2; ++
y) {
1498 setField(move->
m_x2, y, field(move->
m_x2, y + 1));
1499 updateField(move->
m_x2, y);
1511 kDebug() <<
"[undo] gravity from horizontal slide";
1525 kDebug() <<
"[undo] n =" << n;
1532 kDebug() <<
"[undo] slide right";
1537 for (j = 0; j <
yTiles(); ++j) {
1538 if (field(i, j) !=
EMPTY) {
1544 if (j <= move->m_slideY1) {
1548 kDebug() <<
"[undo] moving (" << i <<
"," << j <<
") up to (" << i <<
"," << move->
m_slideY1 <<
")";
1551 setField(i, move->
m_slideY1, field(i, j));
1552 setField(i, j,
EMPTY);
1558 kDebug() <<
"[undo] slide left";
1560 for (
int i = move->
m_slideX2; i < move->m_slideX2 + n; ++i) {
1563 for (j = 0; j <
yTiles(); ++j) {
1564 if (field(i, j) !=
EMPTY) {
1570 if (j <= move->m_slideY1) {
1574 kDebug() <<
"[undo] moving (" << i <<
"," << j <<
") up to (" << i <<
"," << move->
m_slideY1 <<
")";
1577 setField(i, move->
m_slideY1, field(i, j));
1578 setField(i, j,
EMPTY);
1585 kDebug() <<
"[undo] moving up column x2" << move->
m_x2;
1587 for (y = 0; y <= move->
m_y2; ++
y) {
1589 kDebug() <<
"[undo] moving up tile" << y + 1;
1591 setField(move->
m_x2, y, field(move->
m_x2, y + 1));
1592 updateField(move->
m_x2, y);
1601 for (
int i = move->
m_x1 + dx; i >= move->
m_x1; --i) {
1603 kDebug() <<
"[undo] moving up column" << i <<
"until" << move->
m_slideY1;
1605 for (
int j = 0; j < move->
m_slideY1; ++j) {
1607 kDebug() <<
"[undo] moving up tile" << j + 1;
1609 setField(i, j, field(i, j + 1));
1613 kDebug() <<
"[undo] clearing last tile" << move->
m_slideY1;
1621 for (
int i = move->
m_x1 - dx; i <= move->m_x1; ++i) {
1623 kDebug() <<
"[undo] moving up column" << i <<
"until" << move->
m_slideY1;
1625 for (
int j = 0; j < move->
m_slideY1; ++j) {
1627 kDebug() <<
"[undo] moving up tile" << j + 1;
1629 setField(i, j, field(i, j + 1));
1633 kDebug() <<
"[undo] clearing last tile" << move->
m_slideY1;
1643 kDebug() <<
"[undo] reversing slide";
1652 kDebug() <<
"[undo] gravity from vertical slide";
1656 for (y = 0; y < move->
m_y1; ++
y) {
1657 setField(move->
m_x1, y, field(move->
m_x1, y + 1));
1658 updateField(move->
m_x1, y);
1662 for (y = 0; y < move->
m_y2; ++
y) {
1663 setField(move->
m_x2, y, field(move->
m_x2, y + 1));
1664 updateField(move->
m_x2, y);
1679 updateField(move->
m_x1, move->
m_y1);
1680 updateField(move->
m_x2, move->
m_y2);
1697 performSlide(move->
m_x1, move->
m_y1, s);
1701 updateField(move->
m_x1, move->
m_y1);
1702 updateField(move->
m_x2, move->
m_y2);
1713 if (
hint_I(m_possibleMoves)) {
1714 m_connection = m_possibleMoves.
first().m_path;
1721 void Board::makeHintMove()
1725 if (
hint_I(possibleMoves)) {
1728 marked(possibleMoves.
first().m_path.first().x, possibleMoves.
first().m_path.first().y);
1729 marked(possibleMoves.
first().m_path.last().x, possibleMoves.
first().m_path.last().y);
1734 void Board::dumpBoard()
const
1736 kDebug() <<
"Board contents:";
1737 for (
int y = 0; y <
yTiles(); ++
y) {
1739 for (
int x = 0; x <
xTiles(); ++
x) {
1740 int tile = field(x, y);
1741 if (tile ==
EMPTY) {
1751 void Board::dumpBoard(
const int *board)
const
1753 kDebug() <<
"Board contents:";
1754 for (
int y = 0; y <
yTiles(); ++
y) {
1756 for (
int x = 0; x <
xTiles(); ++
x) {
1757 int tile = board[y *
xTiles() +
x];
1758 if (tile ==
EMPTY) {
1769 int Board::lineWidth()
const
1771 int width = qRound(m_tiles.height() / 10.0);
1786 for (
int x = 0; x <
xTiles(); ++
x) {
1787 for (
int y = 0; y <
yTiles(); ++
y) {
1788 int tile = field(x, y);
1789 if (tile !=
EMPTY && done[tile - 1] != 4) {
1791 for (
int xx = 0; xx <
xTiles(); ++xx) {
1792 for (
int yy = 0; yy <
yTiles(); ++yy) {
1793 if (xx != x || yy != y) {
1794 if (tilesMatch(field(xx, yy), tile)) {
1795 if (findPath(x, y, xx, yy, possibleMoves) > 0) {
1813 for (
int i = 0; i <
xTiles(); ++i) {
1814 for (
int j = 0; j <
yTiles(); ++j) {
1815 if (field(i, j) !=
EMPTY) {
1826 return m_gameClock.seconds();
1835 memcpy(oldField, m_field,
xTiles() *
yTiles() *
sizeof(
int));
1840 kFatal(!tilesMatch(field(p.
first().m_path.first().x, p.
first().m_path.first().y), field(p.
first().m_path.last().x, p.
first().m_path.last().y)))
1841 <<
"Removing unmatched tiles: (" << p.
first().m_path.first().x <<
"," << p.
first().m_path.first().y <<
") => "
1842 << field(p.
first().m_path.first().x, p.
first().m_path.first().y) <<
" (" << p.
first().m_path.last().x <<
"," << p.
first().m_path.last().y <<
") => "
1843 << field(p.
first().m_path.last().x, p.
first().m_path.last().y);
1844 setField(p.
first().m_path.first().x, p.
first().m_path.first().y,
EMPTY);
1845 setField(p.
first().m_path.last().x, p.
first().m_path.last().y,
EMPTY);
1851 memcpy(m_field, oldField,
xTiles() *
yTiles() *
sizeof(
int));
1860 return m_solvableFlag;
1865 if (m_solvableFlag == enabled) {
1870 if (m_solvableFlag && !
solvable()) {
1877 return m_gravityFlag;
1882 if (m_gravityFlag == enabled) {
1894 if (m_chineseStyleFlag == enabled) {
1904 if (m_tilesCanSlideFlag == enabled) {
1907 m_tilesCanSlideFlag =
enabled;
1916 if ((m_gameState == Paused && enabled) || m_gameState == Stuck) {
1920 m_gameState = Paused;
1921 m_gameClock.pause();
1923 m_gameState = Normal;
1924 m_gameClock.resume();
1936 return QSize(9 * dpi, 7 * dpi);
1941 m_gameClock.restart();
1964 if (m_gameState == Stuck && enabled) {
1968 m_gameState = Stuck;
1969 m_gameClock.pause();
1971 m_gameState = Normal;
1972 m_gameClock.resume();
1980 if (m_gameState == Over && enabled) {
1990 if (m_cheat == enabled) {
1999 return m_gameState == Over;
2004 return m_gameState == Paused;
2009 return m_gameState == Stuck;
2023 #include "board.moc"
Path m_slide
path representing the movement of the last sliding tile
void setBrush(ColorRole role, const QBrush &brush)
bool canUndo() const
Returns if undo step is available.
static void setBackground(const QString &v)
Set The background to use.
void setPointSize(int pointSize)
void fillRect(const QRectF &rectangle, const QBrush &brush)
static bool gravity()
Get Gravity.
void setRenderHint(RenderHint hint, bool on)
bool m_hasSlide
flag set if the move requires a slide
QRect contentsRect() const
void setGameStuckEnabled(bool enabled)
Sets whether there are no matching tiles left.
bool loadTileset(const QString &)
Loads the given tileset.
bool hasCheated() const
Returns whether player is in cheat mode.
void loadSettings()
Loads the game settings.
bool isOver() const
Returns whether the game is over.
int m_tile1
type of tile at first set of coordinates
static int speed()
Get Speed.
bool intersects(const QRect &rectangle) const
bool isInPath(int x, int y) const
bool solvableFlag() const
void setChineseStyleFlag(bool b)
int tilesLeft() const
Returns the number of tiles left on the board.
static bool chineseStyle()
Get ChineseStyle.
static int level()
Get Level.
void drawLine(const QLineF &line)
bool solvable(bool noRestore=false)
Returns whether the current game is solvable.
virtual QSize sizeHint() const
bool isPaused() const
Returns whether the game is in pause mode.
int m_y2
coordinates of the two tiles that matched
const QRect & rect() const
int m_slideY1
original y coordinate of the last slided tile
static bool sounds()
Get Sounds.
int m_slideX2
final x coordinate of the last slided tile
void setFont(const QFont &font)
Path m_path
path used to connect the two tiles
int count(const T &value) const
void setSize(int x, int y)
void append(const T &value)
void setTilesCanSlideFlag(bool b)
void resetUndo()
Resets the undo history.
bool isStuck() const
Returns whether there are still matching tiles left.
void setPen(const QColor &color)
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
virtual void resizeEvent(QResizeEvent *e)
Class holding a move on the board made by the player.
virtual void paintEvent(QPaintEvent *e)
Class holding a possible move and its functions.
void setBrush(const QBrush &brush)
void drawText(const QPointF &position, const QString &text)
int m_tile2
type of tile at second set of coordinates
static void setTileSet(const QString &v)
Set The tile set to use.
void cheatStatusChanged()
bool loadBackground(const QString &)
Loads the given background.
void setSoundsEnabled(bool enabled)
Enables / disables sounds.
static QString tileSet()
Get The tile set to use.
static bool solvable()
Get Solvable.
void newGame()
Does most of the newGame work.
void setSolvableFlag(bool b)
int currentTime() const
Returns the current game time in seconds.
static int size()
Get Size.
void resetRedo()
Resets the redo history.
Struct holding a position on the board (x,y)
int m_slideX1
original x coordinate of the last slided tile
static bool tilesCanSlide()
Get TilesCanSlide.
void prepend(const T &value)
void setGravityFlag(bool b)
const QPoint & pos() const
void setPauseEnabled(bool enabled)
Controls the pause mode.
bool canRedo() const
Returns if redo step is available.
const_iterator constEnd() const
void redo()
Redoes one step.
static QString background()
Get The background to use.
const_iterator constBegin() const
void resetTimer()
Resets the game timer.
virtual void mousePressEvent(QMouseEvent *e)
void setGameOverEnabled(bool enabled)
Sets whether the game is over.
static void setSounds(bool v)
Set Sounds.
bool m_hasSlide
if we performed a slide during the move
void undo()
Undoes one step.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void selectAMatchingTile()
int m_slideY2
final y coordinate of the last slided tile
void setCheatModeEnabled(bool enabled)
Sets whether the game is in cheat mode.
bool hint_I(PossibleMoves &possibleMoves) const