Since I bought a professional steel-darts-kit two weeks ago, I created this little python console program that aids me with track-keeping of the game score and further statistical data I may need in the future.
The program essentially takes the game mode (from 301 or 501 down, but that's free choice), the two player names and then goes into the darts game loop where it stays until one of the two players reached 0 score. every now and then, there will be sqlite3 query's to a little database which stores the checkout possibilities (e.g. for 55 points left it'd be 15 + Double 20) and game statictics. After a player wins, the game data goes into another table in my database.
Essentially, the code works fine, takes care of bad user input, has a nice colored output to the console and keeps track of the game accurately. After every game, it is easy to start another one where the other player begins, it is also possible to switch players after a finished game by inputting new user names.
The reason I write this post is that althought I have all the necessary functionalities I want, it really is full of dirty workarounds and looks pretty complex already. I would like to have some advice on which best practises I missed, which lines of code are just obsolete or easy to rephrase. For example, I had to fiddle around with it for numerous hours until I came up with the ugly workaround for alternating player game starts. Also there are quite a lot of repetitions in the code (the whole db-query reformatting stuff) and especially the game loop for player 1 and player 2 (which are essentially the same), so I'd like some suggestions how I could improve the code.
Also I'd happily take any suggestions on how to calculate a average score per 3 darts. I know I would need to implement some sort of input which says with how many darts the inputted points were scored. Then I could just append all the thrown score and darts into a table and do a easy average calculation, but I'm lacking a idea of how to implement a darts thrown into the code without making it more complicated and longer to input the data. And when taking a default for 3 darts per inputted score it would be vastly inaccuate when it comes to the finishes which may take a while and sometimes only need 1 dart thrown until you fail and have to try again... :-D
#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()