package com.example.memorymaster;

import androidx.annotation.NonNull;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.*;

public class FirebaseHelper {
    private DatabaseReference databaseReference;

    public FirebaseHelper() {
        FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
        databaseReference = firebaseDatabase.getReference();
    }

    // Callback interface
    public interface UpdateStatsCallback {
        void onUpdateCompleted(boolean newRecord);
        void onUpdateFailed(Exception e);
    }

    // -------- Memory Game Stats --------
    public void updateMemoryGameStats(String userId, String difficulty, int newScore, long newTime, UpdateStatsCallback callback) {
        String path = "memory_game_statistics/" + userId + "/" + difficulty;
        DatabaseReference userStatsRef = databaseReference.child(path);

        userStatsRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                MemoryGameStats stats = snapshot.getValue(MemoryGameStats.class);
                final boolean[] newRecord = {false};
                if (stats == null) {
                    stats = new MemoryGameStats(newScore, newTime, newTime, newScore);
                    newRecord[0] = true;
                } else {
                    if (newTime < stats.getBestTime()) {
                        stats.setBestTime(newTime);
                        stats.setBestTimeScore(newScore);
                        newRecord[0] = true;
                    }
                    if (newScore > stats.getBestScore()) {
                        stats.setBestScore(newScore);
                        stats.setBestScoreTime(newTime);
                        newRecord[0] = true;
                    }
                }
                userStatsRef.setValue(stats).addOnCompleteListener(task1 -> {
                    if (task1.isSuccessful()) {
                        if (callback != null) {
                            callback.onUpdateCompleted(newRecord[0]);
                        }
                    } else {
                        if (callback != null) {
                            callback.onUpdateFailed(task1.getException());
                        }
                    }
                });
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                if (callback != null) {
                    callback.onUpdateFailed(error.toException());
                }
            }
        });
    }

    // -------- Reaction Game Stats --------
    public void updateReactionGameStats(String userId, int reactionTime, UpdateStatsCallback callback) {
        String path = "reaction_game_statistics/" + userId;
        DatabaseReference userStatsRef = databaseReference.child(path);

        userStatsRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                Integer bestReactionTime = snapshot.getValue(Integer.class);
                boolean newRecord = false;
                if (bestReactionTime == null || reactionTime < bestReactionTime) {
                    userStatsRef.setValue(reactionTime).addOnCompleteListener(task1 -> {
                        if (task1.isSuccessful()) {
                            if (callback != null) {
                                callback.onUpdateCompleted(true);
                            }
                        } else {
                            if (callback != null) {
                                callback.onUpdateFailed(task1.getException());
                            }
                        }
                    });
                } else {
                    if (callback != null) {
                        callback.onUpdateCompleted(false);
                    }
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                if (callback != null) {
                    callback.onUpdateFailed(error.toException());
                }
            }
        });
    }

    // -------- Pair Matching Game Stats --------
    public void updatePairMatchingStats(String userId, int moves, long time, UpdateStatsCallback callback) {
        String path = "pair_matching_statistics/" + userId;
        DatabaseReference userStatsRef = databaseReference.child(path);

        userStatsRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                PairMatchingStats stats = snapshot.getValue(PairMatchingStats.class);
                final boolean[] newRecord = {false};
                if (stats == null) {
                    stats = new PairMatchingStats(moves, time, moves, time);
                    newRecord[0] = true;
                } else {
                    if (moves < stats.getBestMoves()) {
                        stats.setBestMoves(moves);
                        stats.setBestTime(time);
                        newRecord[0] = true;
                    }
                    if (time < stats.getFastestTime()) {
                        stats.setFastestMoves(moves);
                        stats.setFastestTime(time);
                        newRecord[0] = true;
                    }
                }
                userStatsRef.setValue(stats).addOnCompleteListener(task1 -> {
                    if (task1.isSuccessful()) {
                        if (callback != null) {
                            callback.onUpdateCompleted(newRecord[0]);
                        }
                    } else {
                        if (callback != null) {
                            callback.onUpdateFailed(task1.getException());
                        }
                    }
                });
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                if (callback != null) {
                    callback.onUpdateFailed(error.toException());
                }
            }
        });
    }

    // MemoryGameStats model class
    public static class MemoryGameStats {
        private int bestScore;
        private long bestScoreTime;
        private long bestTime;
        private int bestTimeScore;

        // Required for Firebase
        public MemoryGameStats() {
        }

        public MemoryGameStats(int bestScore, long bestScoreTime, long bestTime, int bestTimeScore) {
            this.bestScore = bestScore;
            this.bestScoreTime = bestScoreTime;
            this.bestTime = bestTime;
            this.bestTimeScore = bestTimeScore;
        }

        public int getBestScore() {
            return bestScore;
        }

        public void setBestScore(int bestScore) {
            this.bestScore = bestScore;
        }

        public long getBestScoreTime() {
            return bestScoreTime;
        }

        public void setBestScoreTime(long bestScoreTime) {
            this.bestScoreTime = bestScoreTime;
        }

        public long getBestTime() {
            return bestTime;
        }

        public void setBestTime(long bestTime) {
            this.bestTime = bestTime;
        }

        public int getBestTimeScore() {
            return bestTimeScore;
        }

        public void setBestTimeScore(int bestTimeScore) {
            this.bestTimeScore = bestTimeScore;
        }
    }

    // PairMatchingStats model class
    public static class PairMatchingStats {
        private int bestMoves;
        private long bestTime;
        private int fastestMoves;
        private long fastestTime;

        // Required for Firebase
        public PairMatchingStats() {
        }

        public PairMatchingStats(int bestMoves, long bestTime, int fastestMoves, long fastestTime) {
            this.bestMoves = bestMoves;
            this.bestTime = bestTime;
            this.fastestMoves = fastestMoves;
            this.fastestTime = fastestTime;
        }

        public int getBestMoves() {
            return bestMoves;
        }

        public void setBestMoves(int bestMoves) {
            this.bestMoves = bestMoves;
        }

        public long getBestTime() {
            return bestTime;
        }

        public void setBestTime(long bestTime) {
            this.bestTime = bestTime;
        }

        public int getFastestMoves() {
            return fastestMoves;
        }

        public void setFastestMoves(int fastestMoves) {
            this.fastestMoves = fastestMoves;
        }

        public long getFastestTime() {
            return fastestTime;
        }

        public void setFastestTime(long fastestTime) {
            this.fastestTime = fastestTime;
        }
    }
}



package com.example.memorymaster;

import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.*;

import java.util.Collections;
import java.util.HashSet;

public class MainActivity extends AppCompatActivity {

    private SoundManager soundManager;
    private FirebaseAuth auth;
    private DatabaseReference usersRef;

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

        SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);

        if (!preferences.contains("unlocked_difficulties")) {
            // Если ключа нет, значит первый запуск, разблокируем только легкую сложность
            SharedPreferences.Editor editor = preferences.edit();
            editor.putStringSet("unlocked_difficulties", new HashSet<>(Collections.singletonList("easy")));
            editor.apply();
        }

        FirebaseApp.initializeApp(this);

        auth = FirebaseAuth.getInstance();
        usersRef = FirebaseDatabase.getInstance().getReference("users");

        soundManager = SoundManager.getInstance(this);

        ImageButton btnHelp = findViewById(R.id.button_help);
        btnHelp.setOnClickListener(v -> {
            showHelpDialog();
        });


        Button btnStartMemoryGame = findViewById(R.id.btn_memory);
        Button btnStartReactionGame = findViewById(R.id.btn_reaction);
        Button btnProfile = findViewById(R.id.btn_profile);
        Button btnStartPairMatchingGame = findViewById(R.id.btn_pair_matching);

        btnStartMemoryGame.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            Intent intent = new Intent(MainActivity.this, DifficultySelectionActivity.class);
            startActivity(intent);
        });

        btnStartReactionGame.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            Intent intent = new Intent(MainActivity.this, ReactionGameModeSelection.class);
            startActivity(intent);
        });

        btnProfile.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            Intent intent = new Intent(MainActivity.this, ProfileActivity.class);
            startActivity(intent);
        });

        btnStartPairMatchingGame.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            Intent intent = new Intent(MainActivity.this, PairMatchingGame.class);
            startActivity(intent);
        });
    }

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

        // If user is not logged in, navigate to LoginActivity
        if (currentUser == null) {
            Intent intent = new Intent(MainActivity.this, LoginActivity.class);
            startActivity(intent);
            finish();  // Close MainActivity to prevent returning to it
        } else {
            String userId = currentUser.getUid();
            usersRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                    String nickname = snapshot.child("nickname").getValue(String.class);
                    if (nickname == null) nickname = "Player";

                    SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putString("nickname", nickname);
                    editor.apply();
                }

                @Override
                public void onCancelled(@NonNull DatabaseError error) {
                    Toast.makeText(MainActivity.this, "Ошибка загрузки профиля: " + error.getMessage(), Toast.LENGTH_LONG).show();
                }
            });
        }
    }

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

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

    private void showHelpDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialogCustom);

        LayoutInflater inflater = this.getLayoutInflater();
        View dialogView = inflater.inflate(R.layout.dialog_help, null);
        builder.setView(dialogView);

        AlertDialog alertDialog = builder.create();

        Button btnClose = dialogView.findViewById(R.id.btn_close_help);
        btnClose.setOnClickListener(v -> alertDialog.dismiss());

        alertDialog.show();
    }
}



package com.example.memorymaster;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.*;

public class ProfileActivity extends AppCompatActivity {

    private TextView textViewNickname, textViewEmail;
    private TextView textViewMemoryGameStats, textViewReactionGameStats, textViewPairMatchingGameStats;
    private Button buttonLogout;

    private FirebaseAuth mAuth;
    private DatabaseReference usersRef;
    private DatabaseReference memoryGameStatsRef;
    private DatabaseReference reactionGameStatsRef;
    private DatabaseReference pairMatchingStatsRef;

    private SoundManager soundManager;

    private String userId;
    private String nickname;

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


        textViewNickname = findViewById(R.id.textViewNickname);
        textViewEmail = findViewById(R.id.textViewEmail);
        textViewMemoryGameStats = findViewById(R.id.textViewMemoryGameStats);
        textViewReactionGameStats = findViewById(R.id.textViewReactionGameStats);
        textViewPairMatchingGameStats = findViewById(R.id.textViewPairMatchingGameStats);
        buttonLogout = findViewById(R.id.buttonLogout);


        mAuth = FirebaseAuth.getInstance();
        usersRef = FirebaseDatabase.getInstance().getReference("users");
        memoryGameStatsRef = FirebaseDatabase.getInstance().getReference("memory_game_statistics");
        reactionGameStatsRef = FirebaseDatabase.getInstance().getReference("reaction_game_statistics");
        pairMatchingStatsRef = FirebaseDatabase.getInstance().getReference("pair_matching_statistics");

        soundManager = SoundManager.getInstance(this);

        loadUserProfile();

        buttonLogout.setOnClickListener(v -> logout());
    }

    private void loadUserProfile() {
        FirebaseUser currentUser = mAuth.getCurrentUser();
        if (currentUser == null) {
            // Пользователь не аутентифицирован, переходим к экрану входа
            Intent intent = new Intent(ProfileActivity.this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        userId = currentUser.getUid();

        // Загружаем основную информацию пользователя
        usersRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                nickname = snapshot.child("nickname").getValue(String.class);
                String email = snapshot.child("email").getValue(String.class);

                textViewNickname.setText("Никнейм: " + (nickname != null ? nickname : "Не установлено"));
                textViewEmail.setText("Email: " + (email != null ? email : "Не установлено"));

                // После загрузки основной информации загружаем статистику
                loadUserStatistics();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Toast.makeText(ProfileActivity.this, "Ошибка загрузки профиля: " + error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    private void loadUserStatistics() {
        // Загружаем статистику игры "Мастер памяти"
        memoryGameStatsRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                StringBuilder memoryStatsBuilder = new StringBuilder();

                for (DataSnapshot difficultySnapshot : snapshot.getChildren()) {
                    String difficulty = difficultySnapshot.getKey();
                    FirebaseHelper.MemoryGameStats stats = difficultySnapshot.getValue(FirebaseHelper.MemoryGameStats.class);

                    if (stats != null) {
                        memoryStatsBuilder.append("Сложность: ").append(difficulty).append("\n")
                                .append("Лучший счет: ").append(stats.getBestScore()).append(" (Время: ").append(stats.getBestScoreTime()).append(" сек)\n")
                                .append("Быстрейшее время: ").append(stats.getBestTime()).append(" сек").append(" (Счет: ").append(stats.getBestTimeScore()).append(")\n\n");
                    }
                }

                if (memoryStatsBuilder.length() == 0) {
                    memoryStatsBuilder.append("Нет данных");
                }

                textViewMemoryGameStats.setText("Мастер памяти:\n" + memoryStatsBuilder.toString());
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                textViewMemoryGameStats.setText("Ошибка загрузки статистики: " + error.getMessage());
            }
        });

        // Загружаем статистику игры "Игра на реакцию"
        reactionGameStatsRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                Integer bestReactionTime = snapshot.getValue(Integer.class);
                if (bestReactionTime != null) {
                    textViewReactionGameStats.setText("Игра на реакцию:\nЛучшее время реакции: " + bestReactionTime + " мс");
                } else {
                    textViewReactionGameStats.setText("Игра на реакцию:\nНет данных");
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                textViewReactionGameStats.setText("Ошибка загрузки статистики: " + error.getMessage());
            }
        });

        // Загружаем статистику игры "Найди пару плиток"
        pairMatchingStatsRef.child(userId).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                FirebaseHelper.PairMatchingStats stats = snapshot.getValue(FirebaseHelper.PairMatchingStats.class);
                if (stats != null) {
                    String statsText = "Лучшее количество ходов: " + stats.getBestMoves() + "\n" +
                            "Лучшее время: " + stats.getBestTime() + " сек\n" +
                            "Наименьшее время: " + stats.getFastestTime() + " сек\n" +
                            "Ходов за наименьшее время: " + stats.getFastestMoves();

                    textViewPairMatchingGameStats.setText("Найди пару плиток:\n" + statsText);
                } else {
                    textViewPairMatchingGameStats.setText("Найди пару плиток:\nНет данных");
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                textViewPairMatchingGameStats.setText("Ошибка загрузки статистики: " + error.getMessage());
            }
        });
    }

    private void logout() {
        mAuth.signOut();
        soundManager.playButtonClickSound();
        Intent intent = new Intent(ProfileActivity.this, LoginActivity.class);
        startActivity(intent);
        finish();
    }
}


package com.example.memorymaster;

import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.FirebaseFirestore;

public class LoginActivity extends AppCompatActivity {

    private EditText editTextEmail, editTextPassword;
    private Button buttonLogin;
    private TextView textViewRegisterLink;

    private FirebaseAuth mAuth;
    private FirebaseFirestore db;

    private SoundManager soundManager;

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

        editTextEmail = findViewById(R.id.editTextLoginEmail);
        editTextPassword = findViewById(R.id.editTextLoginPassword);
        buttonLogin = findViewById(R.id.buttonLogin);
        textViewRegisterLink = findViewById(R.id.textViewRegisterLink);

        mAuth = FirebaseAuth.getInstance();
        db = FirebaseFirestore.getInstance();

        soundManager = SoundManager.getInstance(this);

        buttonLogin.setOnClickListener(v -> loginUser());

        textViewRegisterLink.setOnClickListener(v -> {
            Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
            startActivity(intent);
            finish();
        });
    }

    private void loginUser() {
        String email = editTextEmail.getText().toString().trim();
        String password = editTextPassword.getText().toString().trim();

        // Validate inputs
        if (TextUtils.isEmpty(email)) {
            editTextEmail.setError("Введите email");
            return;
        }

        if (TextUtils.isEmpty(password)) {
            editTextPassword.setError("Введите пароль");
            return;
        }

        // Sign in with Firebase Authentication
        mAuth.signInWithEmailAndPassword(email, password)
                .addOnCompleteListener(this, task -> {
                    if (task.isSuccessful()) {
                        soundManager.playButtonClickSound();
                        // Sign-in success, navigate to MainActivity
                        Toast.makeText(LoginActivity.this, "Вход выполнен успешно!", Toast.LENGTH_SHORT).show();
                        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                        startActivity(intent);
                        finish();
                    } else {
                        soundManager.playWrongSound();
                        // If sign in fails, display a message to the user.
                        Toast.makeText(LoginActivity.this, "Ошибка входа: " + task.getException().getMessage(),
                                Toast.LENGTH_LONG).show();
                    }
                });
    }
}



package com.example.memorymaster;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.database.*;

import java.util.HashMap;
import java.util.Map;

public class RegisterActivity extends AppCompatActivity {

    private EditText editTextNickname, editTextEmail, editTextPassword;
    private Button buttonRegister;
    private TextView textViewLoginLink;

    private FirebaseAuth mAuth;
    private FirebaseDatabase db;
    private DatabaseReference usersRef;
    private DatabaseReference nicknamesRef;

    private SoundManager soundManager;

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

        editTextNickname = findViewById(R.id.editTextNickname);
        editTextEmail = findViewById(R.id.editTextEmail);
        editTextPassword = findViewById(R.id.editTextPassword);
        buttonRegister = findViewById(R.id.buttonRegister);
        textViewLoginLink = findViewById(R.id.textViewLoginLink);

        mAuth = FirebaseAuth.getInstance();
        db = FirebaseDatabase.getInstance();
        usersRef = db.getReference("users");
        nicknamesRef = db.getReference("nicknames");

        soundManager = SoundManager.getInstance(this);

        buttonRegister.setOnClickListener(v -> registerUser());

        textViewLoginLink.setOnClickListener(v -> {
            Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
            startActivity(intent);
            finish();
        });
    }

    private void registerUser() {
        String nickname = editTextNickname.getText().toString().trim();
        String email = editTextEmail.getText().toString().trim();
        String password = editTextPassword.getText().toString().trim();

        // Validate inputs
        if (TextUtils.isEmpty(nickname)) {
            editTextNickname.setError("Введите никнейм");
            return;
        }

        if (TextUtils.isEmpty(email)) {
            editTextEmail.setError("Введите email");
            return;
        }

        if (TextUtils.isEmpty(password)) {
            editTextPassword.setError("Введите пароль");
            return;
        }

        if (password.length() < 6) {
            editTextPassword.setError("Пароль должен быть не менее 6 символов");
            return;
        }

        // Check if nickname is unique
        nicknamesRef.child(nickname).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if (snapshot.exists()) {
                    editTextNickname.setError("Этот никнейм уже занят");
                    Toast.makeText(RegisterActivity.this, "Никнейм уже занят. Выберите другой.", Toast.LENGTH_LONG).show();
                } else {
                    // Proceed with registration
                    createUser(nickname, email, password);
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Toast.makeText(RegisterActivity.this, "Ошибка проверки никнейма: " + error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    private void createUser(String nickname, String email, String password) {
        mAuth.createUserWithEmailAndPassword(email, password)
                .addOnCompleteListener(this, task -> {
                    if (task.isSuccessful()) {
                        soundManager.playButtonClickSound();
                        // Registration success
                        String userId = mAuth.getCurrentUser().getUid();
                        User user = new User(nickname, email, userId);

                        // Save user data
                        usersRef.child(userId).setValue(user)
                                .addOnSuccessListener(aVoid -> {
                                    // Save nickname in nicknames node
                                    nicknamesRef.child(nickname).setValue(userId)
                                            .addOnSuccessListener(aVoid1 -> {
                                                // Optionally set display name
                                                mAuth.getCurrentUser().updateProfile(new com.google.firebase.auth.UserProfileChangeRequest.Builder()
                                                                .setDisplayName(nickname)
                                                                .build())
                                                        .addOnCompleteListener(taskUpdate -> {
                                                            if (taskUpdate.isSuccessful()) {
                                                                Toast.makeText(RegisterActivity.this, "Регистрация успешна!", Toast.LENGTH_SHORT).show();
                                                                // Navigate to MainActivity
                                                                Intent intent = new Intent(RegisterActivity.this, MainActivity.class);
                                                                startActivity(intent);
                                                                finish();
                                                            } else {
                                                                Toast.makeText(RegisterActivity.this, "Ошибка установки никнейма: " + taskUpdate.getException().getMessage(), Toast.LENGTH_LONG).show();
                                                            }
                                                        });
                                            })
                                            .addOnFailureListener(e -> {
                                                Toast.makeText(RegisterActivity.this, "Ошибка сохранения никнейма: " + e.getMessage(), Toast.LENGTH_LONG).show();
                                            });
                                })
                                .addOnFailureListener(e -> {
                                    Toast.makeText(RegisterActivity.this, "Ошибка сохранения данных: " + e.getMessage(), Toast.LENGTH_LONG).show();
                                });
                    } else {
                        soundManager.playWrongSound();
                        // If sign up fails, display a message to the user.
                        Toast.makeText(RegisterActivity.this, "Ошибка регистрации: " + task.getException().getMessage(),
                                Toast.LENGTH_LONG).show();
                    }
                });
    }

    // Класс модели пользователя
    public static class User {
        public String nickname;
        public String email;
        public String userId;

        public User() {
            // Пустой конструктор для Firebase
        }

        public User(String nickname, String email, String userId) {
            this.nickname = nickname;
            this.email = email;
            this.userId = userId;
        }
    }
}







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);

        // Удалите ненужные установки слушателей
        /*
        startButton.setOnClickListener(v -> startGame());
        nextLevelButton.setOnClickListener(v -> startGame());
        */

        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);
    }
}




package com.example.memorymaster;

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 androidx.appcompat.app.AlertDialog;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Collections;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import android.content.Intent;

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

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 int moves = 0;
    private long totalTime = 0;
    private TextView movesTextView;
    private long startTime;
    private Handler timerHandler = new Handler();
    private TextView timerTextView;
    private String nickname;
    private SoundManager soundManager;
    private KonfettiView konfettiView;
    private String playerUserId;
    private FirebaseHelper firebaseHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pair_matching_game);
        konfettiView = findViewById(R.id.konfettiView);
        soundManager = SoundManager.getInstance(this);

        gridLayout = findViewById(R.id.gridLayout);
        cardButtons = new ArrayList<>();
        movesTextView = findViewById(R.id.movesTextView);
        timerTextView = findViewById(R.id.timerTextView);

        SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        nickname = preferences.getString("nickname", "");

        firebaseHelper = new FirebaseHelper();

        FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
        if (currentUser != null) {
            playerUserId = currentUser.getUid();
        } else {
            Intent intent = new Intent(PairMatchingGame.this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        setupGameForLevel(currentLevel);
        startTimer();
    }

    private void setupGameForLevel(int level) {
        int numberOfCards;
        switch (level) {
            case 1:
                numberOfCards = 6;  // Easy level (6 cards)
                break;
            case 2:
                numberOfCards = 12; // Medium level (12 cards)
                break;
            default:
                numberOfCards = 16; // Hard level (16 cards)
        }

        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();

        // Reset matchedPairs and moves for the new level
        matchedPairs = 0;
        moves = 0;
    }

    private void setupGameGrid(int numberOfCards) {
        gridLayout.removeAllViews();
        cardButtons.clear();

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

        ArrayList<MemoryCard> cardList = new ArrayList<>();
        Collections.addAll(cardList, cardValues);
        Collections.shuffle(cardList);

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

            GridLayout.LayoutParams params = new GridLayout.LayoutParams();
            params.width = 0;
            params.height = GridLayout.LayoutParams.WRAP_CONTENT;
            params.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f);
            params.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f);
            button.setLayoutParams(params);

            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();

        soundManager.playButtonClickSound();

        if (!selectedButton.getText().toString().isEmpty()) {
            return; // Already matched
        }

        selectedButton.setText(String.valueOf(selectedCard.getValue()));
        selectedButton.setBackgroundResource(R.drawable.card_front);

        if (firstSelectedCard == null) {
            firstSelectedCard = selectedButton;
        } else {
            moves++;
            totalMoves++;
            updateMovesDisplay();

            MemoryCard firstCard = (MemoryCard) firstSelectedCard.getTag();
            if (firstCard.getValue() == selectedCard.getValue()) {
                soundManager.playCorrectSound();
                firstSelectedCard.setEnabled(false);
                selectedButton.setEnabled(false);
                matchedPairs++;

                if (matchedPairs == cardValues.length / 2) {
                    onGameWon();
                }
                firstSelectedCard = null;
            } else {
                soundManager.playWrongSound();
                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 updateMovesDisplay() {
        movesTextView.setText("Ходы: " + moves + " (Всего: " + totalMoves + ")");
    }

    private void startTimer() {
        startTime = System.currentTimeMillis() - totalTime * 1000;
        timerHandler.postDelayed(timerRunnable, 0);
    }

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

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

    private void onGameWon() {
        timerHandler.removeCallbacks(timerRunnable);

        if (currentLevel >= 3) {
            gameCompleted();
            return;
        }

        currentLevel++;
        soundManager.playLevelUpSound();
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Уровень " + (currentLevel - 1) + " пройден!")
                .setMessage("Готовы к Уровню " + currentLevel + "?\nХоды: " + moves + "\nВремя: " + formatTime(totalTime))
                .setPositiveButton("Продолжить", (dialog, which) -> {
                    soundManager.playButtonClickSound();
                    setupGameForLevel(currentLevel);
                    startTimer();
                })
                .setCancelable(false)
                .show();
    }

    private String formatTime(long totalSeconds) {
        long minutes = totalSeconds / 60;
        long seconds = totalSeconds % 60;
        return String.format("%d:%02d", minutes, seconds);
    }

    private void gameCompleted() {
        firebaseHelper.updatePairMatchingStats(playerUserId, totalMoves, totalTime, new FirebaseHelper.UpdateStatsCallback() {
            @Override
            public void onUpdateCompleted(boolean newRecord) {
                if (newRecord) {
                    soundManager.playNewRecordSound();
                    showConfetti();
                } else {
                    soundManager.playVictorySound();
                }

                AlertDialog.Builder builder = new AlertDialog.Builder(PairMatchingGame.this);
                builder.setTitle("Поздравляем!")
                        .setMessage("Вы прошли все уровни!\nВсего ходов: " + totalMoves + "\nВремя: " + formatTime(totalTime))
                        .setPositiveButton("Играть снова", (dialog, which) -> {
                            soundManager.playButtonClickSound();
                            resetGame();
                        })
                        .setNegativeButton("Выйти", (dialog, which) -> {
                            soundManager.playButtonClickSound();
                            finish();
                        })
                        .show();
            }

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

    private void resetGame() {
        currentLevel = 1;
        totalMoves = 0;
        totalTime = 0;
        matchedPairs = 0;
        moves = 0;
        setupGameForLevel(currentLevel);
        startTimer();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        timerHandler.removeCallbacks(timerRunnable);
        soundManager.release();
    }

    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);
    }
}





package com.example.memorymaster;

import android.app.Activity;
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.widget.Toast;
import androidx.appcompat.app.AlertDialog;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

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

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 String playerNickname;
    private int tileCount;
    private boolean gameStarted = false;
    private boolean countdownFinished = false;
    private boolean gameActive = false;
    private Button correctSquare;
    private Runnable showSquareRunnable;
    private String gameMode;
    private int currentLevel = 1;
    private int[] levelTargets = {1000, 900, 800, 700, 600, 550, 500, 450, 400, 350};
    private SoundManager soundManager;
    private KonfettiView konfettiView;
    private String playerUserId;
    private FirebaseHelper firebaseHelper;

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

        initializeViews();
        initializeGame();

        gameMode = getIntent().getStringExtra("gameMode");
        if ("level".equals(gameMode)) {
            startLevelMode();
        } else {
            startFreeMode();
        }

        FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
        if (currentUser != null) {
            playerUserId = currentUser.getUid();
        } else {
            Intent intent = new Intent(ReactionGame.this, LoginActivity.class);
            startActivity(intent);
            finish();
            return;
        }

        setupListeners();
    }

    private void initializeViews() {
        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);
        gridLayout = findViewById(R.id.gridLayout);
    }

    private void initializeGame() {
        tileCount = getIntent().getIntExtra("tileCount", 1);
        SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        playerNickname = preferences.getString("nickname", "Player");
        stopwatch = new Stopwatch();
        handler = new Handler();
        soundManager = SoundManager.getInstance(this);

        setupGameGrid();

        firebaseHelper = new FirebaseHelper();
    }

    private void startLevelMode() {
        updateLevelTitle();
        startButton.setText("Начать уровень");
        startButton.setVisibility(View.VISIBLE);
    }

    private void startFreeMode() {
        title.setText("Свободный режим: Проверьте вашу реакцию");
        startButton.setText("Начать");
        startButton.setVisibility(View.VISIBLE);
    }

    private void setupListeners() {
        startButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            String buttonText = startButton.getText().toString();

            if (buttonText.equals("Следующий уровень")) {
                currentLevel++;
                updateLevelTitle();
                startButton.setText("Начать уровень");
            } else if (buttonText.equals("Начать уровень") || buttonText.equals("Начать")) {
                gameActive = true;
                startCountdown();
                startButton.setVisibility(View.GONE);
            } else if (buttonText.equals("Завершить игру")) {
                gameCompleted();
                return;
            }
        });

        retryButton.setOnClickListener(v -> {
            soundManager.playButtonClickSound();
            gameActive = true;
            retryButton.setVisibility(View.GONE);
            startCountdown();
        });

        setAllSquaresClickable(true);
    }

    private void setAllSquaresClickable(boolean clickable) {
        for (Button square : squares) {
            square.setClickable(clickable);
        }
    }

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

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

        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int tileSize = (screenWidth - 60) / 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::checkReaction);
            squares.add(button);
            gridLayout.addView(button);
        }
    }

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

        if (currentUser == null) {
            Intent intent = new Intent(ReactionGame.this, LoginActivity.class);
            startActivity(intent);
            finish();
        }
    }

    private void startCountdown() {
        countdownText.setVisibility(View.VISIBLE);
        gameStarted = false;
        countdownFinished = false;

        handler.postDelayed(() -> countdownText.setText("3"), 0);
        handler.postDelayed(() -> countdownText.setText("2"), 1000);
        handler.postDelayed(() -> countdownText.setText("1"), 2000);

        handler.postDelayed(() -> {
            countdownText.setText("");
            countdownText.setVisibility(View.GONE);
            countdownFinished = true;
            startReactionGame();
        }, 3000);
    }

    private void startReactionGame() {
        title.setText("Ждите...");
        int randomDelay = new Random().nextInt(5000 - 1000) + 1000;

        showSquareRunnable = () -> {
            showRandomSquare();
            stopwatch.start();
            gameStarted = true;
        };

        handler.postDelayed(showSquareRunnable, randomDelay);
    }

    private void showRandomSquare() {
        Random random = new Random();
        int randomIndex = random.nextInt(squares.size());
        correctSquare = squares.get(randomIndex);

        handler.post(() -> {
            correctSquare.setBackgroundColor(Color.GREEN);
            title.setText("Нажмите на зеленую плитку!");
        });
    }

    private void checkReaction(View view) {
        if (!gameActive) {
            return;
        }

        Button clickedButton = (Button) view;

        if (!countdownFinished) {
            Toast.makeText(this, "Подождите окончания отсчета!", Toast.LENGTH_SHORT).show();
            return;
        }

        if (!gameStarted) {
            title.setText("Слишком рано! Подождите зеленую плитку.");
            soundManager.playWrongSound();
            resetGame();
            return;
        }

        if (clickedButton != correctSquare) {
            title.setText("Ошибка! Нажата неверная плитка.");
            soundManager.playWrongSound();
            resetGame();
            return;
        }

        stopwatch.stop();
        reactionTime = (int) stopwatch.getElapsedTimeMillis();
        reactionTimeText.setText("Время реакции: " + reactionTime + " мс");

        clickedButton.setBackgroundColor(Color.BLUE);
        new Handler().postDelayed(() -> {
            clickedButton.setBackgroundColor(Color.WHITE);
        }, 200);

        if ("level".equals(gameMode)) {
            checkLevelCompletion(reactionTime);
        } else {
            evaluateReactionTime(reactionTime);
            retryButton.setVisibility(View.VISIBLE);
        }

        saveBestTime();
        gameActive = false;
    }

    private void evaluateReactionTime(int reactionTime) {
        if (reactionTime <= 200) {
            title.setText("Отличная реакция!");
        } else if (reactionTime <= 300) {
            title.setText("Хорошая реакция!");
        } else if (reactionTime <= 500) {
            title.setText("Средняя реакция.");
        } else {
            title.setText("Можно быстрее!");
        }
    }

    private void checkLevelCompletion(int reactionTime) {
        if (reactionTime <= levelTargets[currentLevel - 1]) {
            if (currentLevel >= levelTargets.length) {
                gameCompleted();
            } else {
                levelCompleted();
            }
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Уровень не пройден")
                    .setMessage("Вы не уложились в " + levelTargets[currentLevel - 1] + " мс")
                    .setCancelable(false)
                    .setPositiveButton("Начать с начала", (dialog, which) -> {
                        soundManager.playButtonClickSound();
                        currentLevel = 1;
                        updateLevelTitle();
                        startButton.setText("Начать уровень");
                        startButton.setVisibility(View.VISIBLE);
                        resetGame();
                    })
                    .setNegativeButton("Главное меню", (dialog, which) -> {
                        soundManager.playButtonClickSound();
                        finish();
                    });
            AlertDialog alert = builder.create();
            alert.show();
        }
    }

    private void levelCompleted() {
        soundManager.playLevelUpSound();

        if (currentLevel == levelTargets.length) {
            title.setText("Уровень " + currentLevel + " пройден!");
            startButton.setText("Завершить игру");
        } else {
            title.setText("Уровень " + currentLevel + " пройден!");
            startButton.setText("Следующий уровень");
        }

        startButton.setVisibility(View.VISIBLE);
        retryButton.setVisibility(View.GONE);
        gameActive = false;
    }

    private void gameCompleted() {
        firebaseHelper.updateReactionGameStats(playerUserId, reactionTime, new FirebaseHelper.UpdateStatsCallback() {
            @Override
            public void onUpdateCompleted(boolean newRecord) {
                if (newRecord) {
                    soundManager.playNewRecordSound();
                    showConfetti();
                } else {
                    soundManager.playVictorySound();
                }

                if ("level".equals(gameMode)) {
                    unlockNextTile();
                }

                AlertDialog.Builder builder = new AlertDialog.Builder(ReactionGame.this);
                builder.setTitle("Поздравляем!")
                        .setMessage("Вы прошли все уровни!\nВремя реакции: " + reactionTime + " мс")
                        .setPositiveButton("Играть снова", (dialog, which) -> {
                            soundManager.playButtonClickSound();
                            resetGame();
                        })
                        .setNegativeButton("Выйти", (dialog, which) -> {
                            soundManager.playButtonClickSound();
                            finish();
                        })
                        .show();
            }

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

    private void unlockNextTile() {
        SharedPreferences preferences = getSharedPreferences("game_prefs", MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();

        Set<String> unlockedTiles = preferences.getStringSet("unlocked_tiles", new HashSet<>(Collections.singleton("1")));
        unlockedTiles = new HashSet<>(unlockedTiles);

        unlockedTiles.add(String.valueOf(tileCount));

        int nextTileCount = getNextTileCount(tileCount);
        if (nextTileCount != -1) {
            unlockedTiles.add(String.valueOf(nextTileCount));
            Toast.makeText(this, "Разблокировано количество плиток: " + nextTileCount, Toast.LENGTH_LONG).show();
        } else {
            editor.putBoolean("free_mode_unlocked", true);
            Toast.makeText(this, "Свободный режим разблокирован!", Toast.LENGTH_LONG).show();
        }

        editor.putStringSet("unlocked_tiles", unlockedTiles);
        editor.apply();
    }

    private int getNextTileCount(int currentTileCount) {
        int[] tileCounts = {1, 2, 4};
        for (int i = 0; i < tileCounts.length - 1; i++) {
            if (tileCounts[i] == currentTileCount) {
                return tileCounts[i+1];
            }
        }
        return -1;
    }

    private void saveBestTime() {
        firebaseHelper.updateReactionGameStats(playerUserId, reactionTime, new FirebaseHelper.UpdateStatsCallback() {
            @Override
            public void onUpdateCompleted(boolean newRecord) {
                if (newRecord) {
                    soundManager.playNewRecordSound();
                    showConfetti();
                    title.setText(title.getText() + " Новый рекорд!");
                }
            }

            @Override
            public void onUpdateFailed(Exception e) {
                Toast.makeText(ReactionGame.this, "Ошибка сохранения рекорда: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }
        });
    }

    private void resetGame() {
        handler.removeCallbacks(showSquareRunnable);

        for (Button square : squares) {
            square.setBackgroundColor(Color.WHITE);
        }
        gameStarted = false;
        countdownFinished = false;
        gameActive = false;

        if ("level".equals(gameMode)) {
            startButton.setText("Начать уровень");
            startButton.setVisibility(View.VISIBLE);
        } else {
            retryButton.setVisibility(View.VISIBLE);
        }

        if (stopwatch.isRunning()) {
            stopwatch.stop();
        }

        setAllSquaresClickable(true);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        soundManager.release();
    }

    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);
    }

    private void updateLevelTitle() {
        title.setText("Уровень " + currentLevel + ": Реагируйте быстрее чем " + levelTargets[currentLevel - 1] + " мс");
    }


}




как работают игры расскажи подробно про каждый метод что он делает и как игра работает в общем
также расскажи каким образом передаются данные в базу данных и как принимаются и показываются в классе профиль какой метод за что отвечает и как работает