How do you make this code more readable for someone who doesn’t know anything about programming?

Asked

Viewed 118 times

2

I will present this code to my math teacher (who knows only algorithms, no Python or any programming language). I’m a beginner in Python, so I know there must be a simpler way to make the code. The script is a game between two players. It generates random numbers to be multiplied. The one who hits the highest number between the two wins. If the two have the same number of hits, the victory goes to the one who needed less time to answer.

from time import time, sleep
from random import randint
# Listas do jogador 1
gabarito_j1 = list()  # Lista com respostas da multiplicação
respostas_j1 = list()  # Lista com os inputs do usuário
resultado_j1 = list()  # Lista comparando gabarito e repostas
tempo_j1 = list()  # Lista com o tempo levado pelo usuário
# Listas do jogador 2
gabarito_j2 = list()
respostas_j2 = list()
resultado_j2 = list()
tempo_j2 = list()

rodadas = int(input('Insira o número de rodadas: '))
while True:  # Loop infinito para min_range >= max_range
    max_range = int(input('Insira o maior número possível dentre os aleatórios: '))
    min_range = int(input('Insira o menor número possível dentre os aleatórios: '))
    if max_range > min_range:
        break
    else:
        print('Valor inválido. Tente novamente.')

for j in range(0, 2):
    # j varia de acordo com o jogador. j = 0: jogador 1, j = 1: jogador 2
    if j == 0:
        print('\nJOGADOR 1')
        sleep(3)
    elif j == 1:
        print('\nJOGADOR 2')
        sleep(5)

    for c in range(0, rodadas):
        # Código será executado pelo valor da variável 'rodadas'
        print('-=' * 15)
        sleep(1)
        print('Ache o valor de x')
        sleep(1)
        # Gerando os números aleatórios
        n1 = int(randint(min_range, max_range))
        n2 = int(randint(min_range, max_range))
        print(f'x = {n1} * {n2}')
        inicio = time()  # Início da contagem do tempo
        n = int(input('Insira o valor de x: '))
        fim = time()  # Fim da contagem do tempo
        tempo_total = fim - inicio
        print(f'Tempo: {tempo_total:.2f} segundos')

        if j == 0:
            gabarito_j1.append(n1 * n2)
            respostas_j1.append(n)
            tempo_j1.append(tempo_total)
        elif j == 1:
            gabarito_j2.append(n1 * n2)
            respostas_j2.append(n)
            tempo_j2.append(tempo_total)

for cont, n in enumerate(gabarito_j1):
    # Se o valor em 'gabarito' for igual ao de 'respostas' "Correto" será adicionado na lista
    # Senão, "Incorreto" será adicionado em resultado_j2
    if respostas_j1[cont] == n:
        resultado_j1.append('Correto')
    else:
        resultado_j1.append('Incorreto')
num_de_acertos_j1 = resultado_j1.count('Correto')

for cont, n in enumerate(gabarito_j2):
    # Se o valor em 'gabarito' for igual ao de 'respostas' "Correto" será adicionado na lista
    # Senão, "Incorreto" será adicionado em resultado_j2
    if respostas_j2[cont] == n:
        resultado_j2.append('Correto')
    else:
        resultado_j2.append('Incorreto')
num_de_acertos_j2 = resultado_j2.count('Correto')
print('')
print('-=' * 30)
print('DADOS DO JOGADOR 1')
print(f'O jogador 1 acertou {num_de_acertos_j1} num total de {(sum(tempo_j1)):.2f} segundos')
print(f'-=' * 30)
print('DADOS DO JOGADOR 2')
print(f'O jogador 2 acertou {num_de_acertos_j2} num total de {(sum(tempo_j2)):.2f} segundos')
print('-=' * 30)

# Analisando casos onde um jogador obteve mais acertos do que outro
if num_de_acertos_j1 > num_de_acertos_j2:
    print(f''
          f'O jogador 1 venceu por {num_de_acertos_j1 - num_de_acertos_j2}'
          f' pontos de diferença')
elif num_de_acertos_j2 > num_de_acertos_j1:
    print(f'O jogador 2 venceu por {num_de_acertos_j2 - num_de_acertos_j1}'
          f' pontos de diferença')

# Analisando casos onde os jogadores empataram e o desempate é no tempo
elif num_de_acertos_j1 == num_de_acertos_j2:
    if sum(tempo_j1) < sum(tempo_j2):
        print(f'O jogador 1 venceu por {(sum(tempo_j2) - sum(tempo_j1)):.2f}'
              f' segundos de diferença')
    elif sum(tempo_j1) > sum(tempo_j2):
        print(f'O jogador 2 venceu por {(sum(tempo_j1) - sum(tempo_j2)):.2f}'
              f' segundos de diferença')

2 answers

3


What you should do is:

  • Make variable names clear and readable, in your case in Portuguese so that your code resembles pseudocode as closely as possible.
  • Use functions on every bit of logic that makes sense, because it gets the whole code divided into small blocks that have an associated name, representing what that block does. In addition, you get an overview of how it works by only reading function calls in your main code.
  • Repeat code as little as possible, as this ends up making it difficult to read and leaves the reader more confused about what the program does.
  • Avoid having magic numbers in the code, which only the author knows its meaning.

These principles are all that must be applied in code refactoring, to leave the code dry, and are valid for your program as for any other.

By applying these ideas in your code, without wasting too much time, I’ve come to this result:

from time import time, sleep
from random import randint

# Listas do jogador 1
gabarito_j1 = list()  # Lista com respostas da multiplicação
respostas_j1 = list()  # Lista com os inputs do usuário
tempo_j1 = list()  # Lista com o tempo levado pelo usuário
# Listas do jogador 2
gabarito_j2 = list()
respostas_j2 = list()
tempo_j2 = list()

JOGADOR1 = 0
JOGADOR2 = 1


def respostas_corretas(gabaritos, respostas):
    corretas = 0
    for gabarito, resposta in zip(gabaritos, respostas):
        if gabarito == resposta:
            corretas += 1

    return corretas


def mostra_dados(num_jogador, num_de_acertos, tempo):
    print('-=' * 30)
    print(f'DADOS DO JOGADOR {num_jogador}')
    print(f'O jogador {num_jogador} acertou {num_de_acertos} num total de {(sum(tempo)):.2f} segundos')


def le_resultado(n1, n2):
    print(f'x = {n1} * {n2}')
    inicio = time()  # Início da contagem do tempo
    valor_lido = int(input('Insira o valor de x: '))
    fim = time()  # Fim da contagem do tempo
    tempo = fim - inicio
    print(f'Tempo: {tempo:.2f} segundos')
    return tempo, valor_lido


def mostrar_vencedor(num_de_acertos_j1, num_de_acertos_j2, tempo_j1, tempo_j2):
    # Analisando casos onde um jogador obteve mais acertos do que outro
    if num_de_acertos_j1 > num_de_acertos_j2:
        print(f'O jogador 1 venceu por {num_de_acertos_j1 - num_de_acertos_j2} pontos de diferença')
    elif num_de_acertos_j2 > num_de_acertos_j1:
        print(f'O jogador 2 venceu por {num_de_acertos_j2 - num_de_acertos_j1} pontos de diferença')  
    else: # Analisando casos onde os jogadores empataram e o desempate é no tempo
        if sum(tempo_j1) < sum(tempo_j2):
            print(f'O jogador 1 venceu por {(sum(tempo_j2) - sum(tempo_j1)):.2f} segundos de diferença')
        elif sum(tempo_j1) > sum(tempo_j2):
            print(f'O jogador 2 venceu por {(sum(tempo_j1) - sum(tempo_j2)):.2f} segundos de diferença')


rodadas = int(input('Insira o número de rodadas: '))
while True:  # Loop infinito para min_range >= max_range
    maximo = int(input('Insira o maior número possível dentre os aleatórios: '))
    minimo = int(input('Insira o menor número possível dentre os aleatórios: '))
    if maximo > minimo:
        break
    print('Valor inválido. Tente novamente.')

for jogador in range(0, 2):
    print(f'JOGADOR {jogador + 1}')
    sleep(3)

    for rodada in range(0, rodadas):
        print('-=' * 15)
        sleep(1)
        print('Ache o valor de x')
        sleep(1)
        # Gerando os números aleatórios
        n1 = int(randint(minimo, maximo))
        n2 = int(randint(minimo, maximo))
        tempo, valor_lido = le_resultado(n1, n2)

        if jogador == JOGADOR1:
            gabarito_j1.append(n1 * n2)
            respostas_j1.append(valor_lido)
            tempo_j1.append(tempo)
        elif jogador == JOGADOR2:
            gabarito_j2.append(n1 * n2)
            respostas_j2.append(valor_lido)
            tempo_j2.append(tempo)

num_de_acertos_j1 = respostas_corretas(gabarito_j1, respostas_j1)
num_de_acertos_j2 = respostas_corretas(gabarito_j2, respostas_j2)
print()
mostra_dados(1, num_de_acertos_j1, tempo_j1)
mostra_dados(2, num_de_acertos_j2, tempo_j2)
print()
mostrar_vencedor(num_de_acertos_j1, num_de_acertos_j2, tempo_j1, tempo_j2)

Note that it now has several functions and looking at the main code it is much easier to get an idea of what the program actually does. In addition you had (and still have) several blocks of code that repeated to both players.

For me as the logic is precisely the same but for each player, I think creating a class for the player encompassing the logic is ideal, because it avoids the global variables it has and some of the repeated code that still exists. Naturally it will be more difficult for those who are not within these programming concepts.

Applying that step would be something like:

from time import time, sleep
from random import randint


class Jogador:
    def __init__(self, numero):
        self.numero = numero
        self.gabaritos = list()  # Lista com respostas da multiplicação
        self.respostas = list()  # Lista com os inputs do usuário
        self.tempos = list()  # Lista com o tempo levado pelo usuário
        self.corretas = 0

    def calcular_respostas_corretas(self):
        self.corretas = 0
        for gabarito, resposta in zip(self.gabaritos, self.respostas):
            if gabarito == resposta:
                self.corretas += 1

    def mostra_dados(self):
        print('-=' * 30)
        print(f'DADOS DO JOGADOR {self.numero}')
        print(f'O jogador {self.numero} acertou {self.corretas} num total de {self.tempo():.2f} segundos')

    def adicionar_resposta(self, conta, valor_lido, tempo_resposta):
        self.gabaritos.append(conta)
        self.respostas.append(valor_lido)
        self.tempos.append(tempo_resposta)

    def tempo(self):
        return sum(self.tempos)


def le_resultado(n1, n2):
    print(f'x = {n1} * {n2}')
    inicio = time()  # Início da contagem do tempo
    valor_lido = int(input('Insira o valor de x: '))
    fim = time()  # Fim da contagem do tempo
    tempo = fim - inicio
    print(f'Tempo: {tempo:.2f} segundos')
    return tempo, valor_lido


def mostrar_vencedor(jogador1, jogador2):
    # Analisando casos onde um jogador obteve mais acertos do que outro
    if jogador1.corretas > jogador2.corretas:
        print(f'O jogador 1 venceu por {jogador1.corretas - jogador2.corretas} pontos de diferença')
    elif num_de_acertos_j2 > num_de_acertos_j1:
        print(f'O jogador 2 venceu por {jogador2.corretas - jogador1.corretas} pontos de diferença')
    else:  # Analisando casos onde os jogadores empataram e o desempate é no tempo
        if sum(tempo_j1) < sum(tempo_j2):
            print(f'O jogador 1 venceu por {(jogador2.tempo() - jogador1.tempo()):.2f} segundos de diferença')
        elif sum(tempo_j1) > sum(tempo_j2):
            print(f'O jogador 2 venceu por {(jogador1.tempo() - jogador2.tempo()):.2f} segundos de diferença')


rodadas = int(input('Insira o número de rodadas: '))
while True:
    maximo = int(input('Insira o maior número possível dentre os aleatórios: '))
    minimo = int(input('Insira o menor número possível dentre os aleatórios: '))
    if maximo > minimo:
        break
    print('Valor inválido. Tente novamente.')

jogadores = [Jogador(1), Jogador(2)]
for jogador in jogadores:
    print(f'JOGADOR {jogador.numero}')
    sleep(3)

    for rodada in range(0, rodadas):
        print('-=' * 15)
        sleep(1)
        print('Ache o valor de x')
        sleep(1)
        # Gerando os números aleatórios
        n1 = int(randint(minimo, maximo))
        n2 = int(randint(minimo, maximo))
        tempo, valor_lido = le_resultado(n1, n2)
        jogador.adicionar_resposta(n1 * n2, valor_lido, tempo)

print()
for jogador in jogadores:
    jogador.calcular_respostas_corretas()
    jogador.mostra_dados()

print()
mostrar_vencedor(jogadores[0], jogadores[1])

In this last scenario there is no longer the repetition of the lists of answers and times for each player, as well as not having them as global variables, because each player is represented by a class with all the information that this should contain. Also has not repeated the part of placing the values in these same lists, which is now done by the method adicionar_resposta class Jogador. In addition players are now part of a list of players, so changing the game for 3 or more players would be much easier and only needed to adjust the winning part, as the rest is already flexible.

But as I said earlier, this solution may be more difficult to understand for anyone who has never seen object-oriented programming concepts.

2

I know two ways: Flowcharts and pseudocode

1.Flowcharts These are graphical representations of algorithms, this simplifies understanding and makes your program much more transparent, even if you may not know the tools I recommend trying to create something, it helps not only other people understand your code, but shows you possible improvements to be made in the algorithm.Um exemplo de fluxograma: If you are interested try the tool https://www.draw.io

Pseudocode It’s a way of writing algorithms closer to our natural language Example:

Exemplo simples de pseudocódigo

Browser other questions tagged

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