Python - NIM game

Asked

Viewed 13,183 times

5

Enunciation

You must 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, must follow the winning strategy described above.

Be n the initial part number and m the maximum number of pieces it is possible to remove in a round. To ensure that the computer always wins, you need to consider the two possible scenarios for the start of 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 computer’s winning strategy is to always leave a number of tiles that is multiple of (m+1) to the player. If this is not possible, you should take as many pieces as possible.

Your job, then, will be to implement the Game and make the computer use the winning strategy.

Your Program

With the objective of the EP already defined, a doubt that should arise at this time is how to model the game so that it can be implemented in Python 3 corresponding rigorously to the specifications described so far.

To facilitate their 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, it is necessary to meet exactly what is set below for the automatic work correction to work properly.

The program must implement:

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

  • A function usuario_escolhe_jogada which receives the same parameters, prompts the player to inform his move and checks whether the given value is valid. If the given value is valid, the function must return it; otherwise, it must ask the user again to enter a valid move.

  • A function partida which does not receive any parameter, prompts the user to enter the values of n and m and starts the game by switching between plays of 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 stated above. With each move, the current state of the game must be printed on the screen, that is, how many pieces were removed in the last move and how many remain on the table. When the last tile is removed, this function prints the message on the screen "The computer won!" or "You won!" as appropriate.

Note that in order for this to work, your program must always "remember" what the number of pieces is currently on the board and what is the maximum number of pieces to remove on each turn.

Championships

As we all know, a single round of a game is not enough to define who is the best player. So, once the function partida is working, you must create another function called campeonato. This new function must hold three consecutive matches of the game and, at the end, show the score of these three matches and indicate the winner of the championship. The scoreboard should be printed in 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 match, for example: if I put N=3 and M=2, the user must start, when user takes out the maximum parts (two), the computer also takes out two, getting a number of negative pieces on the table and ends the championship.

  • Not the same as: http://answall.com/questions/177176?

  • It is the same, but I have been asked a new question. His game does not follow the requested parameters and information is missing when comparing the print, besides the issue is not solved.

  • Is that all the statement of the problem? What would be "take a piece"?

  • The statement is huge, but in the link that Voce reported above, already contains a part. According to the code and the print, when starting the match, the game asks the "n" number of pieces and "m" maximum of pieces.

  • Great, but essensial to understand the problem. I do not know why removed from the other.

  • I’ll try to edit and add to help.

  • I have already read the other, but in my view it is essential to have. I will analyze your code here.

  • added the question.

  • Why are there several return in each function?

  • Teacher’s answer : You are not returning anything in the Xxx_choice move functions. You will need to change your program so that match() call the functions alternately by receiving from each the value of the current move.

  • Curiosity: What course is and what is your level of knowledge in programming?

  • Coursera, Python from USP. I’m a beginner friend.

  • 1

    I edited the question to an acceptable format, within Sopt standards.

  • Thanks for the support! I noticed that the calculation of the computer’s move is wrong, I put a print(n) at the beginning of the computer_chooses function and I realized that n ends up being negative, and this impacts on the result, regardless of who starts it.

  • I’m responding slowly, keep up with you.

  • As a matter of curiosity, I started to check the possibility of whoever wins in a NIM match from a video (I think this one). For NIM with a stack and taking out up to three pieces, there is only one possibility that whoever wins will be second. I made this demonstration in Java, in this project here

Show 11 more comments

5 answers

4


Selecting the type of game

First, we will solve the problem of knowing which type of game will be run: partida or campeonato. Your logic works very well on 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 the while is basically to repeat while the user does not enter a valid option. When it is 1, the function partida is called. When it is 2, the function campeonato is called.

Function partida

Now let’s define the function partida. As requested, the function has no parameters and must ask the user for the values of n and m, starting the game after this.

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

Its logic is very simple and self-explanatory by the comments of the code. The user is asked the values of n and m. Check who will start: if n is multiple of m+1, then the user starts, so the variable is_computer_turn becomes false. Executes a while as long as there are pieces in the game, that is, n > 0. Check, through the variable is_computer_turn, whose turn it is and calls the respective function, returning the number of pieces that were taken. It is deducted from the total value of pieces, n = n - jogada and back to the beginning of loop. When n = 0, closes the loop, giving the game as finalized. If it ended instead 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. Prompts 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 tiles in the game. As long as 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 always to make the computer win. So the first condition we have is: the computer can take out all the pieces (n < m)? If yes, return the value of n, that is, all remaining pieces of the game. Otherwise, the computer will always seek to keep the number of pieces being multiple of m+1, so that the user cannot win. This condition is made by calculating the rest of the n for 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 that the computer needs to take n becomes a multiple of m+1. If it’s 0, there’s no way to leave a multiple, so take 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 campeonato

The championship function will only perform three times the function partida and count 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 code on Ideone, also in the Repl.it or in the Github Gist.

  • Good morning Anderson, interesting this "if n % (m+1) == 0: is_computer_turn = False" unknown.

  • 1

    Is a if normal, but as it has only one instruction, it can be written inline.

  • Got it! In my logic, regardless of who initiated, the computer ended up choosing an incorrect value and it was only possible to visualize with print(n) at the beginning of the function. Its logic corrects decision making and the computer starts to choose the correct value. Thank you very much for the support, teaching and clarity of the code.

  • What usually causes strangeness is to use the character _ in the for, in function campeonato. It’s kind of a convention in Python when the iteration value doesn’t really matter, as in this case. We only need to run it 3 times, no matter what match is running with.

  • I was surprised, but I treated it like the famous "I" is. It is still possible to use it to print the round already increasing its volor at each wheel.

  • Yes, it works as a normal variable, but it is already explicit that it is not fundamental to subsequent logic. Different would be if you used it as an index of a vector, then it would be better to use the i, or similar. As the The Zen of Python, Explicit is Better than implicit..

  • I understood, I believe and now I know that I must use a lot in the course of my learning. Another new thing for me was the use of . format(xxx), also unknown, because studying books I learned to use the %s. Thank you very much!

  • 1

    Then be enchanted with that.

  • Raccoon... what a time!!

Show 4 more comments

0

The strings (text for the user) have to be exactly the same as the game worked example. What’s more, the message "You start" or "Computer starts" should appear only once! Otherwise the auto-corrector will accuse that 'should begin with the...'

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
  • looking quickly has an infinite loop failure in user

0

Fixed according to Requested Strings 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

-1

def main(): print(') print('Welcome to the NIM game! Choose:') print(') n = None while True: print('1 - for isolated departure:') print('2 - for championship') n = int(input(')) if n == 1: print(' nVoce chose an isolated match!') departure() break Elif n == 2: print(' nVoce chose a championship!') championship() break Else: print(' Invalid print status!')

def partida(): print(') n = int(input('How many pieces? ')) m = int(input('Tile limit per move? '))

liga_pc = True

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

while n > 0:
    if liga_pc :
        a = computador_escolhe_jogada(n,m)
        liga_pc  = False
        if a == 1:
            print('O computador tirou uma peça.')
        else:
            print('O computador tirou {} peças.'.format(a))
    else:
        a = usuario_escolhe_jogada(n,m)
        liga_pc  = True
        if a == 1:
            print('\nVocê tirou uma peça.')
        else:
            print('\nvocê tirou {} peças.'.format(a))
    n = n - a
    

    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 liga_pc:
    print("Fim do jogo! Você ganhou!")
    return 1
else:
    print("Fim do jogo! O computador ganhou!")
    return 0

def campeonato():

a = 1
usuario = 0
computador = 0

while a <= 3:
    print('\n**** Rodada {} ****'.format(a))
    vencedor = partida()

    if vencedor == 1:

        usuario = usuario + 1
    else:
        computador = computador + 1
    
    a = a + 1
print("\n**** Final do campeonato! ****\n")
print('Placar final: você {} x {} Computador'.format(usuario,computador))

def usuario_play_choice(n,m):

jogada = 0

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

def computer_play_choice(n,m):

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

execute = main()

-2

****Function def broken****

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

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!")
  • 1

    What were your input values? Remember that the logic of the game will cause the computer to start most of the time. If n is multiple of m+1, for example, n=6 and m=2, will be the user who will start the game. In my solution this seems to be working perfectly. It has how to improve your answer and better describe what was the problem you solved?

  • Hello Andreson, qqer value I informed the computer started the game, I found it very strange and was doing tests until I got the solution I shared ( that may not necessarily be the best, more worked). Thank you for your comment.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.