нужно будет рассказать про этот код прямо чтобы было понятно как он работает чтобы каждый метод был описан как он работает особое внимание для тех методов где идет описание для непосредственно самого процесса игры
package com.example.memorymaster;

import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.TextView;
import android.app.AlertDialog;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;

import nl.dionsegijn.konfetti.KonfettiView;
import nl.dionsegijn.konfetti.models.Shape;
import nl.dionsegijn.konfetti.models.Size;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import android.util.Log; // Добавьте импорт для логирования

public class MemoryGame extends AppCompatActivity {

    private GridLayout gridLayout;
    private ArrayList<Button> squares;
    private TextView title;
    private TextView level;
    private TextView scoreText;
    private Button startButton;
    private Button nextLevelButton;
    private ArrayList<Button> correctSeq;
    private int currentLevel;
    private int currentScore;
    private int userIndex;
    private int tileCount;
    private String difficulty;
    private Handler handler;
    private SharedPreferences preferences;
    private String playerUserId; // Используем userId вместо nickname
    private int attemptsLeft = 3;
    private int currentTilePoints = 50;
    private SoundManager soundManager;

    private TextView timerTextView;
    private Handler timerHandler = new Handler();
    private Runnable timerRunnable;
    private long startTime;
    private long endTime;

    private final int COLOR_BACKGROUND = Color.parseColor("#D3D3D3"); // Светло-серый фон
    private final int COLOR_BUTTON_NORMAL = Color.parseColor("#800080"); // Фиолетовый
    private final int COLOR_BUTTON_FLASH = Color.parseColor("#008000"); // Зеленый
    private final int COLOR_BUTTON_CORRECT = Color.parseColor("#0000FF"); // Синий
    private final int COLOR_BUTTON_WRONG = Color.parseColor("#F44336"); // Красный
    private final int COLOR_TEXT = Color.parseColor("#FFA500"); // Светло-оранжевый
    private final int COLOR_TILE_NORMAL = Color.parseColor("#FFFFFF"); // Белый
    private boolean gameStarted = false;
    private KonfettiView konfettiView;

    private FirebaseHelper firebaseHelper;

    private static final String TAG = "MemoryGame";

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

        soundManager = SoundManager.getInstance(this);
        gridLayout = findViewById(R.id.gridLayout);

        // Инициализация SharedPreferences
        preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        // Получаем userId из SharedPreferences или напрямую из FirebaseAuth
        FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
        if (currentUser != null) {
            playerUserId = currentUser.getUid();
        } else {
            Intent intent = new Intent(MemoryGame.this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        tileCount = getIntent().getIntExtra("tileCount", 9);
        difficulty = getDifficultyLabel(tileCount);

        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);
        timerTextView = findViewById(R.id.timerTextView);


        nextLevelButton.setVisibility(View.GONE);

        correctSeq = new ArrayList<>();
        currentLevel = 1;
        currentScore = 0;
        handler = new Handler();

        firebaseHelper = new FirebaseHelper();

        setupUI();
        setupGameGrid();
        updateUI();

        timerRunnable = new Runnable() {
            @Override
            public void run() {
                long millis = System.currentTimeMillis() - startTime;
                int seconds = (int) (millis / 1000);
                int minutes = seconds / 60;
                seconds = seconds % 60;

                timerTextView.setText(String.format("%d:%02d", minutes, seconds));
                timerHandler.postDelayed(this, 500);
            }
        };

        // Установите слушатели с воспроизведением звука
        startButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            startGame();
        });
        nextLevelButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            startGame();
        });
    }

    private void setupUI() {
        title.setTextColor(COLOR_TEXT);
        level.setTextColor(COLOR_TEXT);
        scoreText.setTextColor(COLOR_TEXT);

        startButton.setBackgroundColor(COLOR_BUTTON_NORMAL);
        startButton.setTextColor(COLOR_TEXT);

        nextLevelButton.setBackgroundColor(COLOR_BUTTON_NORMAL);
        nextLevelButton.setTextColor(COLOR_TEXT);
    }

    private String getDifficultyLabel(int tileCount) {
        switch (tileCount) {
            case 4:
                return "easy";
            case 9:
                return "medium";
            case 12:
                return "hard";
            default:
                return "medium";
        }
    }

    private void setupGameGrid() {
        squares = new ArrayList<>();
        gridLayout.removeAllViews();

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

        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int screenHeight = getResources().getDisplayMetrics().heightPixels;

        int availableWidth = screenWidth - 40;
        int availableHeight = screenHeight - 300;

        int tileSize = Math.min(availableWidth / columnCount, availableHeight / columnCount) - 10;

        for (int i = 0; i < tileCount; i++) {
            Button button = new Button(this);
            button.setId(View.generateViewId());

            GridLayout.LayoutParams params = new GridLayout.LayoutParams();
            params.width = tileSize;
            params.height = tileSize;
            params.setMargins(5, 5, 5, 5);
            button.setLayoutParams(params);

            button.setBackgroundColor(COLOR_TILE_NORMAL);
            button.setTextColor(COLOR_TEXT);
            button.setTextSize(20);

            button.setOnClickListener(this::checkSequence);
            squares.add(button);
            gridLayout.addView(button);
        }
    }

    private void resetTileColors() {
        for (Button button : squares) {
            button.setBackgroundColor(COLOR_TILE_NORMAL);
            button.setText("");
        }
    }

    private void startGame() {
        gameStarted = true;
        isCheckingSequence = false;
        if (currentLevel == 1) {
            startTime = System.currentTimeMillis();
        }
        timerHandler.postDelayed(timerRunnable, 0);
        nextLevelButton.setVisibility(View.GONE);

        int maxLevel = 4;
        if (currentLevel > maxLevel) {
            showVictoryMessage();
            return;
        }

        correctSeq.clear();
        userIndex = 0;
        currentTilePoints = 50;
        title.setText("Запоминай последовательность!");
        level.setText("Уровень " + currentLevel + " | Попыток: " + attemptsLeft);
        disableSquares();
        startButton.setVisibility(View.INVISIBLE);

        resetTileColors();
        showPattern();
    }

    private void showPattern() {
        disableSquares();
        int delay = preferences.getInt("sequence_speed", 700); // Теперь preferences гарантированно инициализирован

        Set<String> unlockedDifficulties = new HashSet<>(preferences.getStringSet("unlocked_difficulties", new HashSet<>(Collections.singletonList("easy"))));
        for (int i = 0; i < currentLevel; i++) {
            int finalI = i;
            handler.postDelayed(() -> {
                Random random = new Random();
                int randomIndex = random.nextInt(squares.size());
                Button randomSq = squares.get(randomIndex);
                flashButton(randomSq, false);
                correctSeq.add(randomSq);

                if (finalI == currentLevel - 1) {
                    handler.postDelayed(this::playerTurn, 700);
                }
            }, delay);
            delay += preferences.getInt("sequence_speed", 700);
        }
    }

    private void flashButton(Button button, boolean isPlayerTurn) {
        int color = isPlayerTurn ? COLOR_BUTTON_CORRECT : COLOR_BUTTON_FLASH;
        animateButton(button, color, "");
        soundManager.playButtonClickSound();
    }

    private void playerTurn() {
        enableSquares();
        title.setText("Повтори последовательность");
    }

    private boolean isCheckingSequence = false;
    private void checkSequence(View view) {
        if (!gameStarted || isCheckingSequence) {
            return;
        }

        soundManager.playButtonClickSound();
        isCheckingSequence = true;
        Button clickedButton = (Button) view;

        if (clickedButton == correctSeq.get(userIndex)) {
            soundManager.playCorrectSound();
            animateButton(clickedButton, COLOR_BUTTON_CORRECT, "✔");

            userIndex++;
            level.setText(userIndex + "/" + currentLevel);

            currentScore += currentTilePoints;
            currentTilePoints += 25;

            updateUI();

            if (userIndex == currentLevel) {
                currentLevel++;
                soundManager.playLevelUpSound();
                handler.postDelayed(this::startNextLevel, 1000);
            } else {
                handler.postDelayed(() -> {
                    isCheckingSequence = false;
                    enableSquares();
                }, 500);
            }
        } else {
            soundManager.playWrongSound();
            animateButton(clickedButton, COLOR_BUTTON_WRONG, "✖");

            int penaltyPoints = 50; // Штрафные очки за ошибку
            currentScore = Math.max(0, currentScore - penaltyPoints); // Уменьшаем очки, но не ниже нуля
            updateUI();

            attemptsLeft--;
            if (attemptsLeft > 0) {
                handler.postDelayed(this::resetLevel, 1000);
            } else {
                handler.postDelayed(this::gameOver, 1000);
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();

        // Если пользователь не вошёл, переходим к экрану входа
        if (currentUser == null) {
            Intent intent = new Intent(MemoryGame.this, LoginActivity.class);
            startActivity(intent);
            finish();  // Закрываем MemoryGame, чтобы предотвратить возврат
        } else {
            // Дополнительная логика, если необходимо
            Log.d(TAG, "Пользователь вошёл: " + currentUser.getUid());
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (soundManager != null) {
            soundManager.pauseBackgroundMusic();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (soundManager != null) {
            soundManager.release();
        }
    }

    private void startNextLevel() {
        title.setText("Уровень пройден! Готовы к следующему?");
        nextLevelButton.setVisibility(View.VISIBLE);
        disableSquares();
        isCheckingSequence = false;
    }

    private void resetLevel() {
        title.setText("Новая последовательность! Попыток: " + attemptsLeft);
        disableSquares();
        isCheckingSequence = false;
        handler.postDelayed(this::startGame, 1000);
    }

    private void gameOver() {
        gameStarted = false;
        isCheckingSequence = false;
        timerHandler.removeCallbacks(timerRunnable);
        title.setText("Игра окончена!");

        endTime = System.currentTimeMillis();
        long totalTime = (endTime - startTime) / 1000;

        disableSquares();
        startButton.setVisibility(View.VISIBLE);

        showDefeatDialog();
    }

    private void showDefeatDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialogCustom);
        builder.setTitle("Игра окончена!")
                .setMessage("Вы исчерпали все попытки. Хотите попробовать снова или вернуться в главное меню?")
                .setPositiveButton("Попробовать снова", (dialog, which) -> {
                    currentLevel = 1;
                    currentScore = 0;
                    currentTilePoints = 50;
                    attemptsLeft = 3;
                    startGame();
                })
                .setNegativeButton("Главное меню", (dialog, which) -> {
                    Intent intent = new Intent(MemoryGame.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                })
                .setCancelable(false)
                .show();
    }

    private void showVictoryMessage() {
        endTime = System.currentTimeMillis();
        long totalTime = (endTime - startTime) / 1000;

        // Разблокировка следующей сложности
        unlockNextDifficulty();

        // Логирование перед обновлением статистики
        Log.d(TAG, "Обновление статистики игры: userId=" + playerUserId + ", difficulty=" + difficulty + ", score=" + currentScore + ", time=" + totalTime);

        firebaseHelper.updateMemoryGameStats(playerUserId, difficulty, currentScore, totalTime, new FirebaseHelper.UpdateStatsCallback() {
            @Override
            public void onUpdateCompleted(boolean isNewRecord) {
                if (isNewRecord) {
                    soundManager.playNewRecordSound();
                    showConfetti();
                } else {
                    soundManager.playVictorySound();
                }

                AlertDialog.Builder builder = new AlertDialog.Builder(MemoryGame.this, R.style.AlertDialogCustom);
                String message = isNewRecord ?
                        "Поздравляем! Вы установили новый рекорд!\n" :
                        "Вы успешно прошли игру!\n";

                builder.setTitle("Поздравляем!")
                        .setMessage(message)
                        .setPositiveButton("Назад в главное меню", (dialog, which) -> {
                            Intent intent = new Intent(MemoryGame.this, MainActivity.class);
                            startActivity(intent);
                            finish();
                        })
                        .setNegativeButton("Выбрать сложность", (dialog, which) -> {
                            Intent intent = new Intent(MemoryGame.this, DifficultySelectionActivity.class);
                            startActivity(intent);
                            finish();
                        })
                        .setCancelable(false)
                        .show();
            }

            @Override
            public void onUpdateFailed(Exception e) {
                Toast.makeText(MemoryGame.this, "Ошибка обновления статистики: " + e.getMessage(), Toast.LENGTH_LONG).show();
                Log.e(TAG, "Ошибка обновления статистики", e);
            }
        });
    }

    private void unlockNextDifficulty() {
        SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        Set<String> unlockedDifficulties = new HashSet<>(preferences.getStringSet("unlocked_difficulties", new HashSet<>(Collections.singletonList("easy"))));
        boolean updated = false;

        if ("easy".equals(difficulty) && !unlockedDifficulties.contains("medium")) {
            unlockedDifficulties.add("medium");
            updated = true;
        } else if ("medium".equals(difficulty) && !unlockedDifficulties.contains("hard")) {
            unlockedDifficulties.add("hard");
            updated = true;
        }

        if (updated) {
            SharedPreferences.Editor editor = preferences.edit();
            editor.putStringSet("unlocked_difficulties", unlockedDifficulties);
            editor.apply();
            Log.d(TAG, "Новая сложность разблокирована: " + difficulty + " -> " + unlockedDifficulties.toString());
        }
    }

    private void updateUI() {
        scoreText.setText("Очки: " + currentScore);
        level.setText("Уровень: " + currentLevel + " | Попыток: " + attemptsLeft);
    }

    private void enableSquares() {
        for (Button square : squares) {
            square.setClickable(true);
        }
    }

    private void disableSquares() {
        for (Button square : squares) {
            square.setClickable(false);
        }
    }

    private void animateButton(final Button button, int color, String text) {
        button.setBackgroundColor(color);
        button.setText(text);

        PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1f, 1.2f, 1f);
        PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f, 1.2f, 1f);
        ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(button, scaleX, scaleY);
        scaleAnimator.setDuration(300);
        scaleAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

        scaleAnimator.start();

        handler.postDelayed(() -> {
            button.setBackgroundColor(COLOR_TILE_NORMAL);
            button.setText("");
        }, 500);
    }

    private void showConfetti() {
        konfettiView.build()
                .addColors(Color.YELLOW, Color.GREEN, Color.MAGENTA)
                .setDirection(0.0, 359.0)
                .setSpeed(1f, 5f)
                .setFadeOutEnabled(true)
                .setTimeToLive(2000L)
                .addShapes(Shape.Square.INSTANCE, Shape.Circle.INSTANCE)
                .addSizes(new Size(12, 5f))
                .setPosition(-50f, konfettiView.getWidth() + 50f, -50f, -50f)
                .streamFor(300, 5000L);
    }
}