private boolean tryMoveTileFromTo(int fromX, int fromY, int toX, int toY) {

        if (tileIsEmpty(fromX, fromY)) {
            // dont move an empty tile
            return false;
        }

        if (toX < 0 || toY < 0 || toX >= BOARD_SIZE || toY >= BOARD_SIZE) {
            // dont move an edge tile
            return false;
        }

        Tile fromTile = board.getTileAt(fromX, fromY);
        Tile toTile = board.getTileAt(toX, toY);

        if (toTile.isEmpty()) {
            board.setTileAt(toX,toY, fromTile);
            board.setTileAt(fromX,fromY, Tile.emptyTile());
            tryMoveTileFromTo(toX, toY, toX + (toX - fromX), toY + (toY - fromY));

        } else if (toTile.equals(fromTile) && ! toTile.isAlreadyMerged()) {
            Tile mergedTile = new Tile(toTile.getValue() * 2);
            mergedTile.setAlreadyMerged(true);
            board.setTileAt(toX,toY, mergedTile);
            board.setTileAt(fromX,fromY, Tile.emptyTile());

        } else {
            return false;
        }

        return true;
    }