-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Another piece of random useless code in QGIS. Happy April 1st!
Type "bored" into the coordinates box (best results with a map loaded in canvas) Click on tiles to move them to the empty space. Click on the empty tile to toggle tile numbers.
- Loading branch information
Showing
6 changed files
with
259 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
/*************************************************************************** | ||
qgspuzzlewidget.cpp | ||
-------------------------------------- | ||
Date : 1st of April 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgspuzzlewidget.h" | ||
|
||
#include "qgsmapcanvas.h" | ||
|
||
#include <QGraphicsPixmapItem> | ||
#include <QMessageBox> | ||
|
||
|
||
static bool testSolved( QVector<int> &positions ) | ||
{ | ||
for ( int i = 0; i < positions.count() - 1; ++i ) | ||
{ | ||
if ( positions[i] != i ) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
static int findEmpty( QVector<int> &positions ) | ||
{ | ||
for ( int i = 0; i < positions.count(); ++i ) | ||
{ | ||
if ( positions[i] == -1 ) | ||
return i; | ||
} | ||
Q_ASSERT( false ); | ||
return -1; | ||
} | ||
|
||
// half of the possible permutations lead to an unsolvable puzzle, so we initialize the puzzle by | ||
// doing valid moves | ||
// https://en.wikipedia.org/wiki/15_puzzle | ||
static void shuffle( QVector<int> &positions, int count ) | ||
{ | ||
int size = sqrt( positions.count() ); | ||
int idxEmpty = findEmpty( positions ); | ||
int cEmpty = idxEmpty % size, rEmpty = idxEmpty / size; | ||
int moveX[] = { 0, 0, 1, -1 }; | ||
int moveY[] = { 1, -1, 0, 0 }; | ||
int cOther, rOther; | ||
for ( int i = 0; i < count; ++i ) | ||
{ | ||
do | ||
{ | ||
int move = qrand() % 4; | ||
cOther = cEmpty + moveX[move]; | ||
rOther = rEmpty + moveY[move]; | ||
} | ||
while ( cOther < 0 || cOther >= size || rOther < 0 || rOther >= size ); | ||
|
||
int idxOther = rOther * size + cOther; | ||
std::swap( positions[idxEmpty], positions[idxOther] ); | ||
idxEmpty = idxOther; | ||
cEmpty = idxEmpty % size; | ||
rEmpty = idxEmpty / size; | ||
} | ||
} | ||
|
||
QgsPuzzleWidget::QgsPuzzleWidget( QgsMapCanvas *canvas ) | ||
: mCanvas( canvas ) | ||
{ | ||
setInteractive( false ); | ||
setBackgroundBrush( QBrush( Qt::lightGray ) ); | ||
} | ||
|
||
void QgsPuzzleWidget::mousePressEvent( QMouseEvent *event ) | ||
{ | ||
int idxEmpty = findEmpty( mPositions ); | ||
int rEmpty = idxEmpty / mSize; | ||
int cEmpty = idxEmpty % mSize; | ||
int cMouse = event->pos().x() / mTileWidth; | ||
int rMouse = event->pos().y() / mTileHeight; | ||
int idxMouse = rMouse * mSize + cMouse; | ||
int dx = cMouse - cEmpty; | ||
int dy = rMouse - rEmpty; | ||
|
||
if ( ( dx == 0 && qAbs( dy ) == 1 ) || ( dy == 0 && qAbs( dx ) == 1 ) ) | ||
{ | ||
std::swap( mPositions[idxEmpty], mPositions[idxMouse] ); | ||
updateTilePositions(); | ||
if ( testSolved( mPositions ) ) | ||
{ | ||
QMessageBox::information( nullptr, tr( "QGIS" ), tr( "Well done!\n\nNow let's get back to work, shall we?" ) ); | ||
emit done(); | ||
} | ||
} | ||
else if ( dx == 0 && dy == 0 ) | ||
{ | ||
// toggle text help when clicked on empty tile | ||
for ( int i = 0; i < mTextItems.count(); ++i ) | ||
mTextItems[i]->setVisible( !mTextItems[i]->isVisible() ); | ||
} | ||
} | ||
|
||
void QgsPuzzleWidget::letsGetThePartyStarted() | ||
{ | ||
mPositions.clear(); | ||
delete mScene; | ||
mItems.clear(); | ||
mTextItems.clear(); | ||
|
||
mScene = new QGraphicsScene; | ||
|
||
QTemporaryFile f; | ||
f.open(); | ||
f.close(); | ||
|
||
QString filename( f.fileName() ); | ||
mCanvas->saveAsImage( filename ); | ||
|
||
QPixmap pixmap; | ||
pixmap.load( filename ); | ||
|
||
int tileWidth = pixmap.width() / mSize; | ||
int tileHeight = pixmap.height() / mSize; | ||
mTileWidth = tileWidth; | ||
mTileHeight = tileHeight; | ||
|
||
for ( int row = 0; row < mSize; ++row ) | ||
for ( int col = 0; col < mSize; ++col ) | ||
{ | ||
QGraphicsPixmapItem *item = new QGraphicsPixmapItem; | ||
item->setPixmap( pixmap.copy( col * tileWidth, row * tileHeight, tileWidth, tileHeight ) ); | ||
mScene->addItem( item ); // takes ownership | ||
mItems.append( item ); | ||
|
||
QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem( QString::number( row * mSize + col + 1 ), item ); | ||
QRectF textRect = textItem->boundingRect(); | ||
textItem->setPos( ( tileWidth - textRect.width() ) / 2, ( tileHeight - textRect.height() ) / 2 ); | ||
textItem->setVisible( false ); | ||
mTextItems.append( textItem ); | ||
} | ||
|
||
// extra lines to show tile split points | ||
for ( int i = 1; i < mSize; ++i ) | ||
{ | ||
QGraphicsLineItem *lineHorz = new QGraphicsLineItem( 0, i * tileHeight, tileWidth * mSize, i * tileHeight ); | ||
QGraphicsLineItem *lineVert = new QGraphicsLineItem( i * tileWidth, 0, i * tileWidth, tileHeight * mSize ); | ||
lineHorz->setZValue( 10 ); | ||
lineVert->setZValue( 10 ); | ||
mScene->addItem( lineHorz ); | ||
mScene->addItem( lineVert ); | ||
} | ||
|
||
// initialize positions | ||
for ( int i = 0; i < mSize * mSize; ++i ) | ||
mPositions << i; | ||
mPositions[mSize * mSize - 1] = -1; | ||
shuffle( mPositions, 1000 ); | ||
|
||
mItems[mSize * mSize - 1]->setVisible( false ); // hide item for the missing piece | ||
|
||
updateTilePositions(); | ||
|
||
setScene( mScene ); | ||
} | ||
|
||
void QgsPuzzleWidget::updateTilePositions() | ||
{ | ||
for ( int i = 0; i < mSize * mSize; ++i ) | ||
{ | ||
int itemIndex = mPositions[i]; | ||
if ( itemIndex == -1 ) | ||
continue; // empty tile | ||
|
||
int r = i / mSize, c = i % mSize; | ||
int x = c * mTileWidth, y = r * mTileHeight; | ||
mItems[itemIndex]->setPos( x, y ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/*************************************************************************** | ||
qgspuzzlewidget.h | ||
-------------------------------------- | ||
Date : 1st of April 2018 | ||
Copyright : (C) 2018 by Martin Dobias | ||
Email : wonder dot sk at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSPUZZLEWIDGET_H | ||
#define QGSPUZZLEWIDGET_H | ||
|
||
#include <QGraphicsView> | ||
|
||
class QgsMapCanvas; | ||
|
||
|
||
class QgsPuzzleWidget : public QGraphicsView | ||
{ | ||
Q_OBJECT | ||
public: | ||
explicit QgsPuzzleWidget( QgsMapCanvas *canvas = nullptr ); | ||
|
||
protected: | ||
void mousePressEvent( QMouseEvent *event ) override; | ||
|
||
signals: | ||
void done(); | ||
|
||
public slots: | ||
void letsGetThePartyStarted(); | ||
|
||
private: | ||
void updateTilePositions(); | ||
|
||
private: | ||
QgsMapCanvas *mCanvas = nullptr; | ||
QGraphicsScene *mScene = nullptr; | ||
int mSize = 4; //!< Number of items in one row/column | ||
int mTileWidth = 0, mTileHeight = 0; | ||
QVector<QGraphicsItem *> mItems; | ||
QVector<QGraphicsItem *> mTextItems; | ||
QVector<int> mPositions; //!< Indices of items (-1 where the piece is missing) | ||
}; | ||
|
||
#endif // QGSPUZZLEWIDGET_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters