NEA Computing Task 2 เกมลูกเต๋า
ฉันเพิ่งตั้งภารกิจที่ 2 ตามที่แสดงด้านล่างและฉันรู้ว่ามีคนตอบคำถามในไซต์นี้ที่นี่แต่ฉันต้องการความคิดเห็นใหม่
ภารกิจที่ 2:
- อนุญาตให้ผู้เล่นสองคนป้อนรายละเอียดซึ่งจะได้รับการรับรองความถูกต้องเพื่อให้แน่ใจว่าเป็นผู้เล่นที่ได้รับอนุญาต
- อนุญาตให้ผู้เล่นแต่ละคนทอยลูกเต๋า 6 เหลี่ยมสองลูก
- คำนวณและส่งออกคะแนนสำหรับแต่ละรอบและคะแนนรวมของผู้เล่นแต่ละคน
- อนุญาตให้ผู้เล่นเล่น 5 รอบ
- หากผู้เล่นทั้งสองคนมีคะแนนเท่ากันหลังจากผ่านไป 5 รอบให้ผู้เล่นแต่ละคนกลิ้งตายฝ่ายละ 1 คนจนกว่าจะมีคนชนะ
- ผลลัพธ์ที่ได้รับรางวัลเมื่อสิ้นสุด 5 รอบ
- เก็บคะแนนของผู้ชนะและชื่อของผู้ชนะไว้ในไฟล์ภายนอก
- แสดงคะแนนและชื่อผู้เล่นของคะแนนที่ชนะ 5 อันดับแรกจากไฟล์ภายนอก
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()
ความคิด / การมองโลกในแง่ดีจะได้รับการชื่นชมอย่างมาก
คำตอบ
ยินดีต้อนรับสู่ Code Review!
PEP-8
ใน python เป็นเรื่องปกติ (และแนะนำ) ให้ปฏิบัติตามคำแนะนำสไตล์ PEP-8 สำหรับการเขียนโค้ดที่สะอาดบำรุงรักษาได้และสม่ำเสมอ
ฟังก์ชั่นและตัวแปรควรตั้งชื่อในlower_snake_caseชั้นเรียนเป็นและคงเป็นUpperCamelCaseUPPER_SNAKE_CASE
f- สตริง
แนะนำใหม่ใน python 3 คือ f-string; ดังนั้นแทนที่จะมีprint("string", variable, "string")คุณสามารถทำได้:
print(f"string {variable} string")
เพื่อให้ได้ผลเช่นเดียวกัน
ฟังก์ชั่น
แยกโค้ดของคุณออกเป็นฟังก์ชั่นเล็ก ๆ แต่ละงานโดยทำงานที่เป็นเอกพจน์ ตัวอย่างบางส่วน ได้แก่ การดึงข้อมูลผู้ใช้ / รหัสผ่านจากusers.txtการตรวจสอบความถูกต้องของรายละเอียดผู้ใช้การอ่านข้อมูลรับรองผู้ใช้และอื่น ๆ
if __name__ บล็อก
สำหรับสคริปต์เป็นแนวทางปฏิบัติที่ดีในการใส่คุณลักษณะที่สามารถเรียกใช้งานได้ภายในif __name__ == "__main__"ประโยค
การควบคุมการไหล
คุณพยายามเปิดไฟล์ผู้ใช้สองครั้ง (เช่นเดียวกับไฟล์คะแนน) ตามด้วยคำจำกัดความของฟังก์ชันตามด้วยรหัสเพื่อให้ผู้ใช้เข้าสู่ระบบ จากนั้นคุณจะมีคำสั่งนำเข้าแรกตามด้วยนิยามฟังก์ชันอื่นและรหัสในภายหลังอีกครั้ง
ลองจัดกลุ่มบล็อกเข้าด้วยกัน ใน python (และภาษาโปรแกรมเกือบทั้งหมด) การนำเข้าเป็นสิ่งแรกสุด (หลังจาก shebang) จากนั้นค่าคงที่ส่วนกลางนิยามฟังก์ชัน / คลาสและโค้ดสคริปต์เอง
with งบ
แทนที่จะจัดการตัวอธิบายไฟล์ที่เปิดอยู่และควบคุมการปิดไฟล์เหล่านั้นในภายหลัง python มีwithคำสั่งที่สรุปสิ่งนี้ให้คุณ:
with open(your_file, mode) as f:
something = f.read()
# f.write(something)
อัตโนมัตินี้จะปิด (และเก็บไว้ในขอบเขต) ตัวอธิบายไฟล์
แอตทริบิวต์ที่เกี่ยวข้อง
คุณมีองค์ประกอบของผู้เล่นซึ่งมีคุณสมบัติที่เกี่ยวข้องเช่น username, player_id, score สิ่งนี้สามารถใส่ลงในคลาสแทนที่จะรักษาตัวแปรที่แตกต่างกัน 10 ตัวแปรสำหรับผู้เล่นแต่ละคน
วิธีการ Inbuilt
ในหลาย ๆ ที่ในโค้ดของคุณคุณกำลังทำไฟล์.replace("\n", ""). สิ่งนี้ไม่จำเป็นจริงๆเนื่องจากวัตถุสตริงใน python มี.strip()วิธีการซึ่งจะล้างช่องว่างทั้งหมด (และบรรทัดใหม่)
ในทำนองเดียวกันคุณพยายามจับFileNotFoundErrorเพียงเพื่อเพิ่มข้อผิดพลาดอื่นด้วยเหตุผลเดียวกัน ปล่อยให้ข้อผิดพลาดที่กำหนดไว้โดยเฉพาะสำหรับงานนั้นทำเช่นนั้น ไม่จำเป็นต้องจับภาพหากคุณต้องการให้โปรแกรมล้มเหลวในกรณีที่ไฟล์หายไป
เขียนใหม่
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()
บันทึก
การเขียนซ้ำช่วยให้ผู้เล่นหลายคนพร้อมกับตัวเลือกในการตั้งค่าหลายรอบ ( NUM_PLAYERSและNUM_ROUNDS)
มีโค้ดของคุณมากมายที่สามารถ refactored ได้ แต่เรามาเริ่มกันตั้งแต่ต้นด้วย Python styleguides (เรียกอีกอย่างว่าPEP8 )
การนำเข้า
ขอแนะนำให้เขียนการนำเข้าทั้งหมดที่ด้านบนของไฟล์
การตั้งชื่อ
ใน Python ชื่อของฟังก์ชันและตัวแปรควรเป็นsnake_case d นั่นคือแทนที่จะเป็นdef Roll()คุณควรมีdef roll()แทนที่จะเป็นPlayer1Scoreคุณควรมีplayer1_scoreไปเรื่อย ๆ คุณมีความคิด อ่านเพิ่มเติมได้ที่นี่
พูดว่า NO กับ `;` ใน Python!
อย่าใช้;ใน Python มันไม่จำเป็นและมันทำให้ฉันจำช่วงเวลาที่ยากลำบากที่ฉันใช้ C / C ++ คุณไม่อยากให้ฉันเสียใจใช่ไหม :(
ทั่วไป
โดยปกติวิธีปฏิบัติที่ดีคือพยายามหลีกเลี่ยงการบล็อกโค้ดแบบอินไลน์ มันยากที่จะปฏิบัติตามและไม่เกิดประโยชน์ใด ๆ นี้:
if Player1Score > Player2Score: Winner = 1
ควรเขียนเป็น:
if Player1Score > Player2Score:
Winner = 1
ที่กล่าวว่ารหัสของคุณจนถึงตอนนี้โดยคำนึงถึงคำแนะนำข้างต้นจะมีลักษณะดังนี้:
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()
ตอนนี้ดีขึ้นหน่อย มาพูดถึงการนำไปใช้งานจริงกัน
ที่นี่:
try:
file = open("Users.txt", "r")
except FileNotFoundError:
raise SystemExit("User file not found")
file = open("Users.txt", "r")
คุณกำลังพยายามเปิดไฟล์และหากไม่มีอยู่ให้เพิ่มและยกเว้น ไม่มีอะไรผิดปกติกับสิ่งนี้ แต่สังเกตว่าคุณเปิดไฟล์สองครั้งอย่างไรหากไม่มีข้อยกเว้นเพิ่มขึ้น หากคุณต้องการตรวจสอบว่ามีไฟล์อยู่หรือไม่คุณสามารถใช้osโมดูลเพื่อยืนยันว่ามีพา ธ ไฟล์อยู่หรือไม่และสร้างฟังก์ชันที่ทำเช่นนั้น ทำให้ filepath เป็นค่าคงที่และวางไว้ที่ด้านบนสุดของสคริปต์ของคุณ:
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
ในการเรียกใช้ฟังก์ชันคุณสามารถทำได้:
if check_path(USERS_FILEPATH):
# do things here
มีสองสิ่งใหม่ที่นี่ ขั้นแรกสังเกตว่าฉันเพิ่ม docstring ลงในฟังก์ชันนี้อย่างไรและจะบอกได้ง่ายเพียงใดว่ามันทำอะไรได้บ้าง ประการที่สองสังเกตว่าการใช้ฟังก์ชันนี้กับไฟล์อื่น ๆ ที่เกมของคุณอาจใช้ประโยชน์ได้นั้นง่ายเพียงใด ประการที่สามดูว่าสตริงถูกจัดรูปแบบอย่างไรเมื่อฉันเพิ่มข้อยกเว้น คุณสามารถอ่านเพิ่มเติมเกี่ยวกับสตริงหลามของการจัดรูปแบบที่นี่
// ต้องไปก่อน