https://huggingface.co/spaces/yuntian-deng/ChatGPT4
Chatbot





<application
    android:allowBackup="true"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.MemoryMaster"
    tools:targetApi="31">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".MemoryGame" />
    <activity android:name=".ProfileActivity" />
    <activity android:name=".DifficultySelectionActivity" />
    <activity android:name=".ReactionGame" />
    <activity android:name=".TileSelectionActivity" />
    <activity android:name=".PairMatchingGame" />
    <activity android:name=".ReactionGameModeSelection" />
    <activity android:name=".LoginActivity"></activity>
    <activity android:name=".RegisterActivity"></activity>
</application>
package com.example.memorymaster;

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

import androidx.appcompat.app.AppCompatActivity;

public class DifficultySelectionActivity extends AppCompatActivity {


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

    Button btnEasy = findViewById(R.id.btn_easy);
    Button btnMedium = findViewById(R.id.btn_medium);
    Button btnHard = findViewById(R.id.btn_hard);

    btnEasy.setOnClickListener(v -> startGameWithDifficulty(4)); // Легкая сложность - 4 плитки
    btnMedium.setOnClickListener(v -> startGameWithDifficulty(9)); // Средняя сложность - 9 плиток
    btnHard.setOnClickListener(v -> startGameWithDifficulty(12)); // Сложная - 12 плиток
}

private void startGameWithDifficulty(int tileCount) {
    Intent intent = new Intent(DifficultySelectionActivity.this, MemoryGame.class);
    intent.putExtra("tileCount", tileCount); // Передаем выбранную сложность
    startActivity(intent);
}
}

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.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.widget.Button;
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.*;

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

    // Initialize Firebase
    FirebaseApp.initializeApp(this);

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

    soundManager = SoundManager.getInstance(this);

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

package com.example.memorymaster;

public class MemoryCard {
private final int value;


public MemoryCard(int value) {
    this.value = value;
}

public int getValue() {
    return value;
}
}

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.Random;

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("#E6E6FA");
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;


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

    ConstraintLayout mainLayout = findViewById(R.id.mainLayout);
    mainLayout.setBackgroundColor(COLOR_BACKGROUND);

    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 = 10;
    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 гарантированно инициализирован

    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 user is not logged in, navigate to LoginActivity
    if (currentUser == null) {
        Intent intent = new Intent(MemoryGame.this, LoginActivity.class);
        startActivity(intent);
        finish();  // Close MemoryGame to prevent returning to it
    } else {
        // Additional logic if needed
    }
}

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

    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();
                    })
                    .setCancelable(false)
                    .show();
        }

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

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 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 long pauseTime = 0;
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); // Ensure you have card_back drawable

        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); // Ensure you have card_front drawable

    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 + " (Total: " + totalMoves + ")");
}

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

private void pauseTimer() {
    timerHandler.removeCallbacks(timerRunnable);
    pauseTime = System.currentTimeMillis() - startTime;
}

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

private void onGameWon() {
    pauseTimer();
    totalTime += pauseTime / 1000;

    if (currentLevel >= 3) { // Adjust based on desired levels
        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);
            })
            .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() {
    // Update Firestore
    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;
    pauseTime = 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.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 Button buttonLogout;

private FirebaseAuth mAuth;
private DatabaseReference usersRef;

private SoundManager soundManager;

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

    textViewNickname = findViewById(R.id.textViewNickname);
    textViewEmail = findViewById(R.id.textViewEmail);
    buttonLogout = findViewById(R.id.buttonLogout);

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

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

    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);
            String email = snapshot.child("email").getValue(String.class);

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

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

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

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.Random;

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

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

private void setupListeners() {
    startButton.setOnClickListener(v -> {
        soundManager.playButtonClickSound();
        gameActive = true;
        startCountdown();
        startButton.setVisibility(View.GONE);
    });

    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) {
        // Player clicked during countdown
        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 {
        // Show dialog for level failure
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Уровень не пройден")
                .setMessage("Вы не уложились в " + levelTargets[currentLevel - 1] + " мс")
                .setCancelable(false)
                .setPositiveButton("Начать с первого уровня", (dialog, which) -> {
                    soundManager.playButtonClickSound();
                    currentLevel = 1;
                    updateLevelTitle();
                    gameActive = true;
                    startCountdown();
                })
                .setNegativeButton("Главное меню", (dialog, which) -> {
                    soundManager.playButtonClickSound();
                    finish(); // Return to main menu
                });
        AlertDialog alert = builder.create();
        alert.show();
    }
    resetGame();
}

private void levelCompleted() {
    soundManager.playLevelUpSound();
    title.setText("Уровень " + currentLevel + " пройден!");
    startButton.setText("Следующий уровень");
    startButton.setVisibility(View.VISIBLE);
    retryButton.setVisibility(View.GONE);
    gameActive = false;
}

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

            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 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.setVisibility(View.VISIBLE);
        startButton.setText("Начать уровень");
    } 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] + " мс");
}
}

package com.example.memorymaster;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;

public class ReactionGameModeSelection extends Activity {
private SoundManager soundManager;


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

    soundManager = SoundManager.getInstance(this);

    Button btnFreeMode = findViewById(R.id.btn_free_mode);
    Button btnLevelMode = findViewById(R.id.btn_level_mode);

    // Вместо непосредственного запуска игры, переходим на экран выбора плиток
    btnFreeMode.setOnClickListener(v -> {
        soundManager.playButtonClickSound();
        Intent intent = new Intent(ReactionGameModeSelection.this, TileSelectionActivity.class);
        intent.putExtra("gameMode", "free");
        startActivity(intent);
    });

    btnLevelMode.setOnClickListener(v -> {
        soundManager.playButtonClickSound();
        Intent intent = new Intent(ReactionGameModeSelection.this, TileSelectionActivity.class);
        intent.putExtra("gameMode", "level");
        startActivity(intent);
    });
}
}

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.Context;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.media.SoundPool;

public class SoundManager {
private static SoundManager instance;
private SoundPool soundPool;
private MediaPlayer backgroundMusic;
private Context context;


private int buttonClickSound;
private int correctSound;
private int wrongSound;
private int victorySound;
private int defeatSound;
private int newRecordSound;
private int levelUpSound;

private boolean isMusicEnabled = true;
private boolean isSoundEnabled = true;

private SoundManager(Context context) {
    this.context = context.getApplicationContext();
    initializeSoundPool();
}

public static synchronized SoundManager getInstance(Context context) {
    if (instance == null) {
        instance = new SoundManager(context);
    } else if (instance.soundPool == null) {
        instance.initializeSoundPool();
    }
    return instance;
}

private void initializeSoundPool() {
    AudioAttributes audioAttributes = new AudioAttributes.Builder()
            .setUsage(AudioAttributes.USAGE_GAME)
            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
            .build();

    soundPool = new SoundPool.Builder()
            .setMaxStreams(6)
            .setAudioAttributes(audioAttributes)
            .build();

    buttonClickSound = soundPool.load(context, R.raw.button_click, 1);
    correctSound = soundPool.load(context, R.raw.correct_sound, 1);
    wrongSound = soundPool.load(context, R.raw.wrong_sound, 1);
    victorySound = soundPool.load(context, R.raw.victory, 1);
    defeatSound = soundPool.load(context, R.raw.defeat, 1);
    newRecordSound = soundPool.load(context, R.raw.new_record, 1);
    levelUpSound = soundPool.load(context, R.raw.level_up, 1);

    initializeBackgroundMusic();
}

private void initializeBackgroundMusic() {
    backgroundMusic = MediaPlayer.create(context, R.raw.background_music);
    backgroundMusic.setLooping(true);
}

public void playButtonClickSound() {
    playSoundEffect(buttonClickSound);
}

public void playCorrectSound() {
    playSoundEffect(correctSound);
}

public void playWrongSound() {
    playSoundEffect(wrongSound);
}

public void playVictorySound() {
    playSoundEffect(victorySound);
}

public void playDefeatSound() {
    playSoundEffect(defeatSound);
}

public void playNewRecordSound() {
    playSoundEffect(newRecordSound);
}

public void playLevelUpSound() {
    playSoundEffect(levelUpSound);
}

private void playSoundEffect(int soundId) {
    if (isSoundEnabled && soundPool != null) {
        soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f);
    }
}

public void playBackgroundMusic() {
    if (isMusicEnabled && backgroundMusic != null && !backgroundMusic.isPlaying()) {
        backgroundMusic.start();
    }
}

public void pauseBackgroundMusic() {
    if (backgroundMusic != null && backgroundMusic.isPlaying()) {
        backgroundMusic.pause();
    }
}

public void stopBackgroundMusic() {
    if (backgroundMusic != null) {
        backgroundMusic.stop();
        backgroundMusic.prepareAsync();
    }
}

public void setMusicEnabled(boolean enabled) {
    isMusicEnabled = enabled;
    if (enabled) {
        playBackgroundMusic();
    } else {
        pauseBackgroundMusic();
    }
}

public void setSoundEnabled(boolean enabled) {
    isSoundEnabled = enabled;
}

public void release() {
    if (soundPool != null) {
        soundPool.release();
        soundPool = null;
    }
    if (backgroundMusic != null) {
        backgroundMusic.release();
        backgroundMusic = null;
    }
}
}

package com.example.memorymaster;

public class Stopwatch {
private long startTime;
private long stopTime;
private boolean running;


public void start() {
    this.startTime = System.currentTimeMillis();
    this.running = true;
}

public void stop() {
    this.stopTime = System.currentTimeMillis();
    this.running = false;
}

public long getElapsedTimeNano() {
    if (running) {
        return System.nanoTime() - startTime;
    } else {
        return stopTime - startTime;
    }
}

public long getElapsedTimeMillis() {
    if (running) {
        return System.currentTimeMillis() - startTime;
    } else {
        return stopTime - startTime;
    }
}

public boolean isRunning() {
    return running;
}
}

package com.example.memorymaster;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;

public class TileSelectionActivity extends Activity {


private String gameMode;

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

    // Получаем режим игры из предыдущей активности
    gameMode = getIntent().getStringExtra("gameMode");

    Button btnOneTile = findViewById(R.id.btn_one_tile);
    Button btnTwoTiles = findViewById(R.id.btn_two_tiles);
    Button btnFourTiles = findViewById(R.id.btn_four_tiles);

    // Слушатели для выбора количества плиток
    btnOneTile.setOnClickListener(v -> startGame(1));
    btnTwoTiles.setOnClickListener(v -> startGame(2));
    btnFourTiles.setOnClickListener(v -> startGame(4));
}

// Метод для запуска игры с выбранным количеством плиток
private void startGame(int tileCount) {
    Intent intent = new Intent(TileSelectionActivity.this, ReactionGame.class);
    // Передаем количество плиток и режим игры в ReactionGame
    intent.putExtra("tileCount", tileCount);
    intent.putExtra("gameMode", gameMode);
    startActivity(intent);

    // Закрываем текущую активность выбора
    finish();  // Закрывает TileSelectionActivity, чтобы оно не накладывалось на интерфейс игры
}
}

activity_difficulty_selection.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/difficultyLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<!-- Заголовок -->
<TextView
    android:id="@+id/select_difficulty_label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Выберите сложность"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Кнопка "Легкая сложность" -->
<Button
    android:id="@+id/btn_easy"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Легкая"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/select_difficulty_label"
    app:layout_constraintBottom_toTopOf="@id/btn_medium"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="200dp"/>

<!-- Кнопка "Средняя сложность" -->
<Button
    android:id="@+id/btn_medium"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Средняя"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_easy"
    app:layout_constraintBottom_toTopOf="@id/btn_hard"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>

<!-- Кнопка "Тяжелая сложность" -->
<Button
    android:id="@+id/btn_hard"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Тяжелая"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_medium"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

activity_login.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/loginLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<!-- Заголовок -->
<TextView
    android:id="@+id/login_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Вход"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toTopOf="@id/editTextLoginEmail"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Поле ввода Email -->
<EditText
    android:id="@+id/editTextLoginEmail"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:hint="Email"
    android:inputType="textEmailAddress"
    app:layout_constraintTop_toBottomOf="@id/login_title"
    app:layout_constraintBottom_toTopOf="@id/editTextLoginPassword"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Поле ввода пароля -->
<EditText
    android:id="@+id/editTextLoginPassword"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:hint="Пароль"
    android:inputType="textPassword"
    app:layout_constraintTop_toBottomOf="@id/editTextLoginEmail"
    app:layout_constraintBottom_toTopOf="@id/buttonLogin"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Кнопка "Войти" -->
<Button
    android:id="@+id/buttonLogin"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Войти"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/editTextLoginPassword"
    app:layout_constraintBottom_toTopOf="@id/textViewRegisterLink"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Ссылка на регистрацию -->
<TextView
    android:id="@+id/textViewRegisterLink"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Нет аккаунта? Зарегистрироваться"
    android:textColor="#800080"
    android:textSize="16sp"
    app:layout_constraintTop_toBottomOf="@id/buttonLogin"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="#E6E6FA">


<!-- Закрепленный заголовок сверху -->
<TextView
    android:id="@+id/game_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Мастер памяти"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

<!-- Центрируем кнопки -->
<Button
    android:id="@+id/btn_memory"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Мастер памяти"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/game_title"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toTopOf="@id/btn_reaction"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="200dp"/>

<Button
    android:id="@+id/btn_reaction"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Игра на реакцию"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_memory"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toTopOf="@id/btn_pair_matching"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>

<Button
    android:id="@+id/btn_pair_matching"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Найди пару плиток"
    android:background="#800080"
    android:textColor="#FFA500"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/btn_reaction"
    app:layout_constraintBottom_toTopOf="@id/btn_profile"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"/>


<Button
    android:id="@+id/btn_profile"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Профиль"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_pair_matching"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"
    app:layout_constraintVertical_chainStyle="packed"/>
</androidx.constraintlayout.widget.ConstraintLayout>

activity_memory_game.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">


<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Мастер памяти"
    android:textSize="24sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

<TextView
    android:id="@+id/level"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Уровень 1"
    android:textSize="18sp"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/title"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="8dp"/>

<TextView
    android:id="@+id/score"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Счёт: 0"
    android:textSize="18sp"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/title"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="8dp"/>

<TextView
    android:id="@+id/timerTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="0:00"
    android:textSize="18sp"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/level"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="8dp"/>

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.2" />

<GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toBottomOf="@id/guideline"
    app:layout_constraintBottom_toTopOf="@id/startBtn"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"
    android:layout_marginBottom="16dp"/>

<Button
    android:id="@+id/startBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Начать игру"
    android:textColor="#FFA500"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"/>

<Button
    android:id="@+id/nextLevelBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Следующий уровень"
    android:textColor="#FFA500"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"
    android:visibility="gone" />


<nl.dionsegijn.konfetti.KonfettiView
    android:id="@+id/konfettiView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_pair_matching_game.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Найди пару плиток"
    android:textSize="24sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"/>

<TextView
    android:id="@+id/movesTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Ходы: 0"
    android:textSize="18sp"
    android:textColor="#4B0082"
    app:layout_constraintTop_toBottomOf="@id/title"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="8dp"/>

<TextView
    android:id="@+id/timerTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Время: 0:00"
    android:textSize="18sp"
    android:textColor="#4B0082"
    app:layout_constraintTop_toBottomOf="@id/title"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="8dp"/>

<GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginTop="16dp"
    app:layout_constraintTop_toBottomOf="@id/movesTextView"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"/>

<nl.dionsegijn.konfetti.KonfettiView
    android:id="@+id/konfettiView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_profile.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="#E6E6FA">


<TextView
    android:id="@+id/profile_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Профиль"
    android:textSize="24sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

<TextView
    android:id="@+id/textViewNickname"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="Никнейм: "
    android:textSize="18sp"
    android:textColor="#800080"
    app:layout_constraintTop_toBottomOf="@id/profile_title"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="24dp"/>

<TextView
    android:id="@+id/textViewEmail"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="Email: "
    android:textSize="18sp"
    android:textColor="#800080"
    app:layout_constraintTop_toBottomOf="@id/textViewNickname"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="16dp"/>

<Button
    android:id="@+id/buttonLogout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Выйти"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/textViewEmail"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="24dp"/>

<!-- Optional: Add sections to display game statistics -->
</androidx.constraintlayout.widget.ConstraintLayout>

activity_reaction_game.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Игра на реакцию"
    android:textSize="24sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"/>

<TextView
    android:id="@+id/countdownText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="36sp"
    android:textStyle="bold"
    android:textColor="#FF0000"
    app:layout_constraintTop_toBottomOf="@id/title"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"
    android:visibility="gone" />

<TextView
    android:id="@+id/reactionTime"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Время реакции: 0 ms"
    android:textSize="18sp"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/countdownText"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"/>

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.3" />

<GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toBottomOf="@id/guideline"
    app:layout_constraintBottom_toTopOf="@id/startBtn"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"
    android:layout_marginBottom="16dp"/>

<Button
    android:id="@+id/startBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Начать игру"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"
    android:visibility="visible" />

<Button
    android:id="@+id/retryBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Ещё раз"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginBottom="16dp"
    android:visibility="gone" />

<nl.dionsegijn.konfetti.KonfettiView
    android:id="@+id/konfettiView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_reaction_game_mode_selection.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/reactionModeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<!-- Заголовок -->
<TextView
    android:id="@+id/select_mode_label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Выберите режим"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Кнопка "Свободный режим" -->
<Button
    android:id="@+id/btn_free_mode"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Свободный режим"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/select_mode_label"
    app:layout_constraintBottom_toTopOf="@id/btn_level_mode"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="200dp"/>

<!-- Кнопка "Режим уровней" -->
<Button
    android:id="@+id/btn_level_mode"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Режим уровней"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_free_mode"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

activity_register.xml:

<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/registerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<!-- Заголовок -->
<TextView
    android:id="@+id/register_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Регистрация"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toTopOf="@id/editTextNickname"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Поле ввода никнейма -->
<EditText
    android:id="@+id/editTextNickname"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:hint="Никнейм"
    android:inputType="textPersonName"
    app:layout_constraintTop_toBottomOf="@id/register_title"
    app:layout_constraintBottom_toTopOf="@id/editTextEmail"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Поле ввода Email -->
<EditText
    android:id="@+id/editTextEmail"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:hint="Email"
    android:inputType="textEmailAddress"
    app:layout_constraintTop_toBottomOf="@id/editTextNickname"
    app:layout_constraintBottom_toTopOf="@id/editTextPassword"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Поле ввода пароля -->
<EditText
    android:id="@+id/editTextPassword"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:hint="Пароль"
    android:inputType="textPassword"
    app:layout_constraintTop_toBottomOf="@id/editTextEmail"
    app:layout_constraintBottom_toTopOf="@id/buttonRegister"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Кнопка "Зарегистрироваться" -->
<Button
    android:id="@+id/buttonRegister"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="Зарегистрироваться"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/editTextPassword"
    app:layout_constraintBottom_toTopOf="@id/textViewLoginLink"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Ссылка на вход -->
<TextView
    android:id="@+id/textViewLoginLink"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Уже есть аккаунт? Войти"
    android:textColor="#800080"
    android:textSize="16sp"
    app:layout_constraintTop_toBottomOf="@id/buttonRegister"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

activity_tile_selection.xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tileSelectionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6E6FA"
android:padding="16dp">


<!-- Заголовок -->
<TextView
    android:id="@+id/select_tile_label"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Выберите количество плиток"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="#FFA500"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

<!-- Кнопка "1 Плитка" -->
<Button
    android:id="@+id/btn_one_tile"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="1 Плитка"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/select_tile_label"
    app:layout_constraintBottom_toTopOf="@id/btn_two_tiles"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="200dp"/>

<!-- Кнопка "2 Плитки" -->
<Button
    android:id="@+id/btn_two_tiles"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="2 Плитки"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_one_tile"
    app:layout_constraintBottom_toTopOf="@id/btn_four_tiles"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>

<!-- Кнопка "4 Плитки" -->
<Button
    android:id="@+id/btn_four_tiles"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:text="4 Плитки"
    android:background="#800080"
    android:textColor="#FFA500"
    app:layout_constraintTop_toBottomOf="@id/btn_two_tiles"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintVertical_chainStyle="packed"
    android:layout_marginTop="16dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.google.gms.google.services) apply false
}

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.google.gms.google.services)
}

android {
namespace = "com.example.memorymaster"
compileSdk = 34


defaultConfig {
    applicationId = "com.example.memorymaster"
    minSdk = 23
    targetSdk = 34
    versionCode = 1
    versionName = "1.0"

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    release {
        isMinifyEnabled = false
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
    }
}
compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
}

dependencies {


implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
implementation(libs.firebase.database)
implementation(libs.firebase.auth)
implementation(libs.firebase.firestore)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
implementation(platform("com.google.firebase:firebase-bom:33.4.0"))
// Firebase Authentication (if necessary)
implementation ("com.google.firebase:firebase-auth:23.0.0")

// Firebase Realtime Database
implementation ("com.google.firebase:firebase-database:20.0.5")
implementation ("nl.dionsegijn:konfetti:1.3.2")
implementation("androidx.gridlayout:gridlayout:1.0.0")
}
почему в окнах выбора режима игры на реакцию и выбора количества плиток цвета кнопок немного отличаются хотя вроде там назначены те же цвета что и в главном меню