MemoryGame.java:
public class MemoryGame extends AppCompatActivity {

    private GridLayout gridLayout;
    private ArrayList<Button> squares; // Кнопки для плиток игры
    private TextView title, level, scoreText;
    private Button startButton, nextLevelButton;
    private ArrayList<Button> correctSeq; // Правильная последовательность плиток
    private int currentLevel; // Текущий уровень игры
    private int currentScore; // Текущий счет игрока
    private int userIndex; // Индекс текущего хода игрока
    private int tileCount; // Количество плиток в зависимости от сложности
    private String difficulty; // Сложность игры (легкая, средняя, сложная)
    private int attemptsLeft = 3; // Количество оставшихся попыток
    private int currentTilePoints = 50; // Очки за плитку
    private SoundManager soundManager; // Управление звуком в игре

    private Handler handler;
    private SharedPreferences preferences;
    private String playerUserId; // Идентификатор пользователя из Firebase

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memory_game);

        // Инициализация компонентов игры
        soundManager = SoundManager.getInstance(this);
        gridLayout = findViewById(R.id.gridLayout);
        title = findViewById(R.id.title);
        level = findViewById(R.id.level);
        scoreText = findViewById(R.id.score);
        startButton = findViewById(R.id.startBtn);
        nextLevelButton = findViewById(R.id.nextLevelBtn);

        // Получаем настройки игры и идентификатор пользователя
        preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
        if (currentUser != null) {
            playerUserId = currentUser.getUid();
        } else {
            // Если пользователь не вошел в систему, перенаправляем его на экран входа
            Intent intent = new Intent(MemoryGame.this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        // Инициализация уровня, очков и количества плиток
        currentLevel = 1;
        currentScore = 0;
        tileCount = getIntent().getIntExtra("tileCount", 9); // Количество плиток зависит от сложности
        difficulty = getDifficultyLabel(tileCount); // Получаем уровень сложности

        setupUI(); // Настройка пользовательского интерфейса
        setupGameGrid(); // Инициализация сетки плиток для игры

        // Запуск игры по нажатию на кнопку "Старт"
        startButton.setOnClickListener(v -> startGame());
        nextLevelButton.setOnClickListener(v -> startGame());
        nextLevelButton.setVisibility(View.GONE); // Кнопка следующего уровня скрыта до окончания текущего
    }

    // Метод для настройки UI элементов
    private void setupUI() {
        title.setTextColor(Color.ORANGE);
        level.setTextColor(Color.ORANGE);
        scoreText.setTextColor(Color.ORANGE);

        startButton.setBackgroundColor(Color.PURPLE);
        nextLevelButton.setBackgroundColor(Color.PURPLE);
    }

    // Метод для установки сетки игры в зависимости от количества плиток
    private void setupGameGrid() {
        squares = new ArrayList<>();
        gridLayout.removeAllViews(); // Очищаем старую сетку

        int columnCount = (int) Math.sqrt(tileCount); // Определяем количество колонок в сетке
        gridLayout.setColumnCount(columnCount);

        // Рассчитываем размер плиток в зависимости от экрана
        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int availableWidth = screenWidth - 40; // Оставляем немного места для отступов

        int tileSize = availableWidth / columnCount;

        // Создаем кнопки для каждой плитки
        for (int i = 0; i < tileCount; i++) {
            Button button = new Button(this);
            GridLayout.LayoutParams params = new GridLayout.LayoutParams();
            params.width = tileSize;
            params.height = tileSize;
            params.setMargins(5, 5, 5, 5); // Устанавливаем отступы
            button.setLayoutParams(params);

            button.setBackgroundColor(Color.WHITE); // Начальный цвет плитки
            button.setOnClickListener(this::checkSequence); // Обработка нажатия на плитку

            squares.add(button); // Добавляем плитку в список
            gridLayout.addView(button); // Добавляем плитку в сетку
        }
    }

    // Метод запуска игры
    private void startGame() {
        correctSeq.clear(); // Очищаем последовательность для нового уровня
        currentScore = 0; // Сбрасываем счет
        currentLevel = 1; // Сбрасываем уровень
        userIndex = 0; // Сбрасываем индекс пользователя
        // Отображаем подсказку для пользователя
        title.setText("Запоминай последовательность!");
        nextLevelButton.setVisibility(View.GONE); // Скрываем кнопку следующего уровня
        showPattern(); // Показать правильную последовательность плиток
    }
    // Метод для показа правильной последовательности
    private void showPattern() {
        disableSquares(); // Отключаем нажатие на плитки, пока показывается последовательность

        for (int i = 0; i < currentLevel; i++) {
            int randomIndex = new Random().nextInt(squares.size());
            Button randomSq = squares.get(randomIndex);
            correctSeq.add(randomSq); // Добавляем плитку в правильную последовательность
            // "Мигаем" правильной плиткой
            flashButton(randomSq, false);
        }
    }
    // Метод для проверки, правильно ли нажата плитка
    private void checkSequence(View view) {
        Button clickedButton = (Button) view;
        if (clickedButton == correctSeq.get(userIndex)) {
            // Правильное нажатие
            userIndex++;
            currentScore += currentTilePoints; // Начисляем очки
            updateUI(); // Обновляем интерфейс

            // Если последовательность полностью угадана, переходим на следующий уровень
            if (userIndex == currentLevel) {
                currentLevel++;
                nextLevelButton.setVisibility(View.VISIBLE); // Показываем кнопку следующего уровня
            }
        } else {
            // Ошибка
            attemptsLeft--;
            if (attemptsLeft == 0) {
                gameOver(); // Если попытки закончились, игра завершена
            } else {
                resetLevel(); // Перезапускаем уровень
            }
        }
    }

    // Метод для завершения игры
    private void gameOver() {
        // Показ сообщения об окончании игры и сброс игры
        showGameOverDialog();
    }
}

PairMatchingGame.java:
public class PairMatchingGame extends AppCompatActivity {

    private GridLayout gridLayout;
    private ArrayList<Button> cardButtons; // Кнопки для карточек
    private MemoryCard[] cardValues; // Массив карточек
    private Button firstSelectedCard = null; // Первая выбранная карточка
    private boolean isFlipping = false; // Проверка на текущее действие (переворот)
    private int matchedPairs = 0; // Количество совпадений
    private int currentLevel = 1; // Текущий уровень игры
    private int totalMoves = 0; // Общее количество ходов
    private long totalTime = 0; // Время игры
    private TextView movesTextView, timerTextView; // Элементы UI для отображения ходов и времени
    private Handler timerHandler = new Handler(); // Хендлер для таймера
    private SoundManager soundManager; // Менеджер звуков
    private FirebaseHelper firebaseHelper; // Firebase для записи статистики

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pair_matching_game);

        soundManager = SoundManager.getInstance(this);

        // Инициализация сетки и UI элементов
        gridLayout = findViewById(R.id.gridLayout);
        movesTextView = findViewById(R.id.movesTextView);
        timerTextView = findViewById(R.id.timerTextView);

        setupGameForLevel(currentLevel); // Настройка игры для текущего уровня
        startTimer(); // Запуск таймера
    }

    // Метод настройки игры для текущего уровня
    private void setupGameForLevel(int level) {
        int numberOfCards = (level == 1) ? 6 : (level == 2) ? 12 : 16; // Количество карточек на каждом уровне
        cardValues = new MemoryCard[numberOfCards];

        // Генерация пар значений для карточек
        for (int i = 0; i < numberOfCards / 2; i++) {
            cardValues[i] = new MemoryCard(i + 1);
            cardValues[i + numberOfCards / 2] = new MemoryCard(i + 1);
        }

        // Настройка сетки с карточками
        setupGameGrid(numberOfCards);
        updateMovesDisplay(); // Обновление отображения количества ходов
        matchedPairs = 0; // Сброс совпадений для нового уровня
    }

    // Метод для настройки сетки карточек
    private void setupGameGrid(int numberOfCards) {
        gridLayout.removeAllViews();
        cardButtons.clear();

        int columnCount = (int) Math.sqrt(numberOfCards);
        gridLayout.setColumnCount(columnCount);

        ArrayList<MemoryCard> cardList = new ArrayList<>(Arrays.asList(cardValues));
        Collections.shuffle(cardList); // Перемешиваем карточки

        for (MemoryCard card : cardList) {
            Button button = new Button(this);
            button.setTag(card);
            button.setText("");
            button.setBackgroundResource(R.drawable.card_back);

            button.setOnClickListener(this::onCardClick); // Добавляем обработку нажатия на карточку
            cardButtons.add(button);
            gridLayout.addView(button);
        }
    }

    // Метод обработки нажатия на карточку
    private void onCardClick(View view) {
        if (isFlipping) return; // Если карточки переворачиваются, новые нажатия игнорируются
        Button selectedButton = (Button) view;
        MemoryCard selectedCard = (MemoryCard) selectedButton.getTag();

        if (!selectedButton.getText().toString().isEmpty()) {
            return; // Если карточка уже открыта, пропускаем действие
        }

        selectedButton.setText(String.valueOf(selectedCard.getValue())); // Показываем значение карточки
        selectedButton.setBackgroundResource(R.drawable.card_front);

        if (firstSelectedCard == null) {
            firstSelectedCard = selectedButton; // Первая выбранная карточка
        } else {
            totalMoves++; // Увеличиваем счетчик ходов
            MemoryCard firstCard = (MemoryCard) firstSelectedCard.getTag();

            // Проверка совпадения двух выбранных карточек
            if (firstCard.getValue() == selectedCard.getValue()) {
                // Если карточки совпали
                firstSelectedCard.setEnabled(false);
                selectedButton.setEnabled(false);
                matchedPairs++; // Увеличиваем количество совпадений

                // Проверка, пройден ли уровень
                if (matchedPairs == cardValues.length / 2) {
                    onGameWon();
                }
                firstSelectedCard = null; // Сброс первой карточки
            } else {
                // Если карточки не совпали, переворачиваем обратно через 1 секунду
                isFlipping = true;
                new Handler().postDelayed(() -> {
                    firstSelectedCard.setText("");
                    selectedButton.setText("");
                    firstSelectedCard.setBackgroundResource(R.drawable.card_back);
                    selectedButton.setBackgroundResource(R.drawable.card_back);
                    firstSelectedCard = null;
                    isFlipping = false;
                }, 1000);
            }}  }

    // Метод для обработки победы на уровне
    private void onGameWon() {
        // Остановка таймера и переход к следующему уровню или завершение игры
        timerHandler.removeCallbacks(timerRunnable);

        if (currentLevel >= 3) {
            gameCompleted();
        } else {
            currentLevel++;
            showLevelCompleteDialog(); // Показ диалога об успешном завершении уровня
        }}
    // Метод завершения всей игры
    private void gameCompleted() {
        firebaseHelper.updatePairMatchingStats(playerUserId, totalMoves, totalTime, new FirebaseHelper.UpdateStatsCallback() {
            @Override
            public void onUpdateCompleted(boolean newRecord) {
                // Если установлен новый рекорд, показываем конфетти
                if (newRecord) {
                    showConfetti();
                }
                showGameCompleteDialog(); // Показ диалога о завершении игры
            }
            @Override
            public void onUpdateFailed(Exception e) {
                // Обработка ошибок при обновлении статистики
                Toast.makeText(PairMatchingGame.this, "Ошибка обновления статистики: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });}}





ReactionGame.java:
public class ReactionGame extends Activity {

    private GridLayout gridLayout;
    private ArrayList<Button> squares; // Плитки для реакции
    private TextView title, reactionTimeText, countdownText;
    private Button startButton, retryButton;
    private Handler handler;
    private Stopwatch stopwatch; // Таймер для отслеживания времени реакции
    private int reactionTime; // Время реакции игрока
    private Button correctSquare; // Правильная плитка для нажатия
    private boolean gameStarted = false; // Статус игры
    private boolean countdownFinished = false; // Завершен ли обратный отсчет
    private SoundManager soundManager; // Звуковой менеджер
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_reaction_game);

        soundManager = SoundManager.getInstance(this);

        // Инициализация элементов UI
        gridLayout = findViewById(R.id.gridLayout);
        title = findViewById(R.id.title);
        reactionTimeText = findViewById(R.id.reactionTime);
        countdownText = findViewById(R.id.countdownText);
        startButton = findViewById(R.id.startBtn);
        retryButton = findViewById(R.id.retryBtn);

        setupGameGrid(); // Настройка сетки для плиток
        startButton.setOnClickListener(v -> startCountdown()); // Запуск игры при нажатии кнопки
        retryButton.setOnClickListener(v -> retryGame()); // Повтор игры
    }
  // Метод для настройки сетки плиток
    private void setupGameGrid() {
        squares = new ArrayList<>();
        gridLayout.removeAllViews();

        int columnCount = 3; // 3x3 сетка плиток для игры
        gridLayout.setColumnCount(columnCount);

        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int tileSize = (screenWidth - 60) / columnCount;

        for (int i = 0; i < 9; i++) {
            Button button = new Button(this);
            GridLayout.LayoutParams params = new GridLayout.LayoutParams();
            params.width = tileSize;
            params.height = tileSize;
            params.setMargins(5, 5, 5, 5);
            button.setLayoutParams(params);
            button.setBackgroundColor(Color.WHITE);
            button.setOnClickListener(this::checkReaction); // Обработка нажатия на плитку

            squares.add(button);
            gridLayout.addView(button);
        } }
    // Метод запуска обратного отсчета
    private void startCountdown() {
        countdownFinished = false;
        title.setText("Приготовьтесь...");

        handler.postDelayed(() -> {
            countdownText.setText("3");
        }, 0);

        handler.postDelayed(() -> {
            countdownText.setText("2");
        }, 1000);

        handler.postDelayed(() -> {
            countdownText.setText("1");
        }, 2000);

        handler.postDelayed(() -> {
            countdownFinished = true;
            countdownText.setText("");
            showRandomSquare(); // Показываем случайную плитку для нажатия
        }, 3000);
    }

    // Метод для показа случайной плитки
    private void showRandomSquare() {
        int randomIndex = new Random().nextInt(squares.size());
        correctSquare = squares.get(randomIndex); // Правильная плитка
        correctSquare.setBackgroundColor(Color.GREEN); // Закрашиваем плитку в зеленый цвет
        stopwatch.start(); // Запуск таймера реакции
        gameStarted = true; // Игра началась
    }

    // Метод проверки реакции пользователя на нажатие плитки
    private void checkReaction(View view) {
        if (!gameStarted || !countdownFinished) return;

        Button clickedButton = (Button) view;
        if (clickedButton == correctSquare) {
            // Если нажата правильная плитка
            stopwatch.stop();
            reactionTime = (int) stopwatch.getElapsedTimeMillis(); // Рассчитываем время реакции
            reactionTimeText.setText("Время реакции: " + reactionTime + " мс");

            soundManager.playCorrectSound(); // Проигрываем звук успеха
            correctSquare.setBackgroundColor(Color.WHITE);
            retryButton.setVisibility(View.VISIBLE); // Показ кнопки повтора
        } else {
            // Если нажата неправильная плитка
            title.setText("Ошибка!");
            soundManager.playWrongSound(); // Проигрываем звук ошибки
            retryButton.setVisibility(View.VISIBLE); // Показ кнопки повтора
        }
        gameStarted = false;
    }

    // Метод повтора игры
    private void retryGame() {
        resetGame();
        startCountdown();
    }

    // Сброс игры для повтора
    private void resetGame() {
        correctSquare.setBackgroundColor(Color.WHITE);
        gameStarted = false;
        countdownFinished = false;
        reactionTime = 0;
        reactionTimeText.setText("");
    }
}





обьясни кратко но при этом точно и понятно каждый блок то есть метод кода чтобы можно было обьяснить как он работает