CentraleSupélec LMF, UMR CNRS 9021
Département informatique Laboratoire Méthodes Formelles
Bât Breguet, 3 rue Joliot-Curie Bât 650 Ada Lovelace, Université Paris Sud
91190 Gif-sur-Yvette, France Rue Noetzlin, 91190 Gif-sur-Yvette, France
TD n°11 SIP

Le sujet SIP-TD11.pdf

Éléments de corrigé

Fichier de test test_td11.py

import pytest
import td11

def test_check_word() :
    assert td11.print_check('python', 'yponth')
    assert td11.print_check('', '')
    assert td11.print_check('', 'c')
    assert not td11.print_check('c', '')
    assert td11.print_check('python', 'yponths')
    assert not td11.print_check('pythons', 'yponth')

def test_update_turns():
    assert td11.check_guess('p', 'python', 9) == (True, 9)
    assert td11.check_guess('a', 'python', 9) == (False, 8)
    assert td11.check_guess('', '', 9) == (True, 9)
    assert td11.check_guess('', 'c', 9) == (True, 9)
    assert td11.check_guess('a', '', 9) == (False, 8)

def test_get_guessed_word():
    assert td11.get_guessed_word('', '') == ''
    assert td11.get_guessed_word('', 'c') == ''
    assert td11.get_guessed_word('centralesupelec', '') == '***************'
    assert td11.get_guessed_word('centralesupelec', 'c') == 'c*************c'
    assert td11.get_guessed_word('centralesupelec', 'cs') == 'c*******s*****c'
    assert td11.get_guessed_word('centralesupelec', 'centralsup') == 'centralesupelec'
    assert td11.get_guessed_word('centralesupelec', 'supcentral') == 'centralesupelec'

def test_check_guessed_word():
    assert td11.check_guessed_word('', '')
    assert td11.check_guessed_word('', 'c')
    assert not td11.check_guessed_word('centralesupelec', '')
    assert not td11.check_guessed_word('centralesupelec', 'cs')
    assert td11.check_guessed_word('centralesupelec', 'centralsup')
    assert td11.check_guessed_word('centralesupelec', 'supcentral')

def test_calc_score():
    assert td11.calc_score('', 0) == 0
    assert td11.calc_score('guess', 4) == 9
    assert td11.calc_score('guess', 8) == 5

Fichier td11.py

import random

def raw_version() :
    AA = ("python", "information", "systems", "programming", "centralesupelec")
    a = random.choice(AA)
    b = ''
    c = 10
    while c > 0:
        d = 0
        for e in a:
            if e in b:
                print(e)
            else:
                print("*")
                d += 1
        if d == 0:
            print("You won")
            break
        f = input("guess a character:")
        b += f
        if f not in a:
            c -= 1
            print("Wrong, you have ", + c, "more guesses")
            if c == 0:
                print("You Lost, the word was: " + a)

def clean_version() :
    words = ("python", "information", "systems", "programming", "centralesupelec")
    word = random.choice(words)
    guessed = ''
    rem_turns = 10
    while rem_turns > 0:
        nb_missing = 0
        for letter in word:
            if letter in guessed:
                print(letter)
            else:
                print("*")
                nb_missing += 1
        if nb_missing == 0:
            print("You won")
            break
        guess = input("guess a character:")
        if guess not in word:
            rem_turns -= 1
            if rem_turns == 0:
                print("Wrong guess, you lose, the word was: " + word)
            else:
                print("Wrong, you have ", + rem_turns, "more guesses")
        else :
            guessed += guess

# Structured version
def print_check(word, guessed) :
    wins = True
    for letter in word:
        if letter in guessed:
            print(letter)
        else:
            print("*")
            wins = False
    return wins

def check_guess(guess, word, turns) :
    good_guess = True
    if guess not in word :
        turns -= 1
        good_guess = False
        if turns == 0:
            print("Wrong guess, you lose, the word was: " + word)
        else:
            print("Wrong, you have ", + turns, "more guesses")
    return (good_guess, turns)

def simple_game(word, turns) :
    guessed = ''
    rem_turns = turns
    while rem_turns > 0:
        if print_check(word, guessed) :
            print("You win!")
            break
        guess = input("guess a character:")
        (good_guess, rem_turns) = check_guess(guess, word, rem_turns)
        if good_guess:
            guessed += guess

# simple_game(random.choice(("python", "information", "systems", "programming", "centralesupelec")), 9)

# Full version
# Ex 5
def get_guessed_word(secret_word, letters_guessed):
    masked_word = ""
    for l in secret_word :
        if l in letters_guessed :
            masked_word += l
        else:
            masked_word += '*'
    return masked_word

# Ex 6
def check_guessed_word(secret_word, letters_guessed) :
    return "*" not in get_guessed_word(secret_word, letters_guessed)

# Ex 7
def word_game(secret_word, max_guesses) :
    letters_guessed = ''
    available_letters = [chr(i) for i in range(ord('a'), ord('z') + 1)]
    num_guesses = 0
    while not check_guessed_word(secret_word, letters_guessed) \
      and num_guesses < max_guesses :
        print(max_guesses - num_guesses, " guesses left")
        print("available letters: ", available_letters)
#        guess = input("Your guess: ")
        guess = validate_input(input("Your guess: "))
        num_guesses += 1
        if guess in available_letters :
            available_letters.remove(guess)
            if guess in secret_word :
                letters_guessed += guess
                print("Good: ", get_guessed_word(secret_word, letters_guessed))
            else:
                print("Sorry: ", get_guessed_word(secret_word, letters_guessed))
        else:
            print("Be careful, just just wasted a guess on an already tested letter!")

    if check_guessed_word(secret_word, letters_guessed) :
        return num_guesses
    else:
        return -1

# Ex 8
def calc_max_guesses(secret_word) :
    # Allow two guesses for each distinct letter
    return len(set(secret_word)) * 2

scrabble_values = {
    'a': 1, 'b': 3,'c': 3, 'd': 2, 'e': 1,'f': 4,'g': 2,'h': 4,'i': 1,
    'j': 8,'k': 5,'l': 1,'m': 3,'n': 1,'o': 1,'p': 3,'q': 10,'r': 1,'s': 1,
    't': 1,'u': 1,'v': 4,'w': 4,'x': 8,'y': 4, 'z': 10
}

def calc_score(secret_word, num_guesses, letter_values = scrabble_values) :
    score = 0
    for l in set(secret_word):
        score += letter_values[l]
    score += calc_max_guesses(secret_word) - num_guesses
    return score


def real_word_game(secret_word) :
    n = word_game(secret_word, calc_max_guesses(secret_word))
    if n < 0 :
        print("You lose.")
    else:
        print("You win with score: ", calc_score(secret_word, n))

def validate_input(l) :
    if l.isalpha() :
        return l
    else:
        return validate_input(input("# Invalid input, please type only letters: "))

# Ex 10
def guess_whole_word(secret_word):
    guess = validate_input(input("guess a word: "))
    if guess == secret_word :
        return 0 # As if guessed in no turn
    else:
        return -1

def word_game_w(secret_word, max_guesses) :
    letters_guessed = ''
    available_letters = [chr(i) for i in range(ord('a'), ord('z') + 1)]
    num_guesses = 0
    while not check_guessed_word(secret_word, letters_guessed) \
      and num_guesses < max_guesses :
        print(max_guesses - num_guesses, " guesses left")
        print("available letters: ", available_letters)
        guess = input("Your guess, or * for guessing the whole word: ")
        if guess == "*":
            return guess_whole_word(secret_word)
        guess = validate_input(guess)
        num_guesses += 1
        if guess in available_letters :
            available_letters.remove(guess)
            if guess in secret_word :
                letters_guessed += guess
                print("Good: ", get_guessed_word(secret_word, letters_guessed))
            else:
                print("Sorry: ", get_guessed_word(secret_word, letters_guessed))
        else:
            print("Be careful, just just wasted a guess on an already tested letter!")

    if check_guessed_word(secret_word, letters_guessed) :
        return num_guesses
    else:
        return -1

def real_word_game_w(secret_word) :
    n = word_game_w(secret_word, calc_max_guesses(secret_word))
    if n < 0 :
        print("You lose.")
    else:
        print("You win with score: ", calc_score(secret_word, n))

# Ex 11
def random_word_game(secret_word, max_guesses) :
    letters_guessed = ''
    available_letters = [chr(i) for i in range(ord('a'), ord('z') + 1)]
    num_guesses = 0
    while not check_guessed_word(secret_word, letters_guessed) \
      and num_guesses < max_guesses :
        print(max_guesses - num_guesses, " guesses left")
        print("available letters: ", available_letters)
        guess = random.choice(available_letters)
        num_guesses += 1
        available_letters.remove(guess)
        if guess in secret_word :
            letters_guessed += guess
            print(guess, " is good: ", get_guessed_word(secret_word, letters_guessed))
        else:
            print(guess, " is not in the word: ", get_guessed_word(secret_word, letters_guessed))

    if check_guessed_word(secret_word, letters_guessed) :
        return num_guesses
    else:
        return -1

# Ex 12
def match(word, guess_pattern, letters_tried):
    """
    Check if a word is a possible solution according to the guess pattern
    and the letters that have already been tried.
    :param word: the word to test
    :param guess_pattern: the guess pattern, which is the secret word with '*' in place of not yet guessed letters
    :param letters_tried: the letters that have already been tried to guess the secret word
    :return: True if the word can be the secret word, else False
    """
    if len(word) != len(guess_pattern) :
        # If the word does not have the right length, we can reject it
        return False
    for i in range(len(guess_pattern)) :
        # Check if the word matches the current guess (with '*' in place of not yet guessed characters)
        if guess_pattern[i] != "*" and guess_pattern[i] != word[i] :
            return False
        # Ignore words that contains already tried letters which are not in the pattern
        if not word[i] in guess_pattern and word[i] in letters_tried :
            return False
    return True

def probabilities(guess_pattern, letters_tried, dic):
    # Filter out words that cannot be the secret one
    possible_words = [word for word in dic if match(word, guess_pattern, letters_tried)]
    print("# possibilities for ", guess_pattern, ": ", possible_words)
    # Count the number of occurrences of a character
    frequencies = {}
    for word in possible_words :
        for c in word :
            if c in letters_tried :
                # Ignore already characters that have already been tried
                continue
            if c in frequencies :
                frequencies[c] += 1
            else:
                frequencies[c] = 1
    print("# freq for ", guess_pattern, ": ", frequencies)
    # Get the total number of distinct characters
    total_chars = sum(frequencies.values())
    # Fill the table of probabilities
    prob = {}
    for c in frequencies.keys() :
        prob[c] = frequencies[c] / total_chars
    return prob

def ai_word_game(secret_word):
    with open("../dic.txt", "r") as dict_file :
        words = dict_file.read().lower().splitlines()
        dic = [word.replace("-", "").replace("-", "") for word in words]
    letters_tried = ''
    num_guesses = 0
    max_guesses = calc_max_guesses(secret_word)

    while num_guesses < max_guesses \
      and not check_guessed_word(secret_word, letters_tried) :
        probs = probabilities(get_guessed_word(secret_word, letters_tried), letters_tried, dic)
        guess = max(probs, key=probs.get)
        num_guesses += 1
        letters_tried += guess
        if guess in secret_word :
            print(guess, " is good: ", get_guessed_word(secret_word, letters_tried))
        else:
            print(guess, " is not in the word: ", get_guessed_word(secret_word, letters_tried))

    if check_guessed_word(secret_word, letters_tried) :
        print("AI wins with score: ", calc_score(secret_word, num_guesses))
    else:
        print("AI loses.")