Python - NIM Game

5

Statement

You should write a program in the Python language, version 3, which will allow a "victim" to play the NIM against the computer. The computer, of course, should follow the winning strategy described above.

Let n be the starting part number and m for the maximum number of pieces that can be removed in a round. To ensure that the computer always wins, consider the two possible scenarios for starting the game:

If n is multiple of (m + 1) , the computer must be "generous" and invite the player to start the game. Otherwise, the computer takes the initiative to start the game. Once the game is started, the strategy of the computer to win is to always leave a number of pieces that are multiple of (m + 1) to the player. If this is not possible, you should take out as many pieces as possible.

Your job, then, is to implement the Game and get the computer to use the winning strategy.

Your Program

With the purpose of the already defined EP, a doubt that must arise at the moment is how to model the game in a way that can be implemented in Python 3, corresponding strictly to the specifications described so far.

In order to facilitate its work and allow the automatic correction of the exercise, we present below a model, that is, a general description of a set of functions that solves the problem proposed in this EP. Although other approaches are possible, you must meet exactly what is defined below for automatic job matching to work correctly.

The program should implement:

  • A computador_escolhe_jogada function that receives as parameters the n and m numbers described above and returns an integer corresponding to the next move of the computer according to with the winning strategy.

  • A usuario_escolhe_jogada function that receives the same parameters, prompts the player to report his move and check if the value entered is valid. If the value entered is valid, the function should return it; otherwise, you must prompt the user again to enter a valid move.

  • A partida function that does not receive any parameters prompts the user to enter the n and m values and starts the game by switching between plays the computer and the user (that is, calls to the two previous functions). The choice of the initial move must be made according to the winning strategy, as said before. At each play, the current state of play must be printed on the screen, ie how many pieces were removed on the last play and how many are left on the table. When the last part is removed, this function prints the message " The computer won!" Or " You won! " as the case may be.

Note that for this to work, your program should always "remember" what is the number of pieces currently on the board and what is the maximum number of pieces to take out on each move.

Championships

As we all know, a single round of a game is not enough to define who is the best player. So, since the partida function is working, you should create another function called campeonato . This new role must carry out three consecutive games of the game and, at the end, show the score of those three matches and indicate the winner of the championship. The scoreboard should be printed on the form

Code

computador = 0
usuario = 0
rodada = 0

def computador_escolhe_jogada(n, m):
    global computador
    n = n - m
    if (n == 1):
        print(" ")
        print("O computador tirou %s peça." % n)
        print("Agora restam %s peças no tabuleiro." % n)
        print(" ")
        if (n == 0):
            print ("Fim do jogo! O computador ganhou!")
            partida()
    else:
        print(" ")
        print("O computador tirou %s peça." % m)
        print("Agora restam %s peças no tabuleiro." % n)
        print(" ")
        if (n == 0):
            print ("Fim do jogo! O computador ganhou!")
            partida()
    return n
    return m


def usuario_escolhe_jogada(n, m):
    global usuario
    print(" ")
    n_user = int(input("Quantas peças você vai tirar? "))
    print("Voce tirou %s peças." % n_user)
    if (n_user <= m):
        n = n - m
        print(" ")
        print("Agora restam apenas %s peças no tabuleiro." % n)
    else:
        while (n_user > m):
            print("Oops! Jogada inválida! Tente de novo.")
            print(" ")
            n_user = int(input("Quantas peças você vai tirar? "))
    if (n == 0):
        print ("Vitoria do usuario")
    return n_user
    return n
    return m

def partida():
    global computador
    global usuario
    global rodada
    while(rodada <= 3):
        rodada = rodada + 1
        if (rodada <= 3 ):
            print(" ")
            print("**** Rodada %s ****" % rodada)
            print(" ")
            n = int(input("Quantas peças? "))
            m = int(input("Limite de peças por jogada? "))
            if (((n )%(m + 1)) == 0):
                while (n > 0):
                    print(" ")
                    print("Voce começa!")
                    usuario_escolhe_jogada(n,m)
                    if n > 0:
                        n = n - m    
                    computador_escolhe_jogada(n,m)
                    n = n - m
                    computador = computador + 1
            else:
                print(" ")
                print("Computador Começa!!")
                while( n > 0):
                    computador_escolhe_jogada(n,m)
                    computador = computador + 1
                    n = n - m
                    if n > 0:
                        usuario_escolhe_jogada(n,m)
                        n = n - m
        else:
            print("**** Final do campeonato! ****")
            print(" ")
            print("Fim de Campeonato: Computador %s x 0 Usuario " % computador)
        break

print("Bem-vindo ao jogo do NIM! Escolha:")
print(" ")
print("1 - para jogar uma partida isolada ")
tipo_jogo = int(input("2 - para jogar um campeonato "))
print(" ")
if ( tipo_jogo == 1 ):
    print("Voce escolheu partida isolada!")
if ( tipo_jogo == 2):
    print("Voce escolheu um campeonato!")
    partida()
else:
    pass

My problem is when the user starts the game, for example: if I put N = 3 and M = 2 , the user should start, maximum of pieces (two), the computer also removes two, leaving a number of negative pieces on the table and closes the championship.

    
asked by anonymous 15.02.2017 / 01:51

4 answers

3

Selecting the game type

First, let's solve the problem of knowing which type of game to play: partida or campeonato . Your logic works great in this part, so let's keep it.

tipo_jogo = 0

# Enquanto não for uma opção válida:
while tipo_jogo == 0:

    # Menu de opções:
    print("Bem-vindo ao jogo do NIM! Escolha:")
    print(" ")
    print("1 - Para jogar uma partida isolada")
    print("2 - Para jogar um campeonato")

    # Solicita a opção ao usuário:
    tipo_jogo = int(input("Sua opção: "))
    print(" ")

    # Decide o tipo de jogo:
    if tipo_jogo == 1:
        print("Voce escolheu partida isolada!")
        partida()
        break
    elif tipo_jogo == 2:
        print("Voce escolheu um campeonato!")
        campeonato()
        break
    else:
        print("Opção inválida!")
        tipo_jogo = 0

The structure with while is basically to repeat as long as the user does not enter a valid option. When it is 1, the partida function is called. When it is 2, the campeonato function is called.

Function partida

Now let's define the partida function. As requested, the function has no parameters and should prompt the user for the n and m values, starting the game after that.

def partida():

    print(" ")

    # Solicita ao usuário os valores de n e m:
    n = int(input("Quantas peças? "))
    m = int(input("Limite de peças por jogada? "))

    # Define uma variável para controlar a vez do computador:
    is_computer_turn = True

    # Decide quem iniciará o jogo:
    if n % (m+1) == 0: is_computer_turn = False

    # Execute enquanto houver peças no jogo:
    while n > 0:

        if is_computer_turn:
            jogada = computador_escolhe_jogada(n, m)
            is_computer_turn = False
            print("Computador retirou {} peças.".format(jogada))
        else:
            jogada = usuario_escolhe_jogada(n, m)
            is_computer_turn = True
            print("Você retirou {} peças.".format(jogada))

        # Retira as peças do jogo:
        n = n - jogada

        # Mostra o estado atual do jogo:
        print("Restam apenas {} peças em jogo.\n".format(n))

    # Fim de jogo, verifica quem ganhou:
    if is_computer_turn:
        print("Você ganhou!")
        return 1
    else:
        print("O computador ganhou!")
        return 0

The logic of it is very simple and self explanatory by the comments of the code. You are prompted for the values of n and m . Verify who will start: if n is a multiple of m + 1 , then the user starts, so the variable is_computer_turn becomes false. Performs while while there are parts in the game, that is n > 0 . It verifies, through the variable is_computer_turn , of who is the one and calls its respective function, returning the quantity of pieces that have been taken. It discounts the total value of parts, n = n - jogada and returns to the beginning of loop . When n = 0 , the loop is terminated, giving the game as finished. If it was over at the time of the computer, it means that the user took the last piece and won, otherwise it was the computer that took the last piece, winning the game.

Function usuario_escolhe_jogada

The simplest function of the game. It asks the user for the number of pieces he wants to remove. If it is a valid number, that is, greater than 0, less than or equal to m , maximum number of pieces per round, and less than or equal to n , current number of pieces in the game. While the number is not valid, continue requesting.

def usuario_escolhe_jogada(n, m):

    # Vez do usuário:
    print("Sua vez!\n")

    # Define o número de peças do usuário:
    jogada = 0

    # Enquanto o número não for válido
    while jogada == 0:

        # Solicita ao usuário quantas peças irá tirar:
        jogada = int(input("Quantas peças irá tirar? "))

        # Condições: jogada < n, jogada < m, jogada > 0
        if jogada > n or jogada < 1 or jogada > m:

            # Valor inválido, continue solicitando ao usuário:
            jogada = 0

    # Número de peças válido, então retorne-o:
    return jogada

Function computador_escolhe_jogada

The idea is to always make the computer win. So the first condition we have is: Can the computer remove all parts (% with%)? If so, return the value of n , that is, all the remaining pieces of the game. Otherwise, the computer will always try to keep the number of parts being multiple of m + 1 , so the user can not win. This condition is calculated by computing the remainder of n division with m + 1 . It will always be a value between 0 and m , inclusive. If it is greater than 0, then it will be the number of pieces the computer needs to take so that n is multiplied by m + 1 . If it is 0, there is no way to leave a multiple, then remove as much as you can, m .

def computador_escolhe_jogada(n, m):

    # Vez do computador:
    print("Vez do computador!")

    # Pode retirar todas as peças?
    if n <= m:

        # Retira todas as peças e ganha o jogo:
        return n

    else:

        # Verifica se é possível deixar uma quantia múltipla de m+1:
        quantia = n % (m+1)

        if quantia > 0:
            return quantia

        # Não é, então tire m peças:
        return m

Function n < m

The championship function will only run three times the campeonato function and post the score:

def campeonato():

    # Pontuações:
    usuario = 0
    computador = 0

    # Executa 3 vezes:
    for _ in range(3):

        # Executa a partida:
        vencedor = partida()

        # Verifica o resultado, somando a pontuação:
        if vencedor == 1:
            # Usuário venceu:
            usuario = usuario + 1
        else:
            # Computador venceu:
            computador = computador + 1

    # Exibe o placar final:
    print("Placar final: Você  {} x {}  Computador".format(usuario, computador))
  

See the full Ideone code, also at Repl.it or even the GitHub Gist .

    
15.02.2017 / 03:22
0

The strings (texts for the user) must be exactly the same as the example of the game played. And there is more, the message "You start" or "Computer starts" should only appear once! Otherwise the autocorretor will accuse 'should start with ...'

def partida():
    # Solicita os valores de n e m
    n = int(input("Quantas peças? "))
    m = int(input("Limite de peças por jogada? "))
    # Define um controlador para quem irá começar o jogo
    x = n % (m + 1)
    # Define um controlador para mensagem que avisa quem irá começar
    primeira_vez_usuario = False
    primeira_vez_computador = False

    if x != 0: # Define que o computador irá começar
        pcJoga = True
        primeira_vez_computador = True # Define que é a primeira jogada do computador
    if x == 0: # Define que o usuário irá começar
        pcJoga = False
        primeira_vez_usuario = True # Define que é a primeira jogada do usuário
    # Entuanto tiver peças(n) no jogo...
    while n > 0:
        if pcJoga == True: # Verifica se o computador começa
            if primeira_vez_computador == True: # Verifica se é a primeira vez do computador
                print("")
                print("Computador começa!")
                print("")
            primeira_vez_computador = False # Define que o computador já jogou a primeira vez
            # Variavel recebendo retorno do número de peças que o computador tirou
            vlr_tirado = computador_escolhe_jogada(n,m)
            # Define que é a vez do usuário
            pcJoga = False
            # Definindo se a mensagem é ficará no singular ou no plural
            if vlr_tirado == 1:
                print("O computador tirou uma peça")
            else:
                print("O computador tirou ",vlr_tirado," peças.")
        else: # Se não for o computador quem começa, então é o usuario...
            # Verifica se é a primeira vez do usuário
            if primeira_vez_usuario == True:
                print("")
                print("Voce começa!")
                print("")
            primeira_vez_usuario = False # Define que o usuário já jogou a primeira vez
            # Variavel recebendo retorno do número de peças que o usuário tirou
            vlr_tirado = usuario_escolhe_jogada(n,m)
            # Define que é a vez do computador
            pcJoga = True
            # Definindo se a mensagem é ficará no singular ou no plural
            if vlr_tirado == 1:
                print("Você tirou uma peça")
            else:
                print("Voce tirou",vlr_tirado,"peças.")
        n = n - vlr_tirado # Remove do tabuleiro as respectivas peças tirada de cada rodada.
        # Para não mostrar que restam 0 peças
        if n > 0:
            print("Agora restam",n,"peças no tabuleiro.")
            print("")
    # Verifica quem jogou por último, e mostra a mensagem respectiva
    if pcJoga == True:
        print("Fim do jogo! Você ganhou!")
        print("")
        return 1 # ID para contabilizar quantas partidas o usuário ganhou no campeonato
    else:
        print("Fim do jogo! O computador ganhou!")
        print("")
        return 0 # ID para contabilizar quantas partidas o computador ganhou no campeonato


# Função que retorna quantas peças o usuário irá tirar do tabuleiro
def usuario_escolhe_jogada(n,m):
    vlr_tirado = 0
    # Enquanto o usuário não digitar um valor válido, ficará preço aqui
    while vlr_tirado == 0:
        vlr_tirado = int(input("Quantas peças você vai tirar?"))
        # Verifica se o valor digitado pelo usuário é valido
        if vlr_tirado > n or vlr_tirado > m or vlr_tirado < 1 :
            print("")
            print("Oops! Jogada inválida! Tente de novo.")
            print("")
            vlr_tirado = 0 # Se for inválido mostra a msg e retorna para o loop
    return vlr_tirado # Se não, retorna o valor tirado


# Função que retorna quantas peças o computador irá tirar do tabuleiro
def computador_escolhe_jogada(n,m):
    if n <= m: # Se o numero de peças for menor que o máximo
        return n # Apenas retorna o mesmo numero de peças para tirar e ganhar logo
    else:
        sobrou = n % (m+1) # sobrou recebe o resto da divisão
        if sobrou > 0:  # Já que não é menor que m, e maior que 0 então...
            return sobrou # retorne o resto
        return m # Se não, retorne o máximo de peças possíveis


# Função que chama partida 3 vezes
def campeonato():
    # Define um controle de placar
    computador = 0
    usuario = 0
    # Define um controle de partidas
    i = 1
    for _ in range(3):
        print("**** Rodada",i,"****")
        print("")
        id_ganhou = partida()
        i = i + 1 # Conta as partidas
        if id_ganhou == 1:
            usuario = usuario +1 # Conta pontos para usuário no placar
        else:
            computador = computador + 1 # Conta pontos para o computador no placar
    print("**** Final do campeonato! ****")
    # Mostra os respectivos placares...
    print("Placar: Você",usuario,"X",computador,"Computador")

# O programa começa aqui, o usuário irá definir a modalidade
escolha = 0
while escolha == 0:
    print("")
    print("Bem-vindo ao jogo do NIM! Escolha:")
    print("")
    print("1 - para jogar uma partida isolada")
    print("2 - para jogar um campeonato 2")
    escolha = int(input())
    if escolha == 1:
        partida() #Inicia uma partida
        break
    elif escolha == 2:
        print("Voce escolheu um campeonato!")
        print("")
        campeonato() # Inicia um campenato
        break
    else:
        print("Escolha uma opção válida!")
        print("")
        escolha = 0 # Volta para o loop, enquanto não escolher 1 ou 2
    
16.05.2017 / 05:27
0

Fixed according to Strings requested and running 100%:

def campeonato():
usuario = 0
computador = 0
x = 1
for _ in range(3):
    print("\n**** Rodada {} ****\n".format(x))
    x = x + 1
    vencedor = partida()
    if vencedor == 1:
        usuario = usuario + 1
    else:
        computador = computador + 1
print("\n**** Final do campeonato! ****\n")
print("Placar: Você {} x {} Computador".format(usuario, computador))

def computador_escolhe_jogada(n, m):
if n <= m:
    return n
else:
    quantia = n % (m+1)
    if quantia > 0:
        return quantia
return m

def usuario_escolhe_jogada(n, m):
jogada = 0
while jogada == 0:
    jogada = int(input("Quantas peças você vai tirar? "))
    if jogada > n or jogada < 1 or jogada > m:
        print("\nOops! Jogada inválida! Tente de novo.\n")
        jogada = 0
return jogada

def partida():
n = int(input("Quantas peças? "))
m = int(input("Limite de peças por jogada? "))

is_computer_turn = True

if n % (m+1) == 0: 
    is_computer_turn = False
    print("\nVocê começa!\n")
else:
    print("\nComputador começa!\n")

while n > 0:

    if is_computer_turn:
        jogada = computador_escolhe_jogada(n, m)
        is_computer_turn = False
        if(jogada == 1):
            print("\nO computador tirou uma peça.")
        else:
            print("\nO computador tirou {} peças.".format(jogada))
    else:
        jogada = usuario_escolhe_jogada(n, m)
        is_computer_turn = True
        if(jogada == 1):
            print("\nVocê tirou uma peça.")
        else:
            print("\nVocê tirou {} peças.".format(jogada))


    n = n - jogada

    if(n == 1):
        print("Agora resta apenas uma peça no tabuleiro.\n")
    elif(n > 1):
        print("Agora restam {} peças no tabuleiro.\n".format(n))

if is_computer_turn:
    print("Fim do jogo! Você ganhou!")
    return 1
else:
    print("Fim do jogo! O computador ganhou!")
    return 0

    tipo_jogo = 0
while tipo_jogo == 0:
    tipo_jogo = (int(input("Bem-vindo ao jogo do NIM! Escolha: \n\n1 - para jogar uma partida isolada \n2 - para jogar um campeonato ")))
    if ( tipo_jogo == 1 ):
        print("\nVoce escolheu partida isolada!")
        partida()
        break
    elif ( tipo_jogo == 2):
        print("\nVoce escolheu um campeonato!")
        campeonato()
        break
    else:
        print("Opção inválida!")
        tipo_jogo = 0
    
23.08.2017 / 19:29
-2

**** Start def function ****

I made a small change in the match def () because when I executed, regardless of the result of the division, the game was always started by the computer. Below my change:

is_computer_turn = True
    if x != 0:
        is_computer_turn = True
        print("O computador começa!") 
    if x == 0:
        is_computer_turn = False
        print("Você começa!")
    
14.05.2017 / 16:45