เมื่อคุณเรียนรู้การเขียนโปรแกรมเป็นครั้งแรก คุณมองหา (หรืออาจได้รับมอบหมาย) โครงการที่ส่งเสริมแนวคิดพื้นฐาน แต่บ่อยแค่ไหนที่คุณเมื่อคุณได้รับความรู้และประสบการณ์มากขึ้น ทบทวนโครงการเริ่มต้นเหล่านั้นจากมุมมองของโปรแกรมเมอร์ขั้นสูง?
ในบทความนี้ฉันต้องการทำอย่างนั้น ฉันต้องการทบทวนโครงการสำหรับผู้เริ่มต้นทั่วไป การนำเกม “Rock Paper Scissors” ไปใช้ใน Python ด้วยความรู้ที่ฉันได้รับจากประสบการณ์การเขียนโปรแกรม Python เกือบแปดปี
สารบัญ
- กฎของ “กรรไกรกระดาษหิน”
- ความต้องการ
- โซลูชัน “สำหรับผู้เริ่มต้น”
- โซลูชันขั้นสูง #1
- โซลูชันขั้นสูง #2
- โซลูชันขั้นสูง #3
- บทสรุป
- อะไรเป็นแรงบันดาลใจให้บทความนี้?
กฎของ “กรรไกรกระดาษหิน”
ก่อนดำดิ่งลงไปในโค้ด เรามาตั้งฉากโดยสรุปวิธีการเล่น “Rock Paper Scissors” กันก่อน ผู้เล่นสองคนแต่ละคนเลือกหนึ่งในสามรายการ: หิน กระดาษ หรือกรรไกร ผู้เล่นเปิดเผยการเลือกของพวกเขาให้กันและกันและผู้ชนะจะถูกกำหนดโดยกฎต่อไปนี้:
- ร็อคเต้นกรรไกร
- กรรไกรตีกระดาษ
- กระดาษเต้นร็อค
เมื่อโตขึ้น ฉันกับเพื่อนใช้ “กรรไกรตัดกระดาษ” เพื่อแก้ปัญหาทุกประเภท ใครจะได้เล่นเป็นคนแรกในวิดีโอเกมเล่นคนเดียว? ใครได้รับโซดากระป๋องสุดท้าย? ใครต้องไปรับเรื่องที่เราเพิ่งทำไป? ของสำคัญ.
ความต้องการ
มาร่างข้อกำหนดบางประการสำหรับการนำไปปฏิบัติกัน แทนที่จะสร้างเกมที่เต็มรูปแบบ ให้เน้นที่การเขียนฟังก์ชันที่เรียกว่า play()
ที่ยอมรับสองอาร์กิวเมนต์สตริง — ตัวเลือกของ "rock"
, "paper"
หรือ "scissors"
ที่ผู้เล่นแต่ละคนเลือก – และส่งคืนสตริงที่ระบุ ผู้ชนะ (เช่น "paper wins"
) หรือหากผลการแข่งขันเท่ากัน (เช่น "tie"
)
ต่อไปนี้คือตัวอย่างวิธีการเรียก play()
และสิ่งที่ส่งคืน:
>>> play("rock", "paper") 'rock wins' >>> play("scissors", "paper") 'scissors wins' >>> play("paper", "paper") 'tie'
หากอาร์กิวเมนต์หนึ่งหรือทั้งสองอาร์กิวเมนต์ไม่ถูกต้อง ซึ่งหมายความว่าไม่ใช่หนึ่งใน "rock"
, "paper"
หรือ "scissors"
ดังนั้น play()
ควรมีข้อยกเว้นบางประการ
play()
ควรจะ สับเปลี่ยน ด้วย นั่นคือ play("rock", "paper")
ควรคืนค่าเหมือนกับ play("paper", "rock")
โซลูชัน “สำหรับผู้เริ่มต้น”
ในการกำหนดพื้นฐานสำหรับการเปรียบเทียบ ให้พิจารณาว่าผู้เริ่มต้นใช้งานฟังก์ชัน play()
ได้อย่างไร หากผู้เริ่มต้นคนนี้เป็นเหมือนฉันเมื่อตอนที่ฉันเรียนการเขียนโปรแกรมครั้งแรก พวกเขาอาจจะเริ่มเขียนประโยค if
จำนวนมาก:
def play(player1_choice, player2_choice): if player1_choice == "rock": if player2_choice == "rock": return "tie" elif player2_choice == "paper": return "paper wins" elif player2_choice == "scissors": return "rock wins" else: raise ValueError(f"Invalid choice: {player2_choice}") elif player1_choice == "paper": if player2_choice == "rock": return "paper wins" elif player2_choice == "paper": return "tie" elif player2_choice == "scissors": return "rock wins" else: raise ValueError(f"Invalid choice: {player2_choice}") elif player1_choice == "scissors": if player2_choice == "rock": return "rock wins" elif player2_choice == "paper": return "scissors wins" elif player2_choice == "scissors": return "tie" else: raise ValueError(f"Invalid choice: {player2_choice}") else: raise ValueError(f"Invalid choice: {player1_choice}")
พูดอย่างเคร่งครัดไม่มีอะไร ผิดปกติ กับรหัสนี้ มันทำงานโดยไม่มีข้อผิดพลาดและตรงตามข้อกำหนดทั้งหมด นอกจากนี้ยังคล้ายกับการใช้งานระดับสูงจำนวนมากสำหรับการค้นหาของ Google “rock paper scissors python”
โปรแกรมเมอร์ที่มีประสบการณ์จะรับรู้ถึงกลิ่นโค้ดจำนวนหนึ่งได้อย่างรวดเร็ว โดยเฉพาะอย่างยิ่ง โค้ดซ้ำกันและมีเส้นทางการดำเนินการที่เป็นไปได้มากมาย
โซลูชันขั้นสูง #1
วิธีหนึ่งในการใช้ “Rock Paper Scissors” จากมุมมองขั้นสูงคือการใช้ประโยชน์จากประเภทพจนานุกรมของ Python พจนานุกรมสามารถแมปไอเท็มกับไอเท็มที่พวกเขาเอาชนะได้ตามกฎของเกม
เรียกพจนานุกรมนี้ว่า loses_to
(การตั้งชื่อยากนะ):
loses_to = { "rock": "scissors", "paper": "rock", "scissors": "paper", }
loses_to
จัดเตรียม API อย่างง่ายสำหรับกำหนดว่ารายการใดจะสูญเสียไปยังรายการอื่น:
>>> loses_to["rock"] 'scissors' >>> loses_to["scissors"] 'paper'
พจนานุกรมมีประโยชน์สองสามประการ คุณสามารถใช้เพื่อ:
- ตรวจสอบรายการที่เลือกโดยตรวจสอบการเป็นสมาชิกหรือเพิ่ม
KeyError
- กำหนดผู้ชนะโดยตรวจสอบว่าค่าสูญเสียไปยังคีย์ที่เกี่ยวข้องหรือไม่
เมื่อคำนึงถึงสิ่งนี้ ฟังก์ชัน play()
สามารถเขียนได้ดังนี้:
def play(player1_choice, player2_choice): if player2_choice == loses_to[player1_choice]: return f"{player1_choice} wins" if player1_choice == loses_to[player2_choice]: return f"{player2_choice} wins" if player1_choice == player2_choice: return "tie"
ในเวอร์ชันนี้ play()
ใช้ประโยชน์จาก KeyError
ในตัวที่สร้างโดยพจนานุกรม loses_to
เมื่อพยายามเข้าถึงคีย์ที่ไม่ถูกต้อง สิ่งนี้จะตรวจสอบตัวเลือกของผู้เล่นได้อย่างมีประสิทธิภาพ ดังนั้นหากผู้เล่นคนใดคนหนึ่งเลือกไอเท็มที่ไม่ถูกต้อง เช่น "lizard"
หรือ 1234
— play()
ทำให้เกิด KeyError
:
>>> play("lizard", "paper") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in play KeyError: 'lizard'
แม้ว่า KeyError
จะไม่มีประโยชน์เท่ากับ ValueError
ที่มีข้อความอธิบาย แต่ก็ยังสามารถทำงานให้เสร็จได้
ฟังก์ชั่น play()
ใหม่นั้นง่ายกว่าฟังก์ชั่นดั้งเดิมมาก แทนที่จะจัดการกับกรณีที่ชัดเจนจำนวนมาก มีเพียงสามกรณีที่ต้องตรวจสอบ:
-
player2_choice
แพ้player1_choice
-
player1_choice
แพ้player2_choice
-
player1_choice
และplayer2_choice
เหมือนกัน
มีคดีที่สี่ซ่อนอยู่ อย่างไรก็ตาม ที่คุณเกือบจะต้องเหล่เพื่อดู กรณีนั้นเกิดขึ้นเมื่อไม่มีกรณีอื่นใดอีกสามกรณีเป็นจริง ในกรณีนี้ play()
จะส่งคืนค่า None
แต่… กรณีนี้จะเกิดขึ้นได้จริงหรือ? จริงๆแล้วไม่ มันไม่สามารถ ตามกฎของเกม ถ้าผู้เล่นที่ 1 ไม่แพ้ผู้เล่นที่ 2 และ ผู้เล่นที่ 2 ไม่แพ้ผู้เล่นที่ 1 แสดงว่าผู้เล่นทั้งสองต้องเลือกรายการเดียวกัน
กล่าวอีกนัยหนึ่ง เราสามารถลบส่วนสุดท้าย if
บล็อกจาก play()
และเพียงแค่ return "tie"
หากไม่มีอีกสองอัน if
บล็อกดำเนินการ:
def play(player1_choice, player2_choice): if player2_choice == loses_to[player1_choice]: return f"{player1_choice} wins" if player1_choice == loses_to[player2_choice]: return f"{player2_choice} wins" return "tie"
เราได้ทำการแลกเปลี่ยน เราได้เสียสละความชัดเจน — ฉันขอยืนยันว่าจำเป็นต้องมีภาระด้านความรู้ความเข้าใจมากขึ้นเพื่อทำความเข้าใจว่าฟังก์ชัน play()
ด้านบนทำงานอย่างไรเมื่อเปรียบเทียบกับเวอร์ชัน “เริ่มต้น” เพื่อลดฟังก์ชันและหลีกเลี่ยงสถานะที่ไม่สามารถเข้าถึงได้
การแลกเปลี่ยนนี้คุ้มค่าหรือไม่? ฉันไม่รู้. ความบริสุทธิ์เอาชนะการปฏิบัติจริงหรือไม่?
โซลูชันขั้นสูง #2
โซลูชันก่อนหน้านี้ใช้งานได้ดี สามารถอ่านได้ และ สั้นกว่าโซลูชัน “สำหรับผู้เริ่มต้น” มาก แต่ก็ไม่ค่อยยืดหยุ่นเท่าไหร่ กล่าวคือ ไม่สามารถจัดการกับรูปแบบต่างๆ ของ “Rock Paper Scissors” ได้โดยไม่ต้องเขียนตรรกะบางอย่างใหม่
ตัวอย่างเช่น มีรูปแบบที่เรียกว่า “Rock Paper Scissors Lizard Spock” ที่มีชุดกฎที่ซับซ้อนมากขึ้น:
- ร็อคทุบกรรไกรและจิ้งจก
- กระดาษเต้นร็อคและสป็อค
- กรรไกรตีกระดาษและจิ้งจก
- จิ้งจกตีสป็อคและกระดาษ
- สป็อคตีกรรไกรและร็อค
คุณจะปรับโค้ดเพื่อจัดการกับรูปแบบนี้ได้อย่างไร
ขั้นแรก แทนที่ค่าสตริงในพจนานุกรม loses_to
ด้วยชุด Python แต่ละชุดประกอบด้วยรายการทั้งหมดที่สูญเสียไปยังคีย์ที่เกี่ยวข้อง นี่คือลักษณะของ loses_to
เวอร์ชันนี้เมื่อใช้กฎ “Rock Paper Scissors” ดั้งเดิม:
loses_to = { "rock": {"scissors"}, "paper": {"rock"}, "scissors": {"paper"}, }
ทำไมต้องชุด? เพราะเราสนใจแต่ของ ที่ เสียให้กับคีย์ที่ให้มาเท่านั้น เราไม่สนใจเกี่ยวกับ ลำดับ ของรายการเหล่านั้น
ในการปรับ play()
เพื่อจัดการกับพจนานุกรม loses_to
ใหม่ สิ่งที่คุณต้องทำคือแทนที่ ==
ด้วย in
เพื่อใช้การตรวจสอบสมาชิกแทนการตรวจสอบความเท่าเทียมกัน:
def play(player1_choice, player2_choice): # vv--- replace == with in if player2_choice in loses_to[player1_choice]: return f"{player1_choice} wins" # vv--- replace == with in if player1_choice in loses_to[player2_choice]: return f"{player2_choice} wins" return "tie"
ใช้เวลาสักครู่เพื่อเรียกใช้รหัสนี้และตรวจสอบว่าทุกอย่างยังใช้งานได้
ตอนนี้แทนที่ loses_to
ด้วยพจนานุกรมที่ใช้กฎสำหรับ “Rock Paper Scissors Lizard Spock” นี่คือสิ่งที่ดูเหมือน:
loses_to = { "rock": {"scissors", "lizard"}, "paper": {"rock", "spock"}, "scissors": {"paper", "lizard"}, "lizard": {"spock", "paper"}, "spock": {"scissors", "rock"}, }
ฟังก์ชันใหม่ play()
ทำงานร่วมกับกฎใหม่เหล่านี้ได้อย่างไม่มีที่ติ:
>>> play("rock", "paper") 'paper wins' >>> play("spock", "lizard") 'lizard wins' >>> play("spock", "spock") 'tie'
ในความคิดของฉัน นี่เป็นตัวอย่างที่ดีของพลังของการเลือกโครงสร้างข้อมูลที่ถูกต้อง ด้วยการใช้ชุดเพื่อแสดงรายการทั้งหมดที่สูญเสียไปยังคีย์ในพจนานุกรม loses_to
และแทนที่ ==
ด้วย in
คุณได้สร้างวิธีแก้ปัญหาทั่วไปมากขึ้นโดยไม่ต้องเพิ่มโค้ดแม้แต่บรรทัดเดียว
โซลูชันขั้นสูง #3
ลองย้อนกลับไปและใช้แนวทางที่แตกต่างออกไปเล็กน้อย แทนที่จะค้นหารายการในพจนานุกรมเพื่อตัดสินผู้ชนะ เราจะสร้างตารางข้อมูลที่เป็นไปได้ทั้งหมดและผลลัพธ์
คุณยังคงต้องการบางสิ่งเพื่อแสดงถึงกฎของเกม ดังนั้นเรามาเริ่มด้วยคำ loses_to
จากวิธีแก้ปัญหาก่อนหน้านี้:
loses_to = { "rock": {"scissors"}, "paper": {"rock"}, "scissors": {"paper"}, }
ถัดไป เขียนฟังก์ชัน build_results_table()
ที่ใช้พจนานุกรมกฎ เช่น loses_to
และส่งคืนพจนานุกรมใหม่ที่จับคู่สถานะกับผลลัพธ์ ตัวอย่างเช่น นี่คือสิ่งที่ build_results_table()
ควรส่งคืนเมื่อถูกเรียกด้วย loses_to
เป็นอาร์กิวเมนต์:
>>> build_results_table(loses_to) { {"rock", "scissors"}: "rock wins", {"paper", "rock"}: "paper wins", {"scissors", "paper"}: "scissors wins", {"rock", "rock"}: "tie", {"paper", "paper"}: "tie", {"scissors", "scissors"}: "tie", }
ถ้าคุณคิดว่ามีบางอย่างดูเหมือนอยู่ที่นั่น คุณคิดถูก มีสองสิ่งผิดปกติในพจนานุกรมนี้:
- ชุดเช่น
{"rock", "rock"}
ไม่มีอยู่จริง ชุดต้องไม่มีองค์ประกอบซ้ำ ในสถานการณ์จริง ชุดนี้จะดูเหมือน{"rock"}
คุณไม่จำเป็นต้องกังวลเกี่ยวกับเรื่องนี้มากเกินไป ฉันเขียนเซตเหล่านั้นด้วยสององค์ประกอบเพื่อให้ชัดเจนว่าสถานะเหล่านั้นเป็นตัวแทนของอะไร - คุณไม่สามารถใช้ชุดเป็นคีย์พจนานุกรม แต่เรา ต้องการ ใช้เซตเพราะมันดูแลการสลับสับเปลี่ยนให้เราโดยอัตโนมัติ นั่นคือ
{"rock", "paper"}
และ{"paper", "rock"}
ประเมินว่าเท่ากันและควรส่งคืนผลลัพธ์เดียวกันเมื่อค้นหา
วิธีแก้ไขคือใช้ ประเภท frozenset
ในตัวของ Python เช่นเดียวกับชุด frozensets
การตรวจสอบสมาชิกภาพ และเปรียบเทียบเท่ากับ set
อื่นหรือชุด frozenset
เฉพาะในกรณีที่ทั้งสองชุดมีสมาชิกเหมือนกัน อย่างไรก็ตาม ต่างจากชุดมาตรฐาน อินสแตนซ์ frozenset
จะไม่เปลี่ยนรูป เป็นผลให้สามารถใช้เป็นคีย์พจนานุกรมได้
ในการใช้งาน build_results_table()
คุณสามารถวนซ้ำแต่ละคีย์ในพจนานุกรม loses_to
และสร้างอินสแตนซ์ frozenset
สำหรับแต่ละค่าสตริงในชุดที่สอดคล้องกับคีย์:
def build_results_table(rules): results = {} for key, values in rules.items(): for value in values: state = frozenset((key, value)) result = f"{key} wins" results[state] = result return results
สิ่งนี้ทำให้คุณได้ประมาณครึ่งทาง:
>>> build_results_table(loses_to) {frozenset({'rock', 'scissors'}): 'rock wins', frozenset({'paper', 'rock'}): 'paper wins', frozenset({'paper', 'scissors'}): 'scissors wins'}
แม้ว่ารัฐที่ส่งผลให้เกิดการเสมอกันจะไม่ครอบคลุม ในการเพิ่มสิ่งเหล่านี้ คุณต้องสร้างอินสแตนซ์ frozenset
สำหรับแต่ละคีย์ในพจนานุกรม rules
ที่แมปกับสตริง "tie"
:
def build_results_table(rules): results = {} for key, values in rules.items(): # Add the tie states results[frozenset((key,))] = "tie" # <-- New # Add the winning states for value in values: state = frozenset((key, value)) result = f"{key} wins" results[state] = result return results
ตอนนี้ค่าที่ส่งคืนโดย build_results_table()
ต้อง:
>>> build_results_table(loses_to) {frozenset({'rock'}): 'tie', frozenset({'rock', 'scissors'}): 'rock wins', frozenset({'paper'}): 'tie', frozenset({'paper', 'rock'}): 'paper wins', frozenset({'scissors'}): 'tie', frozenset({'paper', 'scissors'}): 'scissors wins'}
ทำไมต้องผ่านปัญหาทั้งหมดนี้? build_results_table()
ดูซับซ้อนกว่าฟังก์ชัน play()
จากโซลูชันก่อนหน้านี้
คุณไม่ผิด แต่ฉันต้องการชี้ให้เห็นว่ารูปแบบนี้มีประโยชน์มาก หากมีสถานะในโปรแกรมจำนวนจำกัด บางครั้งคุณอาจเห็นความเร็วที่เพิ่มขึ้นอย่างมากโดยการคำนวณผลลัพธ์ล่วงหน้าสำหรับสถานะเหล่านั้นทั้งหมด นี่อาจเกินความสามารถสำหรับบางสิ่งที่เรียบง่ายเช่น “Rock Paper Scissors” แต่อาจสร้างความแตกต่างอย่างมากในสถานการณ์ที่มีรัฐหลายแสนหรือหลายล้านรัฐ
สถานการณ์หนึ่งในชีวิตจริงที่แนวทางประเภทนี้สมเหตุสมผลคือ อัลกอริธึม Q-learning ที่ ใช้ในแอปพลิเคชันการเรียนรู้แบบเสริมกำลัง ในอัลกอริธึมนั้น ตารางสถานะ — ตาราง Q — จะถูกรักษาไว้ซึ่งแมปแต่ละสถานะกับชุดของความน่าจะเป็นสำหรับการกระทำที่กำหนดไว้ล่วงหน้าบางอย่าง เมื่อตัวแทนได้รับการฝึกอบรมแล้ว จะสามารถเลือกและดำเนินการตามความน่าจะเป็นสำหรับสถานะที่สังเกตได้ จากนั้นจึงดำเนินการตามนั้น
บ่อยครั้ง ตารางแบบเดียวกับที่สร้างโดย build_results_table()
จะถูกคำนวณและจัดเก็บไว้ในไฟล์ เมื่อโปรแกรมทำงาน ตารางที่คำนวณไว้ล่วงหน้าจะถูกโหลดลงในหน่วยความจำแล้วใช้โดยแอปพลิเคชัน
ดังนั้น เมื่อคุณมีฟังก์ชันที่สามารถสร้างตารางผลลัพธ์ได้แล้ว ให้กำหนดตารางสำหรับ loses_to
ให้กับตัวแปร outcomes
:
outcomes = build_results_table(loses_to)
ตอนนี้คุณสามารถเขียนฟังก์ชัน play()
ที่ค้นหาสถานะในตาราง outcomes
ตามอาร์กิวเมนต์ที่ส่งไปเล่นแล้วส่งคืนผลลัพธ์:
def play(player1_choice, player2_choice): state = frozenset((player1_choice, player2_choice)) return outcomes[state]
play()
เวอร์ชันนี้เรียบง่ายอย่างเหลือเชื่อ โค้ดแค่สองบรรทัด! คุณสามารถเขียนเป็นบรรทัดเดียวได้หากต้องการ:
def play(player1_choice, player2_choice): return outcomes[frozenset((player1_choice, player2_choice))]
โดยส่วนตัวแล้ว ฉันชอบเวอร์ชันสองบรรทัดมากกว่าเวอร์ชันบรรทัดเดียว
ฟังก์ชัน play()
ใหม่ของคุณเป็นไปตามกฎของเกมและมีการสับเปลี่ยน:
>>> play("rock", "paper") 'paper wins' >>> play("paper", "rock") 'paper wins'
play()
ยังทำให้เกิด KeyError
หากถูกเรียกด้วยตัวเลือกที่ไม่ถูกต้อง แต่ตอนนี้ข้อผิดพลาดมีประโยชน์น้อยกว่าเมื่อตั้งค่าคีย์ของพจนานุกรม outcomes
:
>>> play("lizard", "paper") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 21, in play return outcomes[state] KeyError: frozenset({'lizard', 'paper'})
อย่างไรก็ตาม ข้อผิดพลาดที่คลุมเครือไม่น่าจะเป็นปัญหา ในบทความนี้ คุณกำลังใช้งานฟังก์ชัน play()
เท่านั้น ในการใช้งาน “Rock Paper Scissors” อย่างแท้จริง คุณน่าจะจับข้อมูลที่ผู้ใช้ป้อนและตรวจสอบว่าก่อนที่จะผ่านตัวเลือกที่ผู้ใช้เลือก play()
ดังนั้นการใช้งานนี้เร็วกว่าการติดตั้งก่อนหน้านี้มากน้อยเพียงใด นี่คือผลการจับเวลาบางส่วนเพื่อเปรียบเทียบประสิทธิภาพของการใช้งานต่างๆ โดยใช้ฟังก์ชันเวทย์มนตร์ %timeit
ของ IPython play1()
เป็นเวอร์ชันของ play()
จากส่วน Advanced Solution #2 และ play2()
เป็นเวอร์ชันปัจจุบัน:
In [1]: %timeit play1("rock", "paper") 141 ns ± 0.0828 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each) In [2]: %timeit play2("rock", "paper") 188 ns ± 0.0944 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
ในกรณีนี้ โซลูชันที่ใช้ตารางผลลัพธ์จริง ๆ แล้ว ช้า กว่าการใช้งานครั้งก่อน ผู้ร้ายที่นี่คือบรรทัดที่แปลงอาร์กิวเมนต์ของฟังก์ชันเป็น frozenset
ดังนั้น แม้ว่าการค้นหาพจนานุกรมจะรวดเร็ว และการสร้างตารางที่แมปสถานะกับผลลัพธ์สามารถปรับปรุง ประสิทธิภาพ ได้ แต่คุณต้องระวังเพื่อหลีกเลี่ยงการดำเนินการที่มีราคาแพงซึ่งอาจจบลงด้วยการปฏิเสธสิ่งที่คุณคาดหวังว่าจะได้รับ
บทสรุป
ฉันเขียนบทความนี้เป็นแบบฝึกหัด ฉันอยากรู้ว่าฉันจะเข้าถึงโครงการเริ่มต้นเช่น “Rock Paper Scissors” ใน Python ได้อย่างไร เพราะตอนนี้ฉันมีประสบการณ์มากมาย ฉันหวังว่าคุณจะพบว่ามันน่าสนใจ หากคุณมีแรงบันดาลใจในการทบทวนโครงการเริ่มต้นของคุณเอง ฉันคิดว่าฉันทำงานเสร็จแล้ว!
หากคุณทบทวนโครงการเริ่มต้นของคุณเองหรือหากคุณเคยทำมาแล้วในอดีต โปรดแจ้งให้เราทราบว่าผลเป็นอย่างไรในความคิดเห็น คุณได้เรียนรู้อะไรใหม่หรือไม่? โซลูชันใหม่ของคุณแตกต่างจากวิธีที่คุณเขียนเมื่อเป็นมือใหม่มากน้อยเพียงใด
อะไรเป็นแรงบันดาลใจให้บทความนี้?
Miguel Raz Guzmán Macedo เพาะเลี้ยงสัตว์น้ำจากโลกของ Julia ทำให้ฉันเข้าสู่ บล็อกโพสต์ โดย Mosè Giordano Mosè ใช้ประโยชน์จากกระบวนทัศน์การ จัดส่ง ที่หลากหลายของ Julia ในการเขียน “Rock Paper Scissors” ด้วยโค้ดที่น้อยกว่าสิบบรรทัด:
ฉันจะไม่ลงรายละเอียดว่าโค้ดของ Mosè ทำงานอย่างไร Python ไม่สนับสนุนแม้กระทั่งการจัดส่งหลายรายการตั้งแต่แกะกล่อง (แม้ว่าคุณสามารถใช้มันได้ด้วยความช่วยเหลือจาก แพ็คเกจ plum
)
บทความของ Mosè ทำให้จิตใจของฉันหมุนวน และสนับสนุนให้ฉันทบทวน “Rock Paper Scissors” ใน Python เพื่อคิดว่าฉันจะเข้าถึงโครงการในรูปแบบที่ต่างไปจากเดิมได้อย่างไร
ขณะที่ฉันกำลังแก้ปัญหานี้ ฉันได้รับการเตือนถึงบทความที่ฉันตรวจสอบสำหรับ Real Python เมื่อนานมาแล้ว:
ปรากฎว่าสองวิธีแก้ปัญหาแรกที่ฉัน “คิดค้น” ในที่นี้คล้ายกับวิธีแก้ปัญหาที่ Chris Wilkerson ผู้เขียนบทความของ Real Python คิดขึ้นมา
โซลูชันของ Chris มีคุณสมบัติครบถ้วนมากขึ้น มันมีกลไกการเล่นเกมแบบโต้ตอบและแม้กระทั่งใช้ประเภท Enum
ของ Python เพื่อแสดงรายการเกม นั่นต้องเป็นที่ที่ฉันได้ยินชื่อ “Rock Paper Scissors Lizard Spock” เป็นครั้งแรก
คุณสนุกกับบทความนี้หรือไม่? ติดตามข่าวสารล่าสุดเกี่ยวกับเนื้อหาทั้งหมดของฉัน เข้าใช้หลักสูตรของฉันก่อนใคร และรับเนื้อหาที่คัดสรรจากชุมชน Python และ Julia ส่งตรงไปยังกล่องจดหมายของคุณทุกวันศุกร์โดยสมัคร รับจดหมายข่าว Curious About Code รายสัปดาห์ของฉัน