Newer
Older
python_M_mind / src / game_logic.py
"""
Logique pure du jeu MasterMind - sans GUI
"""

import random
from typing import List, Tuple
from config import CODE_LENGTH, NUM_COLORS, MAX_ATTEMPTS, COLORS


class MasterMindGame:
    """Moteur du jeu MasterMind"""

    def __init__(self):
        """Initialise une nouvelle partie"""
        self.secret_code = self._generate_secret()
        self.attempts = []  # Liste de tuples (guess, feedback)
        self.game_over = False
        self.won = False

    def _generate_secret(self) -> List[int]:
        """Génère un code secret aléatoire (indices de couleurs)"""
        return [random.randint(0, NUM_COLORS - 1) for _ in range(CODE_LENGTH)]

    def _calculate_feedback(self, guess: List[int]) -> Tuple[int, int]:
        """
        Calcule le feedback pour une tentative.
        Retourne (noirs, blancs) où:
        - noirs = positions correctes (bonne couleur + bonne position)
        - blancs = bonnes couleurs mais mauvaises positions
        """
        secret = self.secret_code.copy()
        guess_copy = guess.copy()

        # D'abord compter les noirs (positions exactes)
        black = 0
        for i in range(CODE_LENGTH):
            if guess_copy[i] == secret[i]:
                black += 1
                guess_copy[i] = None  # Marquer comme compté
                secret[i] = None

        # Ensuite compter les blancs (bonnes couleurs mal placées)
        white = 0
        for i in range(CODE_LENGTH):
            if guess_copy[i] is not None:
                for j in range(CODE_LENGTH):
                    if secret[j] is not None and guess_copy[i] == secret[j]:
                        white += 1
                        secret[j] = None
                        break

        return black, white

    def make_guess(self, guess: List[int]) -> Tuple[bool, Tuple[int, int]]:
        """
        Effectue une tentative.
        Args:
            guess: Liste d'indices de couleurs (0 à NUM_COLORS-1)
        Returns:
            (is_correct, feedback) où feedback = (noirs, blancs)
        """
        if self.game_over:
            raise ValueError("La partie est terminée")

        if len(guess) != CODE_LENGTH:
            raise ValueError(f"Le guess doit contenir {CODE_LENGTH} couleurs")

        feedback = self._calculate_feedback(guess)
        self.attempts.append((guess.copy(), feedback))

        # Vérifier si gagné
        if feedback[0] == CODE_LENGTH:
            self.won = True
            self.game_over = True
        elif len(self.attempts) >= MAX_ATTEMPTS:
            self.game_over = True

        return self.won, feedback

    def get_remaining_attempts(self) -> int:
        """Retourne le nombre de tentatives restantes"""
        return MAX_ATTEMPTS - len(self.attempts)

    def reveal_secret(self) -> List[int]:
        """Retourne le code secret (pour affichage en fin de partie)"""
        return self.secret_code.copy()

    def reset(self):
        """Réinitialise la partie"""
        self.__init__()


def guess_to_colors(guess: List[int]) -> List[str]:
    """Convertit une liste d'indices en noms de couleurs"""
    return [COLORS[i][0] for i in guess]


def feedback_to_string(feedback: Tuple[int, int]) -> str:
    """Formatte le feedback pour affichage"""
    black, white = feedback
    return f"⬛{black} ⬜{white}"


if __name__ == "__main__":
    # Test simple de la logique
    game = MasterMindGame()
    print(f"Code secret (indices): {game.secret_code}")
    print(f"Code secret (couleurs): {guess_to_colors(game.secret_code)}")

    # Test d'une tentative
    test_guess = game.secret_code.copy()  # Devine le secret (should win)
    won, feedback = game.make_guess(test_guess)
    print(f"Guess: {guess_to_colors(test_guess)} -> Feedback: {feedback} - Gagné: {won}")