Дартс --- помогает консольная программа для отслеживания, учета и статистики


Так как я купил профессиональный стали дартс комплект две недели назад, я создал этот небольшой консольной программы на языке Python, который помогает мне с учета игрового счета и дополнительные статистические данные мне могут понадобиться в будущем.

Программа, по сути, режим игры (с 301 или 501, но это свободный выбор), два имени игрока, а затем переходит в дартс игровой цикл, где и остается до одного из двух игроков достигло 0 баллов. каждый сейчас и потом, там будет запрос sqlite3 для того, чтобы немного базу данных, которая хранит возможности оформить заказ (например, на 55 очков слева было бы 15 + двойной 20) и игровая статистика. После того, как игрок выигрывает, игра переходит в другой таблице в базе данных.

По сути, этот код прекрасно работает, заботится о плохой пользовательский ввод, имеет хороший цветной вывод в консоль и отслеживает точно игры. После каждой игры, это легко, чтобы начать еще один, где другой игрок начинает, это также возможно переключение игроков после законченной игры, введя новое имя пользователя.

Причина, по которой я пишу этот пост заключается в том, что хотя у меня есть все необходимые функциональные возможности, я хочу, это действительно полный грязных обходные пути и уже выглядит довольно сложным. Я хотел бы получить некоторые советы, на которых лучшие практики, я пропустила, какие строки кода просто устарели или просто перефразировать. Например, мне пришлось возиться с ним долгими часами, пока я не придумал уродское решение для переменного игру, игрок начинает. Также есть довольно много повторений в коде (всего БД-запрос переформатирование хлам) и особенно игровой цикл для игрока 1 и игрока 2 (который по сути то же самое), поэтому я хотел бы некоторые предложения, как я могу улучшить код.

Также я с радостью принять любые предложения о том, как рассчитать средний балл за 3 дротика. Я знаю, что мне нужно для реализации какой-то вход, который говорит, сколько дартс введенных баллов набрали. Тогда я мог бы просто добавить все кинули счет и дартс в таблицу и сделать легкий средний расчет, но мне не хватает идеи, как реализовать дартс брошены в код, не делая его сложнее и дольше для ввода данных. И при съемке по умолчанию для 3 дротика за введенных результат будет значительно inaccuate, когда дело доходит до отделки, которая может занять некоторое время, а иногда нужно только 1 дротик брошен, пока вы не удастся, и придется еще раз попробовать... :-Д

#necessary imports
import sqlite3
import re
import time
import datetime
from pandas import read_excel
from colorama import init

#setup db connection
darts_db = sqlite3.connect('darts_db.db')
cursor = darts_db.cursor()

#get checkout value list
checkout_table = read_excel('checkout.xlsx')
values = checkout_table["value"].tolist()

#basic setup
init(autoreset=True) #autoreset of coloring after every printout
game_loop = True
points_default = int(input("enter starting score (301, 501, ...): "))

P1_Game_Wins = 0 
P2_Game_Wins = 0

Player_1 = input("Name of Player 1: ")
Player_2 = input("Name of Player 2: ")

#show stats for each player before the game starts
cursor.execute("SELECT count(winner) FROM game_overview WHERE winner == ?", (Player_1,))
P1_Stats = str(cursor.fetchall()[0]) 
P1_Stats = re.sub('''[()',]''', '', P1_Stats) 
cursor.execute("SELECT max(cast(checkout as int)) FROM game_overview WHERE winner == ?", (Player_1,))
P1_Checkout = str(cursor.fetchall()[0]) 
P1_Checkout = re.sub('''[()',]''', '', P1_Checkout)  
print("\n\x1b[1;33;40mTotal Wins of {0}: {1}. Highest Checkout: {2}".format(Player_1, P1_Stats, P1_Checkout)) 
cursor.execute("SELECT count(winner) FROM game_overview WHERE winner == ?", (Player_2,))
P2_Stats = str(cursor.fetchall()[0]) 
P2_Stats = re.sub('''[()',]''', '', P2_Stats)
cursor.execute("SELECT max(cast(checkout as int)) FROM game_overview WHERE winner == ?", (Player_2,))
P2_Checkout = str(cursor.fetchall()[0]) 
P2_Checkout = re.sub('''[()',]''', '', P2_Checkout)  
print("\x1b[1;33;40mTotal Wins of {0}: {1}. Highest Checkout: {2}".format(Player_2, P2_Stats, P2_Checkout)) 

while game_loop == True:

    P1_Score = points_default
    P2_Score = points_default

    #switch players after every match so that they alternate --> dirty but works
    if (P1_Game_Wins + P2_Game_Wins) == 0:
        pass
    else:
        Player_dummy = Player_1
        Player_1 = Player_2
        Player_2 = Player_dummy
        Win_History_dummy = P1_Game_Wins
        P1_Game_Wins = P2_Game_Wins
        P2_Game_Wins = Win_History_dummy
                                                             #ANSI Green       ANSi escape
    print("\n{0} is playing vs {1}. We play down from \x1b[1;32;40m{2} \x1b[0m. {3} begins!".format(Player_1, Player_2, points_default, Player_1))                                                  
    #playing loop
    while P1_Score or P2_Score != 0:


        while True: #player 1 playing loop
            print("\nPoints of\x1b[1;32;40m {0} \x1b[0mbefore his turn: \x1b[1;32;40m{1}".format(Player_1, P1_Score))
            if P1_Score in values:

                cursor.execute("SELECT checkout FROM checkout_table WHERE value == ?", (P1_Score,)) #select checkout from db
                checkout = str(cursor.fetchall()[0])                                                #store select in variable
                checkout = re.sub('''[()',]''', '', checkout)                                       #reformatting to printable form
                print("Checkout: {}".format(checkout))                                              #and finally: print
            else:
                pass
            try:
                P1_Hit = int(input("Points scored: "))
            except ValueError:
                print("\x1b[1;31;40mPlease enter a number between 0 and 180!")
            else:
                if 0 <= P1_Hit <= 180:
                    break
                else:
                    print("\x1b[1;31;40mPlease enter a number between 0 and 180!")

        P1_Score = P1_Score - int(P1_Hit) #player 1 scoring function
        if P1_Score == 0:
            print("Points of {0} after his turn: {1}\n".format(Player_1, P1_Score))
            print("\x1b[1;33;40m===============***WIN! WIN! WIN!***===============")
            print("\x1b[1;33;40m===============***{0} IS A GOD!!!***===============\n".format(Player_1.upper()))
            P1_Game_Wins += 1
            unix = int(time.time())
            date = str(datetime.datetime.fromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S'))
            cursor.execute("INSERT INTO game_overview(game_id, player1, player2, winner, gamemode, checkout) VALUES (?, ?, ?, ?, ?, ?)",
                           (date, Player_1, Player_2, Player_1, points_default, P1_Hit))

            darts_db.commit()
            break
        elif P1_Score >= 2: 
            print("Points of {0} after his turn: {1}".format(Player_1, P1_Score))
        elif P1_Score <= 1:    
            print("\x1b[1;31;40mYou scored too much! Noob.")
            P1_Score = P1_Score + int(P1_Hit)


        while True: #player 2 playing loop -> essentially the same again for player 2
            print("\nPoints of\x1b[1;32;40m {0} \x1b[0mbefore his turn: \x1b[1;32;40m{1}".format(Player_2, P2_Score))
            if P2_Score in values:
                cursor.execute("SELECT checkout FROM checkout_table WHERE value == ?", (P2_Score,))
                checkout = str(cursor.fetchall()[0])
                checkout = re.sub('''[()',]''', '', checkout)
                print("Checkout: {}".format(checkout))
            else:
                pass
            try:
                P2_Hit = int(input("Points scored: "))
            except ValueError:
                print("\x1b[1;31;40mPlease enter a number between 0 and 180!")
            else:
                if 0 <= P2_Hit <= 180:
                    break
                else:
                    print("\x1b[1;31;40mPlease enter a number between 0 and 180!")

        P2_Score = P2_Score - int(P2_Hit) #player 2 scoring function
        if P2_Score == 0:
            print("Points of {0} after his turn: {1}\n".format(Player_2, P2_Score))
            print("\x1b[1;33;40m===============***WIN! WIN! WIN!***===============")
            print("\x1b[1;33;40m===============***{0} IS A GOD!!!***===============\n".format(Player_2.upper()))
            P2_Game_Wins += 1
            unix = int(time.time())
            date = str(datetime.datetime.fromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S'))
            cursor.execute("INSERT INTO game_overview(game_id, player1, player2, winner, gamemode, checkout) VALUES (?, ?, ?, ?, ?, ?)",
                           (date, Player_1, Player_2, Player_2, points_default, P2_Hit))
            darts_db.commit()
            break
        elif P2_Score >= 2: 
            print("Points of {0} after his turn: {1}".format(Player_2, P2_Score))
        elif P2_Score <= 1:    
            print("\x1b[1;31;40mYou scored too much! Noob.")
            P2_Score = P2_Score + int(P2_Hit)

    print("Total Wins of {0}: {1} \nTotal Wins of {2}: {3}\n".format(Player_1, P1_Game_Wins, Player_2, P2_Game_Wins))

    another_round = input("Another Match? Press[Enter]. Or [N] for new players.")
    if another_round == '':
        game_loop = True
    elif another_round.upper() == 'N':
        P1_Game_Wins = 0 
        P2_Game_Wins = 0

        Player_1 = input("\nName of Player 1: ")
        Player_2 = input("Name of Player 2: ")
        game_loop = True
    else:
        game_loop = False

#close db connection            
cursor.close()    
darts_db.close()


238
4
задан 5 февраля 2018 в 08:02 Источник Поделиться
Комментарии
1 ответ

Есть довольно много вещей, которые вы могли бы сделать по-другому. Первым шагом будет выделение констант и функций, которые делают что-то с вашей базой данных.

Следующий шаг-это функция объединения в классы, где это необходимо.

Здесь я сделал это один раз с DBConnection класс, который содержит все эти SQL для казни и Player класса, который просто хранит имя игрока, счет и выигрывает. В DBConnection класс представляет собой файл contextmanager, поэтому мы можем использовать его с with заявление, которое заботится о закрытие подключения к базе данных даже в случае, если ваш код вызывает исключение где-то еще.

Я в основном заменены все излишки, которые были специальные чехлы для игрока 1 и игрока 2 с for цикл по players и использовать новый f-strings введен в Python 3.6 сделать все печати легче.

Еще несколько заметок:


  • "[()',]" легче понять, чем '''[()',]'''

  • Взгляните на языке Python официальный стиль-руководство, PEP8. Он рекомендует использовать lower_case для переменных и функций, PascalCase для классов и UPPER_CASE для констант. Он также рекомендует придерживаться максимальной длины строки в 80 символов (которые я не совсем понимаю здесь...).

  • cursor.fetchone() легче, чем cursor.fetchall()[0].

  • Использование языка Python идиома a, b = b, a чтобы поменять две переменные.

  • Использовать if __name__ == "__main__: охранник , чтобы импортировать этот модуль объекты из другого сценария.

  • datetime имеет datetime.datetime.now() classmethod в который попадает текущее время.

  • score in values берет \$\mathcal{о}(н)\$ времени. Если values это setон только принимает \$\mathcal{О,} (1)\$ времени. Читал на разных временных сложностях встроенные типы данных.

# necessary imports
import sqlite3
import re
import time
import datetime
from pandas import read_excel
from colorama import init

# autoreset of coloring after every printout
init(autoreset=True)

# some constants for nice colors in printing
BLUE = "\x1b[1;33;40m"
GREEN = "\x1b[1;32;40m"
RED = "\x1b[1;31;40m"
CLEAR = "\x1b[0m"

# get checkout value list
VALUES = set(read_excel('checkout.xlsx')["value"].tolist())

class DBConnection:
"""Manages a db connection and defines the needed queries.
Needs to be used as a contextmanager."""

def __init__(self, file_name):
self.file_name = file_name
self.db = None
self.cursor = None

def __enter__(self):
self.db = sqlite3.connect(self.file_name)
self.cursor = self.db.cursor()
return self

def __exit__(self, *args):
self.cursor.close()
self.db.close()

def get_wins(self, player):
self.cursor.execute(
"SELECT count(winner) FROM game_overview WHERE winner == ?", (player,))
return re.sub("[()',]", "", str(self.cursor.fetchone()))

def get_max_checkout(self, player):
self.cursor.execute(
"SELECT max(cast(checkout as int)) FROM game_overview WHERE winner == ?", (player,))
return re.sub("[()',]", "", str(self.cursor.fetchone()))

def get_checkout(self, score):
self.cursor.execute(
"SELECT checkout FROM checkout_table WHERE value == ?", (score,))
return re.sub("[()',]", "", str(self.cursor.fetchone()))

def record_game(self, player_1, player_2, winner, points_default, checkout):
date = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.cursor.execute("INSERT INTO game_overview(game_id, player1, player2, winner, gamemode, checkout) VALUES (?, ?, ?, ?, ?, ?)",
(date, player_1, player_2, winner, points_default, checkout))
self.db.commit()

class Player:

def __init__(self, name, score=301):
self.name = name
self.score = score
self.wins = 0

def __str__(self):
"""`print(player)` just prints the name of the player."""
return self.name

def get_player_hit():
"""Ask the user until he supplies a valid hit."""
while True:
try:
hit = int(input("Points scored: "))
except ValueError:
print(f"{RED}Please enter a number between 0 and 180!")
else:
if 0 <= P1_Hit <= 180:
return hit
else:
print(f"{RED}Please enter a number between 0 and 180!")

# Put main code under this guard to allow importing from another module
if __name__ == "__main__":
# game setup
points_default = int(input("enter starting score (301, 501, ...): "))
players = [Player(input("Name of Player 1: "), points_default),
Player(input("Name of Player 2: "), points_default)]

# setup db connection
with DBConnection('darts_db.db') as db:
while True:
# show stats for each player before the game starts
for player in players:
wins = db.get_wins(player.name)
checkout = db.get_max_checkout(player.name)
print(f"\n{BLUE}Total Wins of {player}: {wins}. Highest Checkout: {checkout}")

# switch players after every match so that they alternate
if (players[0].wins + players[1].wins) != 0:
players[0], players[1] = players[1], players[0]

print(f"\n{players[0]} is playing vs {players[1]}. We play down from {GREEN}{points_default}{CLEAR}. {players[0]} begins!")

# playing loop
play = True
while play:
for player in players:
print(f"\nPoints of {GREEN}{player}{CLEAR} before his turn: {GREEN}{player.score}")
if player.score in VALUES:
print("Checkout:", db.get_checkout(player.score))

hit = get_player_hit()
player.score -= hit

if player.score == 0:
print(f"Points of {player} after his turn: {player.score}\n")
print(f"{BLUE}===============***WIN! WIN! WIN!***===============")
print(f"{BLUE}===============***{player.name.upper()} IS A GOD!!!***===============\n")
player.wins += 1
db.record_game(players[0].name, players[
1].name, player.name, points_default, hit)
play = False
break
elif player.score >= 2:
print(f"Points of {player} after his turn: {player.score}")
elif player.score <= 1:
print(f"{RED}You scored too much! Noob.")
player.score += hit

for player in players:
print(f"Total Wins of {player}: {player.wins}")

another_round = input(
"Another Match? Press[Enter]. Or [N] for new players.")
if another_round == '':
continue
elif another_round.upper() == 'N':
players = [Player(input("Name of Player 1: "), points_default),
Player(input("Name of Player 2: "), points_default)]
else:
break

1
ответ дан 26 февраля 2018 в 05:02 Источник Поделиться