NEA Computing Task 2 Dice Game
Saya baru-baru ini menetapkan Tugas 2 seperti yang terlihat di bawah dan saya menyadari seseorang menjawab pertanyaan di situs ini di sini tetapi saya ingin pendapat baru
TUGAS 2:
- Izinkan dua pemain untuk memasukkan detail mereka, yang kemudian diautentikasi untuk memastikan bahwa mereka adalah pemain resmi.
- Memungkinkan setiap pemain untuk melempar dua dadu bersisi 6.
- Menghitung dan mengeluarkan poin untuk setiap putaran dan skor total setiap pemain.
- Memungkinkan pemain untuk bermain 5 putaran.
- Jika kedua pemain memiliki skor yang sama setelah 5 putaran, izinkan setiap pemain untuk melempar 1 dadu masing-masing hingga seseorang menang.
- Keluaran yang menang di akhir 5 ronde.
- Menyimpan skor pemenang, dan nama mereka, di file eksternal.
- Menampilkan skor dan nama pemain dari 5 skor kemenangan teratas dari file eksternal.
try: File = open("Users.txt","r")
except FileNotFoundError:
raise SystemExit("User file not found")
File = open("Users.txt", "r")
def Login(Username, Player):
File.seek(0)
for Line in File:
ValidUsername = Line.split(",")[0]
ValidPassword = Line.split(",")[1].replace("\n", "")
if Username == ValidUsername:
Password = input("Password: ")
if Password == ValidPassword:
print("Player",Player,"logged in")
print("")
return True
else: print("Invalid Details")
return False
try:
while True:
print("Player 1 Login")
Username1 = input("Username: ")
if Login(Username1, 1): break
print("")
while True:
print("Player 2 Login")
Username2 = input("Username: ")
if Username1 == Username2:
print("Double login detected")
elif Login(Username2, 2): break
print("")
except KeyboardInterrupt:
raise SystemExit("Exiting...")
finally:
File.close()
import random
Player1Score = 0
Player2Score = 0
def Roll():
Dice1 = random.randint(1, 6)
Dice2 = random.randint(1, 6)
print("You rolled a",Dice1,"and a",Dice2)
Change = Dice1 + Dice2
Change += 10 if (Dice1 + Dice2) % 2 == 0 else -5
if Change < 0: Change = 0
if Dice1 == Dice2:
Dice3 = random.randint(1, 6)
print("Your third roll is a",Dice3)
Change += Dice3
print("")
return Change
for X in range(5):
print("Play:",X + 1,"starting")
input("Player 1, press enter to roll: ")
Player1Score += Roll()
input("Player 2, press enter to roll: ")
Player2Score += Roll()
print("Player 1 now has a score of",Player1Score)
print("Player 2 now has a score of",Player2Score)
print("")
if Player1Score > Player2Score: Winner = 1
if Player1Score < Player2Score: Winner = 2
if Player1Score == Player2Score:
print("You both got the same score")
def SameScore():
input("Press enter to roll dice: ")
print("")
Dice1 = random.randint(1, 6)
Dice2 = random.randint(1, 6)
print("Player 1 rolled:",Dice1)
print("Player 2 rolled:",Dice2)
if Dice1 == Dice2: return False
if Dice1 > Dice2: return 1
if Dice1 < Dice2: return 2
Winner = False
while not Winner:
Winner = SameScore()
if Winner == 1:
Winner = Username1 + ": " + str(Player1Score)
print(Username1,"won with",Player1Score,"points")
print(Username2,"lost with",Player2Score,"points")
if Winner == 2:
Winner = Username2 + ": " + str(Player2Score)
print(Username2,"won with",Player2Score,"points")
print(Username1,"lost with",Player1Score,"points")
WinnerScore = int(Winner.split(": ")[1])
FileWritten = False
try:
File = open("Scores.txt", "r")
Data = File.readlines();File.close()
for X in range(len(Data)):
if WinnerScore > int(Data[X].split(": ")[1]):
Data.insert(X, Winner + "\n")
if len(Data) > 5: Data.pop(5)
FileWritten = True; break
if len(Data) < 5:
if not FileWritten: Data.append(Winner + "\n")
File = open("Scores.txt","w")
for X in Data:
File.write(X.replace("\n","") + "\n")
except FileNotFoundError:
File = open("Scores.txt","w")
File.write(Winner + "\n")
File.close()
print("")
File = open("Scores.txt","r")
print("Highscores:")
for Line in File:
if Line != "": print(Line.replace("\n", ""))
File.close()
Pikiran / optimisasi apa pun akan sangat dihargai
Jawaban
Selamat datang di Review Kode!
PEP-8
Dalam python, adalah umum (dan disarankan) untuk mengikuti panduan gaya PEP-8 untuk menulis kode yang bersih, dapat dipelihara dan konsisten.
Fungsi dan variabel harus diberi nama dalam a lower_snake_case, kelas sebagai UpperCamelCase, dan konstanta sebagai UPPER_SNAKE_CASE.
f-string
Yang baru diperkenalkan di python 3 adalah f-string; jadi alih-alih meminta print("string", variable, "string")Anda dapat melakukan:
print(f"string {variable} string")
untuk efek yang sama.
Fungsi
Bagi kode Anda menjadi beberapa fungsi yang lebih kecil, melakukan tugas tunggal. Beberapa contohnya adalah, mengambil pengguna / kata sandi dari users.txt, memvalidasi detail pengguna, membaca kredensial pengguna, dan sebagainya.
if __name__ blok
Untuk skrip, itu adalah praktik yang baik untuk menempatkan fitur yang dapat dieksekusi di dalam if __name__ == "__main__"klausa.
Aliran kontrol
Anda mencoba untuk membuka file pengguna dua kali (hal yang sama berlaku untuk file skor). Ini diikuti oleh definisi fungsi, diikuti dengan kode untuk membuat pengguna login. Kemudian Anda memiliki pernyataan import pertama Anda diikuti dengan definisi fungsi lain dan kode selanjutnya lagi.
Cobalah mengelompokkan blok menjadi satu. Dalam python (dan hampir semua bahasa pemrograman), impor adalah hal pertama (setelah shebang). Kemudian konstanta global, definisi fungsi / kelas, dan kemudian kode skrip itu sendiri.
with pernyataan
Alih-alih Anda mengelola deskriptor file yang dibuka dan kemudian mengontrol penutupannya, python memiliki withpernyataan yang membungkus ini untuk Anda:
with open(your_file, mode) as f:
something = f.read()
# f.write(something)
ini otomatis menutup (dan tetap dalam cakupan) deskriptor file.
Atribut terkait
Anda memiliki elemen pemain, yang memiliki properti terkait seperti nama pengguna, player_id, skor. Ini dapat dimasukkan ke dalam kelas, alih-alih mempertahankan 10 variabel berbeda untuk setiap pemain.
Metode bawaan
Di banyak tempat dalam kode Anda, Anda melakukan a .replace("\n", ""). Ini tidak benar-benar diperlukan, karena objek string di python memiliki .strip()metode, yang membersihkan semua spasi (dan baris baru).
Demikian pula, Anda mencoba menangkap satu- FileNotFoundErrorsatunya untuk memunculkan kesalahan lain karena alasan yang sama. Biarkan kesalahan yang ditentukan secara spesifik untuk pekerjaan itu yang melakukannya. Tidak perlu merekam jika Anda ingin program gagal jika file hilang.
Menulis kembali
from operator import itemgetter
import random
USERS_FILE: str = "Users.txt"
SCORES_FILE: str = "Scores.txt"
NUM_PLAYERS: int = 2
NUM_ROUNDS: int = 5
def roll_die() -> int:
return random.randint(1, 6)
class Player:
def __init__(self, _id: int, name: str):
self._id = _id
self.name = name
self.score = 0
def add_score(self, value: int):
self.score += value
if self.score < 0:
self.score = 0
def turn(self):
input(f"{self.name}'s turn. Press enter to roll.")
dice_1 = roll_die()
dice_2 = roll_die()
print(f"{self.name} rolled {dice_1} and {dice_2}.")
change = dice_1 + dice_2
change += 10 if change % 2 == 0 else -5
if change < 0:
change = 0
if dice_1 == dice_2:
dice_3 = roll_die()
print(f"Third roll is {dice_3}")
change += dice_3
self.add_score(change)
def __str__(self) -> str:
return f"Player({self.name}): {self.score}"
def fetch_users() -> dict:
users = {}
with open(USERS_FILE, "r") as f:
users = dict([line.strip().split(",") for line in f])
return users
def authenticate(users: dict, name: str, password: str) -> bool:
return users.get(name) == password
def show_highscores() -> None:
with open(SCORES_FILE, "r") as f:
print(f.read())
def fetch_highscores() -> list:
scores = []
with open(SCORES_FILE, "r") as f:
for line in f:
name, score = line.strip().split(": ")
score = int(score)
scores.append((name, score))
return scores
def write_score(player: Player, limit: int = 5):
current_highscores = fetch_highscores()
current_highscores.append((player.name, player.score))
sorted_scores = sorted(current_highscores, key=itemgetter(1), reverse=True)
with open(SCORES_FILE, "w") as f:
for name, score in sorted_scores[:limit]:
f.write(f"{name}: {score}\n")
def get_player(_id: int, users: dict) -> Player:
print(f"Players {_id} login")
while True:
name = input("username: ")
password = input("password: ")
if authenticate(users, name, password):
return Player(_id, name)
print("Invalid details. Try again!")
def get_winning_player(players: list) -> Player:
def filter_winning_players(player_dices: list, value: int):
filtered = []
for player, dice in player_dices:
print(f"{player.name} rolled {dice}.")
if dice == value:
filtered.append(player)
return filtered
max_score = max([player.score for player in players])
winners = [player for player in players if player.score == max_score]
if len(winners) == 1:
return winners[0]
print(f"{len(winners)} players have the same score. Trying to determine single winning player.")
while True:
input("Press enter to roll dice: ")
dices = [roll_die() for _ in range(len(winners))]
max_dice = max(dices)
winners = filter_winning_players(zip(winners, dices), max_dice)
if len(winners) == 1:
return winners[0]
def game():
users = fetch_users()
players = [get_player(count + 1, users) for count in range(NUM_PLAYERS)]
for round in range(1, NUM_ROUNDS + 1):
for player in players:
player.turn()
print(f"Player scores at end of round {round}:")
for player in players:
print(str(player))
winner = get_winning_player(players)
print(f"Winner is {winner}.")
write_score(winner)
print("Highscores: ")
show_highscores()
if __name__ == "__main__":
game()
CATATAN
Penulisan ulang memungkinkan beberapa pemain, bersama dengan opsi untuk mengatur beberapa putaran ( NUM_PLAYERSdan NUM_ROUNDS).
Ada banyak kode Anda yang dapat direfraktorisasi tetapi mari kita mulai dari awal dengan beberapa panduan gaya Python (juga disebut PEP8 )
Impor
Disarankan untuk menulis semua impor di bagian atas file Anda.
Penamaan
Dalam Python, nama fungsi dan variabel haruslah snake_case d. Artinya, bukannya def Roll()kamu harus punya def roll(), bukannya Player1Scorekamu harus punya player1_scoredan sebagainya. Anda punya ide. Baca lebih lanjut di sini
Katakan TIDAK untuk `;` dengan Python!
Jangan gunakan ;dengan Python. Itu tidak diperlukan, dan itu membuat saya mengingat masa-masa sulit saya menggunakan C / C ++. Anda tidak ingin saya bersedih, bukan? :(
Umum
Biasanya merupakan praktik yang baik untuk mencoba menghindari blok kode sebaris. Sulit untuk diikuti dan tidak ada manfaatnya. Ini:
if Player1Score > Player2Score: Winner = 1
Harus ditulis sebagai:
if Player1Score > Player2Score:
Winner = 1
Meskipun demikian, kode Anda sejauh ini, dengan mempertimbangkan saran di atas, akan terlihat seperti ini:
import random
try:
file = open("Users.txt", "r")
except FileNotFoundError:
raise SystemExit("User file not found")
file = open("Users.txt", "r")
def same_score():
input("Press enter to roll dice: ")
print("")
dice_1 = random.randint(1, 6)
dice_2 = random.randint(1, 6)
print("player 1 rolled:", dice_1)
print("player 2 rolled:", dice_2)
if dice_1 == dice_2:
return False
if dice_1 > dice_2:
return 1
if dice_1 < dice_2:
return 2
def login(username, player):
file.seek(0)
for line in file:
valid_username = line.split(",")[0]
valid_password = line.split(",")[1].replace("\n", "")
if username == valid_username:
password = input("password: ")
if password == valid_password:
print("player", player, "logged in")
print("")
return True
else:
print("Invalid Details")
return False
def roll():
dice1 = random.randint(1, 6)
dice2 = random.randint(1, 6)
print("You rolled a", dice1, "and a", dice2)
change = dice1 + dice2
change += 10 if (dice1 + dice2) % 2 == 0 else -5
if change < 0:
change = 0
if dice1 == dice2:
dice3 = random.randint(1, 6)
print("Your third roll is a",dice3)
change += dice3
print("")
return change
try:
while True:
print("player 1 login")
username1 = input("username: ")
if login(username1, 1):
break
print("")
while True:
print("player 2 login")
username2 = input("username: ")
if username1 == username2:
print("Double login detected")
elif login(username2, 2):
break
print("")
except KeyboardInterrupt:
raise SystemExit("Exiting...")
finally:
file.close()
player1_score = 0
player2_score = 0
for x in range(5):
print("Play:", x + 1, "starting")
input("player 1, press enter to roll: ")
player1_score += roll()
input("player 2, press enter to roll: ")
player2_score += roll()
print("player 1 now has a score of", player1_score)
print("player 2 now has a score of", player2_score)
print("")
if player1_score > player2_score:
winner = 1
if player1_score < player2_score:
winner = 2
if player1_score == player2_score:
print("You both got the same score")
winner = False
while not winner:
winner = same_score()
if winner == 1:
winner = username1 + ": " + str(player1_score)
print(username1, "won with", player1_score, "points")
print(username2, "lost with", player2_score, "points")
if winner == 2:
winner = username2 + ": " + str(player2_score)
print(username2, "won with", player2_score, "points")
print(username1, "lost with", player1_score, "points")
winner_score = int(winner.split(": ")[1])
file_written = False
try:
file = open("Scores.txt", "r")
data = file.readlines()
file.close()
for x in range(len(data)):
if winner_score > int(data[x].split(": ")[1]):
data.insert(x, winner + "\n")
if len(data) > 5:
data.pop(5)
file_written = True
break
if len(data) < 5:
if not file_written:
data.append(winner + "\n")
file = open("Scores.txt", "w")
for x in data:
file.write(x.replace("\n", "") + "\n")
except FileNotFoundError:
file = open("Scores.txt", "w")
file.write(winner + "\n")
file.close()
print("")
file = open("Scores.txt", "r")
print("Highscores:")
for line in file:
if line != "":
print(line.replace("\n", ""))
file.close()
Sekarang, ini sedikit lebih baik. Mari kita bahas implementasi sebenarnya sekarang.
Sini:
try:
file = open("Users.txt", "r")
except FileNotFoundError:
raise SystemExit("User file not found")
file = open("Users.txt", "r")
Anda mencoba membuka file, dan jika tidak ada, Anda memunculkan dan pengecualian. Tidak ada yang salah dengan ini, tetapi perhatikan bagaimana Anda membuka file dua kali jika tidak ada pengecualian yang dimunculkan. Jika Anda ingin memeriksa apakah ada file atau tidak, Anda bisa menggunakan osmodul untuk mengkonfirmasi jika jalur file ada dan membuat fungsi yang melakukannya. Juga, buat jalur file menjadi konstan dan letakkan di bagian atas skrip Anda:
import os
USERS_FILEPATH = '/path/to/Users.txt'
def check_file(filepath):
"""Verify if a filepath exists.
Return True if a filepath exists. Otherwise raise an exception.
Arguments:
filepath (str): Path to a file
Returns:
True or raise an exception
"""
if not os.path.exists(filepath):
raise OSError('User filepath {} not found.'.format(filepath))
return True
Untuk memanggil fungsi tersebut, Anda dapat melakukan:
if check_path(USERS_FILEPATH):
# do things here
Ada beberapa hal baru di sini. Pertama, perhatikan bagaimana saya menambahkan docstring ke fungsi ini dan betapa mudahnya untuk mengetahui apa yang sebenarnya dilakukannya. Kedua, perhatikan betapa mudahnya menggunakan fungsi ini pada file lain yang mungkin digunakan oleh game Anda. Ketiga, lihat bagaimana string diformat saat saya mengajukan pengecualian. Anda dapat membaca lebih lanjut tentang pemformatan string Python di sini .
// harus pergi sekarang