NEA Computing Task 2 Dice Game

Oct 21 2020

Gần đây tôi đã đặt Nhiệm vụ 2 như được thấy bên dưới và tôi nhận ra ai đó trả lời câu hỏi trên trang web này ở đây nhưng tôi muốn có một ý kiến ​​mới

NHIỆM VỤ 2:

  1. Cho phép hai người chơi nhập thông tin chi tiết của họ, sau đó được xác thực để đảm bảo rằng họ là người chơi được ủy quyền.
  2. Cho phép mỗi người chơi tung hai viên xúc xắc 6 mặt.
  3. Tính toán và xuất điểm cho mỗi vòng và tổng điểm của mỗi người chơi.
  4. Cho phép người chơi chơi 5 vòng.
  5. Nếu cả hai người chơi có cùng số điểm sau 5 vòng, cho phép mỗi người chơi lăn 1 con chết cho đến khi có người thắng.
  6. Kết quả là ai đã chiến thắng ở cuối 5 vòng.
  7. Lưu trữ điểm và tên của người chiến thắng trong một tệp bên ngoài.
  8. Hiển thị điểm số và tên người chơi của 5 điểm số chiến thắng cao nhất từ ​​tệp bên ngoài.
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()

Mọi suy nghĩ / lạc quan sẽ được đánh giá rất cao

Trả lời

5 hjpotter92 Oct 21 2020 at 15:21

Chào mừng bạn đến với Đánh giá mã!

PEP-8

Trong python, thông thường (và được khuyến nghị) làm theo hướng dẫn kiểu PEP-8 để viết mã sạch, có thể bảo trì và nhất quán.

Các hàm và biến phải được đặt tên trong a lower_snake_case, các lớp là UpperCamelCasevà các hằng là UPPER_SNAKE_CASE.

chuỗi f

Mới được giới thiệu trong python 3 là chuỗi f; vì vậy thay vì có print("string", variable, "string")bạn có thể làm:

print(f"string {variable} string")

cho hiệu quả tương tự.

Chức năng

Chia mã của bạn thành từng chức năng nhỏ hơn, thực hiện các tác vụ đơn lẻ. Một vài ví dụ sẽ là, tìm nạp người dùng / mật khẩu từ users.txt, xác thực chi tiết người dùng, đọc thông tin đăng nhập của người dùng, v.v.

if __name__ khối

Đối với script, bạn nên đặt tính năng thực thi của mình vào bên trong if __name__ == "__main__"mệnh đề.

Kiểm soát dòng chảy

Bạn cố gắng mở tệp người dùng hai lần (điều này cũng đúng với tệp điểm). Tiếp theo là định nghĩa hàm, theo sau là mã để người dùng đăng nhập. Sau đó, bạn có câu lệnh nhập đầu tiên, theo sau là một định nghĩa hàm khác và mã sau đó một lần nữa.

Thử nhóm các khối lại với nhau. Trong python (và hầu như tất cả các ngôn ngữ lập trình), nhập là điều đầu tiên (sau shebang). Sau đó là các hằng số toàn cục, các định nghĩa hàm / lớp và sau đó là chính mã script.

with các câu lệnh

Thay vì bạn quản lý các bộ mô tả tệp đã mở và sau đó kiểm soát việc đóng chúng, python có withcâu lệnh kết thúc điều này cho bạn:

with open(your_file, mode) as f:
    something = f.read()
    # f.write(something)

tự động này đóng (và giữ trong phạm vi) trình mô tả tệp.

Các thuộc tính liên kết

Bạn có phần tử người chơi, có các thuộc tính liên quan như tên người dùng, player_id, điểm số. Điều này có thể được đưa vào một lớp, thay vì duy trì 10 biến khác nhau cho mỗi người chơi.

Phương pháp có sẵn

Tại nhiều vị trí trong mã của bạn, bạn đang thực hiện một .replace("\n", ""). Điều này không thực sự cần thiết, vì các đối tượng chuỗi trong python có một .strip()phương thức để xóa tất cả các khoảng trắng (và các dòng mới).

Tương tự, bạn cố gắng nắm bắt một lỗi FileNotFoundErrorduy nhất để nêu ra một lỗi khác vì lý do tương tự. Hãy để lỗi được xác định cụ thể cho công việc làm điều đó. Không cần chụp nếu bạn muốn chương trình không thành công trong trường hợp thiếu tệp.


Viết lại

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()

GHI CHÚ

Việc viết lại cho phép nhiều người chơi, cùng với tùy chọn để đặt nhiều vòng ( NUM_PLAYERSvà NUM_ROUNDS).

4 GrajdeanuAlex Oct 21 2020 at 14:37

Có rất nhiều thứ trong mã của bạn có thể được cấu trúc lại nhưng hãy bắt đầu lại từ đầu với một số hướng dẫn định kiểu Python (còn được gọi là PEP8 )

Nhập khẩu

Bạn nên viết tất cả các lần nhập ở đầu tệp của bạn.

Đặt tên

Trong Python, tên của các hàm và biến phải là solid_case d. Đó là, thay vì def Roll()bạn nên có def roll(), thay vì Player1Scorebạn nên có player1_score, v.v. Bạn có ý tưởng. Đọc thêm về nó ở đây

Nói KHÔNG với `;` bằng Python!

Không sử dụng ;trong Python. Nó không cần thiết, và nó khiến tôi nhớ lại khoảng thời gian khó khăn khi sử dụng C / C ++. Em không muốn anh buồn phải không? :(

Chung

Thông thường, bạn nên cố gắng tránh các khối mã nội tuyến. Thật khó để làm theo và nó không có bất kỳ lợi ích nào. Điều này:

if Player1Score > Player2Score: Winner = 1

Nên viết là:

if Player1Score > Player2Score: 
    Winner = 1

Điều đó nói rằng, mã của bạn cho đến nay, khi xem xét lời khuyên ở trên, sẽ trông giống như sau:

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()

Bây giờ, điều này đã tốt hơn một chút. Hãy thảo luận về việc triển khai thực tế ngay bây giờ.

Đây:

try:
    file = open("Users.txt", "r")
except FileNotFoundError:
    raise SystemExit("User file not found")
file = open("Users.txt", "r")

Bạn đang cố gắng mở một tệp và nếu nó không tồn tại, bạn sẽ nâng cao và ngoại lệ. Không có gì sai với điều này, nhưng hãy lưu ý cách bạn mở tệp hai lần nếu không có ngoại lệ nào được nêu ra. Nếu bạn muốn kiểm tra xem tệp có tồn tại hay không, bạn có thể sử dụng osmô-đun để xác nhận xem đường dẫn tệp có tồn tại hay không và tạo một hàm thực hiện điều đó. Ngoài ra, hãy đặt đường dẫn tệp thành một hằng số và đặt nó ở đầu tập lệnh của bạn:

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

Để gọi hàm, bạn có thể làm:

if check_path(USERS_FILEPATH):
    # do things here

Có một vài điều mới ở đây. Đầu tiên, hãy lưu ý cách tôi đã thêm một chuỗi doc vào hàm này và cách dễ dàng để biết nó thực sự hoạt động như thế nào. Thứ hai, hãy lưu ý việc sử dụng chức năng này trên bất kỳ tệp nào khác mà trò chơi của bạn có thể sử dụng dễ dàng như thế nào. Thứ ba, hãy xem cách chuỗi được định dạng khi tôi nêu ra một ngoại lệ. Bạn có thể đọc thêm về định dạng chuỗi của Python tại đây .

// phải đi ngay bây giờ