Exemple #1
0
void Board::setSize(int x, int y)
{
	if(x == x_tiles() && y == y_tiles())
		return;

	if(field != 0)
		delete [] field;

	field = new int[ x * y ];
	_x_tiles = x;
	_y_tiles = y;
	for(int i = 0; i < x; i++)
		for(int j = 0; j < y; j++)
			setField(i, j, EMPTY);

	// set the minimum size of the scalable window
	const double MINIMUM_SCALE = 0.2;
	int w = qRound(tiles.unscaledTileWidth() * MINIMUM_SCALE) * x_tiles();
	int h = qRound(tiles.unscaledTileHeight() * MINIMUM_SCALE) * y_tiles();
	w += tiles.unscaledTileWidth();
	h += tiles.unscaledTileWidth();

	setMinimumSize(w, h);

	resizeBoard();
	newGame();
	emit changed();
}
Exemple #2
0
void Board::setField(int x, int y, int value) {
  if(x < x_tiles() && y < y_tiles())
    field[y * x_tiles() + x] = value;
  else {
    fprintf(stderr, "write access to invalid field (%d,%d)\n", x, y);
    exit(1);
  }
}
Exemple #3
0
void Board::setField(int x, int y, int value)
{
	if(x < 0 || y < 0 || x >= x_tiles() || y >= y_tiles())
	{
		kdFatal() << "Attempted write to invalid field position "
			"(" << x << ", " << y << ")" << endl;
	}

	field[y * x_tiles() + x] = value;
}
Exemple #4
0
int Board::tilesLeft() {
  int left = 0;

  for(int i = 0; i < x_tiles(); i++)
    for(int j = 0; j < x_tiles(); j++)
      if(getField(i, j) != EMPTY)
	left++;

  return left;
}
Exemple #5
0
int Board::getField(int x, int y) {
  if(x == x_tiles() || x == -1)
    return EMPTY;
  else if(y == y_tiles() || y == -1)
    return EMPTY;
  else if(x < -1 || x > x_tiles() || y < -1 || y > y_tiles()) {
    return EMPTY;
    fprintf(stderr, "read access to invalid field (%d,%d)\n", x, y);
    exit(1);
    return 0; // makes gcc happy
  } else
    return field[y * x_tiles() + x];
}
Exemple #6
0
int Board::getField(int x, int y) const
{
#ifdef DEBUGGING
	if(x < -1 || y < -1 || x > x_tiles() || y > y_tiles())
	{
		kdFatal() << "Attempted read from invalid field position "
			"(" << x << ", " << y << ")" << endl;
	}
#endif

	if(x < 0 || y < 0 || x >= x_tiles() || y >= y_tiles())
		return EMPTY;

	return field[y * x_tiles() + x];
}
Exemple #7
0
bool Board::getHint_I(int &x1, int &y1, int &x2, int &y2, History h[4]) {
  short done[45];
  for( short index = 0; index < 45; index++ )
     done[index] = 0;

  // remember old history
  History old[4];
  for(int i = 0; i < 4; i++)
    old[i] = history[i];

  // initial no hint
  x1 = -1;
  x2 = -1;
  y1 = -1;
  y2 = -1;

  for(int x = 0; x < x_tiles(); x++)
    for(int y = 0; y < y_tiles(); y++)
      if(getField(x, y) != EMPTY && done[getField(x, y)] != 4) {
	int tile = getField(x, y);
	
	// for all these types of tile search path's
	for(int xx = 0; xx < x_tiles(); xx++)
	  for(int yy = 0; yy < y_tiles(); yy++)
	    if(xx != x || yy != y)
	      if(getField(xx, yy) == tile)
		if(findPath(x, y, xx, yy)) {
		  for(int i = 0; i < 4; i++)
		    h[i] = history[i];

		  x1 = x;
		  x2 = xx;
		  y1 = y;
		  y2 = yy;
		  for(int i = 0; i < 4; i++)
		    history[i] = old[i];
		  return TRUE;
		}
	
	clearHistory();
	done[tile]++;
      }

  for(int i = 0; i < 4; i++)
    history[i] = old[i];

  return FALSE;
}
Exemple #8
0
void Board::setSize(int x, int y) {
  if(x == x_tiles() && y == y_tiles())
    return;

  if(field != 0)
    free(field);

  field = (int*)malloc(sizeof(int) * x * y);
  _x_tiles = x;
  _y_tiles = y;
  for(int i = 0; i < x; i++)
    for(int j = 0; j < y; j++)
      setField(i, j, EMPTY);

  loadTiles();
  double scaler = 1.0;
  while(sizeHint().width() > kapp->desktop()->width() - 2*XBORDER ||
     sizeHint().height() > kapp->desktop()->height() - 2*YBORDER) {
    scaler -= 0.2;
    loadTiles(scaler);
  }

  newGame();
  emit changed();
  emit sizeChange();
}
Exemple #9
0
bool Board::findPath(int x1, int y1, int x2, int y2, Path& p) const
{
	p.clear();

	if(findSimplePath(x1, y1, x2, y2, p))
		return true;

	// Find a path of 3 segments
	const int dx[4] = { 1, 0, -1, 0 };
	const int dy[4] = { 0, 1, 0, -1 };

	for(int i = 0; i < 4; i++)
	{
		int newx = x1 + dx[i];
		int newy = y1 + dy[i];
		while(newx >= -1 && newx <= x_tiles() &&
			newy >= -1 && newy <= y_tiles() &&
			getField(newx, newy) == EMPTY)
		{
			if(findSimplePath(newx, newy, x2, y2, p))
			{
				p.push_front(Position(x1, y1));
				return true;
			}
			newx += dx[i];
			newy += dy[i];
		}
	}

	return false;
}
Exemple #10
0
void Board::mousePressEvent(QMouseEvent *e) {
    // calculate position
    int pos_x = (e->pos().x() - XBORDER <0)?-1:
                              (e->pos().x() - XBORDER) / pm_tile[0]->width();
    int pos_y = (e->pos().y() - YBORDER <0)?-1:
                              (e->pos().y() - YBORDER) / pm_tile[0]->height();

    // Mark tile
    if(e->button() == LeftButton) {
      if(highlighted_tile != -1) {
	int oldmarkx = mark_x;
	int oldmarky = mark_y;
	
	mark_x=-1; mark_y=-1;
	for(int i = 0; i < x_tiles(); i++)
	  for(int j = 0; j < y_tiles(); j++){
	    if( highlighted_tile == getField(i, j))
	      updateField(i, j);	      
	  }
	mark_x = oldmarkx; 
	mark_y = oldmarky;   // no tile selected
	highlighted_tile = -1;
      }
      
      if(pos_x >= 0 && pos_x < x_tiles() && pos_y >= 0 && pos_y < y_tiles())
	emit fieldClicked(pos_x, pos_y);  
    }

    // Assist by lighting all tiles of same type
    if(e->button() == RightButton) {
      int field = getField(pos_x,pos_y);
      highlighted_tile = field;
      
      for(int i = 0; i < x_tiles(); i++)
	for(int j = 0; j < y_tiles(); j++){
	  if( field == getField(i, j)){
	    mark_x=i; mark_y=j;
	  }
	  else{
	    mark_x=-1; mark_y=-1;
	  }
	  updateField(i, j);
	}
      mark_x=-1; mark_y=-1;   // no tile selected
    }
}
Exemple #11
0
bool Board::getHint_I(Path& p) const
{
	//dumpBoard();
	short done[TileSet::nTiles];
	for( short index = 0; index < TileSet::nTiles; index++ )
		done[index] = 0;

	for(int x = 0; x < x_tiles(); x++)
	{
		for(int y = 0; y < y_tiles(); y++)
		{
			int tile = getField(x, y);
			if(tile != EMPTY && done[tile - 1] != 4)
			{
				// for all these types of tile search path's
				for(int xx = 0; xx < x_tiles(); xx++)
				{
					for(int yy = 0; yy < y_tiles(); yy++)
					{
						if(xx != x || yy != y)
						{
							if(getField(xx, yy) == tile)
								if(findPath(x, y, xx, yy, p))
								{
									//kdDebug() << "path.size() == " << p.size() << endl;
									//for(Path::const_iterator i = p.begin(); i != p.end(); ++i)
									//	kdDebug() << "pathEntry: (" << i->x << ", " << i->y
									//		<< ") => " << getField(i->x, i->y) << endl;
									return true;
								}
						}
					}
				}
				done[tile - 1]++;
			}
		}
	}

	return false;
}
Exemple #12
0
void Board::clearHighlight()
{
	if(highlighted_tile != -1)
	{
		int old_highlight = highlighted_tile;
		highlighted_tile = -1;

		for(int i = 0; i < x_tiles(); i++)
			for(int j = 0; j < y_tiles(); j++)
				if(old_highlight == getField(i, j))
					updateField(i, j, false);
	}
}
Exemple #13
0
QPoint Board::midCoord(int x, int y) const
{
	QPoint p;
	int w = tiles.tileWidth();
	int h = tiles.tileHeight();

	if(x == -1)
		p.setX(xOffset() - (w / 4));
	else if(x == x_tiles())
		p.setX(xOffset() + (w * x_tiles()) + (w / 4));
	else
		p.setX(xOffset() + (w * x) + (w / 2));

	if(y == -1)
		p.setY(yOffset() - (w / 4));
	else if(y == y_tiles())
		p.setY(yOffset() + (h * y_tiles()) + (w / 4));
	else
		p.setY(yOffset() + (h * y) + (h / 2));

	return p;
}
Exemple #14
0
QPoint Board::midCoord(int x, int y) {
  QPoint p;
  int w = pm_tile[0]->width();
  int h = pm_tile[0]->height();

  if(x == -1) 
    p.setX(XBORDER/2 - w/2);
  else if(x == x_tiles())
    p.setX(XBORDER/2 + w * x_tiles());
  else 
    p.setX(XBORDER + w * x);

  if(y == -1) 
    p.setY(YBORDER/2 - h/2);
  else if(y == y_tiles())
    p.setY(YBORDER/2 + h * y_tiles());
  else 
    p.setY(YBORDER + h * y);

  p.setX(p.x() + w/2);
  p.setY(p.y() + h/2);
  return p;
} 
Exemple #15
0
bool Board::solvable(bool norestore) {
  int x1, y1, x2, y2;
  History h[4];
  int *oldfield = 0;
 
  if(!norestore) {
    oldfield = (int *)malloc(x_tiles() * y_tiles() * sizeof(int));
    memcpy(oldfield, field, x_tiles() * y_tiles() * sizeof(int));
  }

  while(getHint_I(x1, y1, x2, y2, h)) {
    setField(x1, y1, EMPTY);
    setField(x2, y2, EMPTY);
  }
  
  int left = tilesLeft();

  if(!norestore) {
    memcpy(field, oldfield, x_tiles() * y_tiles() * sizeof(int));
    free(oldfield);  
  }

  return (bool)(left == 0);
}
Exemple #16
0
bool Board::solvable(bool norestore)
{
	int *oldfield = 0;

	if(!norestore)
	{
		oldfield = new int [x_tiles() * y_tiles()];
		memcpy(oldfield, field, x_tiles() * y_tiles() * sizeof(int));
	}

	Path p;
	while(getHint_I(p))
	{
		kdFatal(getField(p.front().x, p.front().y) != getField(p.back().x, p.back().y))
			<< "Removing unmateched tiles: (" << p.front().x << ", " << p.front().y << ") => "
			<< getField(p.front().x, p.front().y) << " (" << p.back().x << ", " << p.back().y << ") => "
            << getField(p.back().x, p.back().y) << endl;
		setField(p.front().x, p.front().y, EMPTY);
		setField(p.back().x, p.back().y, EMPTY);
		//if(gravityFlag())
		//{
		//	gravity(p.front().x, false);
		//	gravity(p.back().x, false);
		//}
	}

	int left = tilesLeft();

	if(!norestore)
	{
		memcpy(field, oldfield, x_tiles() * y_tiles() * sizeof(int));
		delete [] oldfield;
	}

	return (bool)(left == 0);
}
Exemple #17
0
void Board::dumpBoard() const
{
	kdDebug() << "Board contents:" << endl;
	for(int y = 0; y < y_tiles(); ++y)
	{
		QString row;
		for(int x = 0; x < x_tiles(); ++x)
		{
			int tile = getField(x, y);
			if(tile == EMPTY)
				row += " --";
			else
				row += QString("%1").arg(getField(x, y), 3);
		}
		kdDebug() << row << endl;
	}
}
Exemple #18
0
void Board::paintEvent(QPaintEvent *e)
{

	QRect ur = e->rect();            // rectangle to update
	QPixmap pm(ur.size());           // Pixmap for double-buffering
	pm.fill(this, ur.topLeft());     // fill with widget background
	QPainter p(&pm);
	p.translate(-ur.x(), -ur.y());   // use widget coordinate system

	if(paused)
	{
		p.setFont(KGlobalSettings::largeFont());
		p.drawText(rect(), Qt::AlignCenter, i18n("Game Paused"));
	}
	else
	{
		int w = tiles.tileWidth();
		int h = tiles.tileHeight();
		for(int i = 0; i < x_tiles(); i++)
		{
			for(int j = 0; j < y_tiles(); j++)
			{
				int tile = getField(i, j);
				if(tile == EMPTY)
					continue;

				int xpos = xOffset() + i * w;
				int ypos = yOffset() + j * h;
				QRect r(xpos, ypos, w, h);
				if(e->rect().intersects(r))
				{
					if(isTileHighlighted(i, j))
						p.drawPixmap(xpos, ypos, tiles.highlightedTile(tile-1));
					else
						p.drawPixmap(xpos, ypos, tiles.tile(tile-1));
				}
			}
		}
	}
	p.end();
	bitBlt( this, ur.topLeft(), &pm );
}
Exemple #19
0
bool Board::findPath(int x1, int y1, int x2, int y2) {
 clearHistory();

  if(findSimplePath(x1, y1, x2, y2))
     return TRUE;
  else {
    // find 3-way path
    int dx[4] = {1, 0, -1, 0};
    int dy[4] = {0, 1, 0, -1};
    int i;

    for(i = 0; i < 4; i++) {
      int newx = x1 + dx[i], newy = y1 + dy[i];
      while(getField(newx, newy) == EMPTY && 
	    newx >= -1 && newx <= x_tiles() &&
	    newy >= -1 && newy <= y_tiles()) {
	if(findSimplePath(newx, newy, x2, y2)) {
	  // make place for history point
	  for(int j = 3; j > 0; j--)
	    history[j] = history[j-1];

	  // insert history point
	  history[0].x = x1;
	  history[0].y = y1;
	  return TRUE;	 
	}

	newx += dx[i];
	newy += dy[i];
      }
    }

    clearHistory();
    return FALSE;
  }

  return FALSE;
}
Exemple #20
0
void Board::paintEvent(QPaintEvent *e) {
  QPainter p;
  p.begin(this);
  for(int i = 0; i < x_tiles(); i++)
    for(int j = 0; j < y_tiles(); j++) {
      if(getField(i, j) == EMPTY)
	continue;

      int xpos = XBORDER + i * pm_tile[1]->width();
      int ypos = YBORDER + j * pm_tile[1]->height();
      QRect r(xpos, ypos, pm_tile[1]->width(), pm_tile[1]->height());
      if(e->rect().intersects(r)) {
	// check if it is a marked piece
	if(i == mark_x && j == mark_y) {
	    QPixmap *lpm = lighten(pm_tile[getField(i, j)-1]);
	    p.drawPixmap(xpos, ypos, *lpm);
	    delete lpm;
	} else
	  p.drawPixmap(xpos, ypos, *pm_tile[getField(i, j)-1]);
      }
    }
  p.end();
}
Exemple #21
0
QSize Board::sizeHint() {
  return QSize(x_tiles() * pm_tile[0]->width() + 2 * XBORDER,
	       y_tiles() * pm_tile[0]->height() + 2 * YBORDER);
}
Exemple #22
0
	int tile_w(void) const
	noexcept
	{
		return (width()/x_tiles())+((tile_i()+1 == x_tiles())?1:0);
	}
Exemple #23
0
	int tile_x(void) const
	noexcept
	{
		return tile_i()*(width()/x_tiles());
	}
Exemple #24
0
	bool multiple_tiles(void) const
	noexcept
	{
		return x_tiles() > 1 || y_tiles() > 1;
	}
Exemple #25
0
void Board::newGame()
{
	//kdDebug() << "NewGame" << endl;
	int i, x, y, k;

	mark_x = -1;
	mark_y = -1;
	highlighted_tile = -1; // will clear previous highlight

	_undo.clear();
	_redo.clear();
	connection.clear();

	// distribute all tiles on board
	int cur_tile = 1;
	for(y = 0; y < y_tiles(); y += 4)
	{
		for(x = 0; x < x_tiles(); ++x)
		{
			for(k = 0; k < 4 && y + k < y_tiles(); k++)
				setField(x, y + k, cur_tile);

			cur_tile++;
			if(cur_tile > TileSet::nTiles)
				cur_tile = 1;
		}
	}

	if(getShuffle() == 0)
	{
		update();
		starttime = time((time_t *)0);
		emit changed();
		return;
	}

	// shuffle the field
	int tx = x_tiles();
	int ty = y_tiles();
	for(i = 0; i < x_tiles() * y_tiles() * getShuffle(); i++)
	{
		int x1 = random.getLong(tx);
		int y1 = random.getLong(ty);
		int x2 = random.getLong(tx);
		int y2 = random.getLong(ty);
		int t  = getField(x1, y1);
		setField(x1, y1, getField(x2, y2));
		setField(x2, y2, t);
	}

	// do not make solvable if _solvable_flag is false
	if(!_solvable_flag)
	{
		update();
		starttime = time((time_t *)0);
		emit changed();
		return;
	}


	int fsize = x_tiles() * y_tiles() * sizeof(int);
	int *oldfield = new int[x_tiles() * y_tiles()];
	memcpy(oldfield, field, fsize);			// save field
	int *tiles = new int[x_tiles() * y_tiles()];
	int *pos = new int[x_tiles() * y_tiles()];

	while(!solvable(true))
	{
		//kdDebug() << "Not solvable" << endl;
		//dumpBoard();

		// generate a list of free tiles and positions
		int num_tiles = 0;
		for(i = 0; i < x_tiles() * y_tiles(); i++)
			if(field[i] != EMPTY)
			{
				pos[num_tiles] = i;
				tiles[num_tiles] = field[i];
				num_tiles++;
			}

		// restore field
		memcpy(field, oldfield, fsize);

		// redistribute unsolved tiles
		while(num_tiles > 0)
		{
			// get a random tile
			int r1 = random.getLong(num_tiles);
			int r2 = random.getLong(num_tiles);
			int tile = tiles[r1];
			int apos = pos[r2];

			// truncate list
			tiles[r1] = tiles[num_tiles-1];
			pos[r2] = pos[num_tiles-1];
			num_tiles--;

			// put this tile on the new position
			field[apos] = tile;
		}

		// remember field
		memcpy(oldfield, field, fsize);
	}


	// restore field
	memcpy(field, oldfield, fsize);
	delete tiles;
	delete pos;
	delete oldfield;

	update();
	starttime = time((time_t *)0);
	emit changed();
}
Exemple #26
0
QSize Board::unscaledSize() const
{
	int w = tiles.unscaledTileWidth() * x_tiles() + tiles.unscaledTileWidth();
	int h = tiles.unscaledTileHeight() * y_tiles() + tiles.unscaledTileWidth();
	return QSize(w, h);
}
Exemple #27
0
void Board::resizeBoard()
{
	// calculate tile size required to fit all tiles in the window
	int w = static_cast<int>( static_cast<double>(width() - tiles.unscaledTileWidth()) / x_tiles() );
	int h = static_cast<int>( static_cast<double>(height() - tiles.unscaledTileWidth()) / y_tiles() );

	const double MAXIMUM_SCALE = 2.0;
	w = std::min(w, static_cast<int>((tiles.unscaledTileWidth() * MAXIMUM_SCALE) + 0.5));
	h = std::min(h, static_cast<int>((tiles.unscaledTileHeight() * MAXIMUM_SCALE) + 0.5));

	tiles.resizeTiles(w, h);
}
Exemple #28
0
// The board is centred inside the main playing area. xOffset/yOffset provide
// the coordinates of the top-left corner of the board.
int Board::xOffset() const
{
	return (width() - (tiles.tileWidth() * x_tiles())) / 2;
}
Exemple #29
0
void Board::mousePressEvent(QMouseEvent *e)
{
	// Calculate field position
	int pos_x = (e->pos().x() - xOffset()) / tiles.tileWidth();
	int pos_y = (e->pos().y() - yOffset()) / tiles.tileHeight();

	if(e->pos().x() < xOffset() || e->pos().y() < yOffset() ||
		pos_x >= x_tiles() || pos_y >= y_tiles())
	{
		pos_x = -1;
		pos_y = -1;
	}

	// Mark tile
	if(e->button() == LeftButton)
	{
		clearHighlight();

		if(pos_x != -1)
			marked(pos_x, pos_y);
	}

	// Assist by highlighting all tiles of same type
	if(e->button() == RightButton)
	{
		int clicked_tile = getField(pos_x, pos_y);

		// Clear marked tile
		if(mark_x != -1 && getField(mark_x, mark_y) != clicked_tile)
		{
			// We need to set mark_x and mark_y to -1 before calling
			// updateField() to ensure the tile is redrawn as unmarked.
			int oldmarkx = mark_x;
			int oldmarky = mark_y;
			mark_x = -1;
			mark_y = -1;
			updateField(oldmarkx, oldmarky, false);
		}
		else
		{
			mark_x = -1;
			mark_y = -1;
		}

		// Perform highlighting
		if(clicked_tile != highlighted_tile)
		{
			int old_highlighted = highlighted_tile;
			highlighted_tile = clicked_tile;
			for(int i = 0; i < x_tiles(); i++)
			{
				for(int j = 0; j < y_tiles(); j++)
				{
					const int field_tile = getField(i, j);
					if(field_tile != EMPTY)
					{
						if(field_tile == old_highlighted)
							updateField(i, j, false);
						else if(field_tile == clicked_tile)
							updateField(i, j, false);
					}
				}
			}
		}
	}
}
Exemple #30
0
void Board::newGame() {
  int i, j, x, y, k;

  mark_x = -1;
  mark_y = -1;

  while(_undo.count())
    _undo.removeFirst();
  while(_redo.count())
    _redo.removeFirst();

  clearHistory();

  for(i = 0; i < x_tiles(); i++)
    for(j = 0; j < y_tiles(); j++)
      setField(i, j, EMPTY);

  // distribute all tiles on board
  int cur_tile = 0;
  for(i = 0; i < x_tiles() * y_tiles() * 12; i++) {
    // map the tileindex to a tile
    // not all tiles from the pixmap are really used, only
    // 36 out of 45 are used. This maps and index to
    // the "real" index.
    int tile;
    if(cur_tile == 28)
      tile = 30;
    else if(cur_tile >= 29 && cur_tile <= 35)
      tile = cur_tile + 7;
    else
      tile = cur_tile;
    
    cur_tile++;
    if(cur_tile == 36)
      cur_tile = 0;

    x = i % x_tiles();
    y = i / x_tiles() * 4;

    tile++;
    for(k = 0; k < 4 && k + y < y_tiles(); k++)
      setField(x, y+k, tile);
  }

  if(getShuffle() == 0) {
    if(!trying) {
      update();
      starttime = time((time_t *)0);
      emit changed();
    }    
    return;
  }

  // shuffle the field
  int tx = x_tiles();
  int ty = y_tiles();
  for(i = 0; i < x_tiles() * y_tiles() * getShuffle(); i++) {
    int x1 = random(tx);
    int y1 = random(ty);
    int x2 = random(tx);
    int y2 = random(ty);
    int t  = getField(x1, y1);
    setField(x1, y1, getField(x2, y2));
    setField(x2, y2, t);
  }

  // do not make solvable if _solvable_flag is FALSE
  if(!_solvable_flag) {
    if(!trying) {
      update();
      starttime = time((time_t *)0);
      emit changed();
    }    
    return;
  }

  
  int fsize = x_tiles() * y_tiles() * sizeof(int);
  int *oldfield = new int[x_tiles() * y_tiles()];
  memcpy(oldfield, field, fsize);			// save field
  int *tiles = new int[x_tiles() * y_tiles()];
  int *pos = new int[x_tiles() * y_tiles()];

  while(!solvable(TRUE)) {
    // generate a list of free tiles and positions
    int num_tiles = 0;
    for(i = 0; i < x_tiles() * y_tiles(); i++)
      if(field[i] != EMPTY) {
	pos[num_tiles] = i;
	tiles[num_tiles] = field[i];
	num_tiles++;
      }

    // restore field
    memcpy(field, oldfield, fsize);
    
    // redistribute unsolved tiles
    while(num_tiles > 0) {
      // get a random tile
      int r1 = random(num_tiles);
      int r2 = random(num_tiles);
      int tile = tiles[r1];
      int apos = pos[r2];
      
      // truncate list
      tiles[r1] = tiles[num_tiles-1];
      pos[r2] = pos[num_tiles-1];
      num_tiles--;

      // put this tile on the new position
      field[apos] = tile;
    }

    // remember field
    memcpy(oldfield, field, fsize);
  }


  // restore field
  memcpy(field, oldfield, fsize);  
  delete tiles;
  delete pos;
  delete oldfield;

  if(!trying) {
    update();
    starttime = time((time_t *)0);
    emit changed();
  }
}