diff --git a/README.md b/README.md new file mode 100644 index 0000000..5035524 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# 🎮 Rock Paper Scissors - Ultimate GUI Edition + +A colorful, kid-friendly, and feature-rich **Rock Paper Scissors** game built using **Python Tkinter**. + +!\[Screenshot Placeholder] + +--- + +## ✨ Features + +* 🎨 **Modern GUI** using Tkinter (bright colors, emojis, fun fonts) +* 📊 **Leaderboard** with wins, losses, ties, streak, and win rate +* 📜 **Game History** showing the last 10 matches with moves and results +* 🤖 **Adaptive AI** that learns from player patterns after a few rounds +* 💾 **Persistent Save System** with JSON file to store stats and history +* 🔄 **Reset Option** and easy-to-use GUI controls +* 🚪 **Quit Button** with auto-save functionality + +--- + +## 📂 Directory Structure + +``` +📦 Rock Paper Scissors Ultimate GUI + ┣ 📜 rps_gui.py + ┣ 📜 rps_gui_save.json # Auto-generated after first run + ┗ 📜 README.md +``` + +--- + +## 🚀 How to Run + +### 1️⃣ Install Requirements (Linux / Debian / Kali) + +```bash +sudo apt update +sudo apt install python3-tk +``` + +### 2️⃣ Run the Program + +```bash +python3 stone-paper-scissors.py +``` + +--- + +## 💡 How It Works + +* **GUI with Tkinter** for all interaction. +* **JSON** file stores progress automatically. +* **Adaptive AI** counters your most frequent choices. +* **Leaderboards & History** displayed via popup windows. + +--- + +## 🏆 Why This Project? + +* Educational example for beginners. +* More polished than typical CLI games. +* Great foundation for extending into more complex projects (adding sounds, animations, etc). + +--- + + +## 🔥 Future Enhancements (Optional) + +* 🎵 Add sound effects +* 🏅 Unlockable badges +* 🎉 Cute animations +* 🌐 Deploy as a simple desktop app via PyInstaller + +--- + +--- + +## 📄 License + +MIT License + +--- + +## 📢 Contributions + +Pull Requests and feature ideas are welcome! + +--- + +**Enjoy playing & learning! 🎮✨** diff --git a/stone-paper-scissors.py b/stone-paper-scissors.py new file mode 100644 index 0000000..ac04aab --- /dev/null +++ b/stone-paper-scissors.py @@ -0,0 +1,210 @@ +import tkinter as tk +import random +import json +import os +from datetime import datetime + +MOVES = {'R': 'Rock 🪨', 'P': 'Paper 📄', 'S': 'Scissors ✂️'} + +class RPSGame: + def __init__(self, root): + self.root = root + self.root.title("🎉 Rock Paper Scissors Ultimate 🎉") + self.root.geometry("500x600") + self.root.configure(bg="#FFFAE3") + + self.wins = 0 + self.losses = 0 + self.ties = 0 + self.streak = 0 + self.history = [] + self.load_data() + + self.build_ui() + + def build_ui(self): + tk.Label(self.root, text="ROCK PAPER SCISSORS!", font=("Comic Sans MS", 28, "bold"), + bg="#FFFAE3", fg="#FF6B6B").pack(pady=20) + + self.stats_label = tk.Label(self.root, font=("Comic Sans MS", 14), + bg="#FFFAE3", fg="#444") + self.stats_label.pack(pady=10) + + self.result_label = tk.Label(self.root, font=("Comic Sans MS", 20, "bold"), + width=30, height=2, bg="#FFFAE3") + self.result_label.pack(pady=20) + + btn_frame = tk.Frame(self.root, bg="#FFFAE3") + btn_frame.pack(pady=20) + + rock_btn = tk.Button(btn_frame, text="🪨 Rock", command=lambda: self.play('R')) + paper_btn = tk.Button(btn_frame, text="📄 Paper", command=lambda: self.play('P')) + scissors_btn = tk.Button(btn_frame, text="✂️ Scissors", command=lambda: self.play('S')) + + for btn in (rock_btn, paper_btn, scissors_btn): + btn.config(font=("Comic Sans MS", 14, "bold"), + bg="#FFD93D", fg="#444", + activebackground="#FF6B6B", activeforeground="#fff", + width=10, height=2, bd=4, relief="groove", cursor="hand2") + btn.pack(side="left", padx=15) + + tk.Button(self.root, text="📋 View History", command=self.show_history, + font=("Comic Sans MS", 12), bg="#5CD859", fg="white", + width=20, height=2).pack(pady=10) + + tk.Button(self.root, text="🏆 View Leaderboard", command=self.show_leaderboard, + font=("Comic Sans MS", 12), bg="#FF6B6B", fg="white", + width=20, height=2).pack(pady=10) + + tk.Button(self.root, text="🔄 Reset Stats", command=self.reset_game, + font=("Comic Sans MS", 12), bg="#FFD93D", fg="#444", + width=20, height=2).pack(pady=10) + + tk.Button(self.root, text="🚪 Quit", command=self.quit_game, + font=("Comic Sans MS", 12), bg="#FF6B6B", fg="white", + width=20, height=2).pack(pady=10) + + self.update_stats() + + def load_data(self): + if os.path.exists('rps_gui_save.json'): + try: + with open('rps_gui_save.json', 'r') as f: + data = json.load(f) + self.wins = data.get('wins', 0) + self.losses = data.get('losses', 0) + self.ties = data.get('ties', 0) + self.streak = data.get('streak', 0) + self.history = data.get('history', []) + except: + pass + + def save_data(self): + data = { + 'wins': self.wins, + 'losses': self.losses, + 'ties': self.ties, + 'streak': self.streak, + 'history': self.history + } + with open('rps_gui_save.json', 'w') as f: + json.dump(data, f) + + def adaptive_ai(self): + if len(self.history) < 3: + return random.choice(['R', 'P', 'S']) + last_moves = [h['player'] for h in self.history[-3:]] + most_common = max(set(last_moves), key=last_moves.count) + counter = {'R': 'P', 'P': 'S', 'S': 'R'} + return counter[most_common] + + def play(self, user_move): + computer_move = self.adaptive_ai() + result = self.determine_winner(user_move, computer_move) + + self.history.append({ + 'time': datetime.now().strftime("%Y-%m-%d %H:%M"), + 'player': user_move, + 'computer': computer_move, + 'result': result + }) + + feedback = { + 'win': ("You Win! 🥳", "#5CD859"), + 'loss': ("Computer Wins! 😝", "#FF6B6B"), + 'tie': ("It's a Draw! 🤝", "#FFD93D") + } + + text, color = feedback[result] + self.result_label.config(text=f"{MOVES[user_move]} vs {MOVES[computer_move]} — {text}", bg=color) + self.update_stats() + self.save_data() + + def determine_winner(self, player, computer): + if player == computer: + self.ties += 1 + self.streak = 0 + return 'tie' + elif (player == 'R' and computer == 'S') or \ + (player == 'P' and computer == 'R') or \ + (player == 'S' and computer == 'P'): + self.wins += 1 + self.streak += 1 + return 'win' + else: + self.losses += 1 + self.streak = 0 + return 'loss' + + def update_stats(self): + total = self.wins + self.losses + self.ties + win_rate = (self.wins / total * 100) if total > 0 else 0 + self.stats_label.config( + text=f"Wins: {self.wins} Losses: {self.losses} Ties: {self.ties}\n" + f"Streak: {self.streak} Win Rate: {win_rate:.1f}%" + ) + + def show_history(self): + history_window = tk.Toplevel(self.root) + history_window.title("📋 Game History") + history_window.configure(bg="#FFFAE3") + + tk.Label(history_window, text="Last 10 Matches", font=("Comic Sans MS", 16, "bold"), + bg="#FFFAE3").pack(pady=10) + + text = tk.Text(history_window, width=50, height=15, bg="#fff", font=("Comic Sans MS", 12)) + text.pack(padx=10, pady=10) + + for h in self.history[-10:]: + result = "Win" if h['result'] == 'win' else "Loss" if h['result'] == 'loss' else "Tie" + text.insert(tk.END, f"{h['time']}: You chose {MOVES[h['player']]}, Computer chose {MOVES[h['computer']]} — {result}\n") + + text.config(state='disabled') + + def show_leaderboard(self): + leaderboard_window = tk.Toplevel(self.root) + leaderboard_window.title("🏆 Leaderboard") + leaderboard_window.configure(bg="#FFFAE3") + + max_streak = 0 + current_streak = 0 + for h in self.history: + if h['result'] == 'win': + current_streak += 1 + max_streak = max(max_streak, current_streak) + else: + current_streak = 0 + + total_games = len(self.history) + win_rate = (self.wins / total_games * 100) if total_games > 0 else 0 + + tk.Label(leaderboard_window, text="Your Leaderboard", font=("Comic Sans MS", 16, "bold"), + bg="#FFFAE3").pack(pady=10) + + stats = f""" + Total Games: {total_games} + Wins: {self.wins} + Losses: {self.losses} + Ties: {self.ties} + Longest Win Streak: {max_streak} + Current Win Streak: {self.streak} + Win Rate: {win_rate:.1f}% + """ + tk.Label(leaderboard_window, text=stats.strip(), justify='left', + bg="#FFFAE3", font=("Comic Sans MS", 12)).pack(pady=20) + + def reset_game(self): + self.wins = self.losses = self.ties = self.streak = 0 + self.history = [] + self.update_stats() + self.result_label.config(text="", bg="#FFFAE3") + self.save_data() + + def quit_game(self): + self.save_data() + self.root.quit() + + +root = tk.Tk() +app = RPSGame(root) +root.mainloop() diff --git a/stone-paper-sssc.py b/stone-paper-sssc.py deleted file mode 100644 index 47c766f..0000000 --- a/stone-paper-sssc.py +++ /dev/null @@ -1,59 +0,0 @@ -import random, sys - -print("Let's Play ROCK PAPER SCISSORS GAME!") - -wins = 0 -losses = 0 -ties = 0 - -while True: - print("Current streak: %s Wins, %s Losses, %s Ties" % (wins, losses, ties)) - while True: - print("Type 'Q' to quit \n'R' for ROCK, 'P' for PAPER, 'S' for SCISSORS") - playermove = input().upper() - if playermove == "Q": - sys.exit() - if playermove == "R" or playermove == "P" or playermove == "S": - break - - if playermove == "R": - print("ROCK versus...") - if playermove == "P": - print("PAPER versus...") - if playermove == "S": - print("SCISSORS versus...") - - randomNum = random.randint(1, 3) - if randomNum == 1: - compMove = "R" - print("ROCK") - if randomNum == 2: - compMove = "P" - print("PAPER") - if randomNum == 3: - compMove = "S" - print("SCISSORS") - - if playermove == compMove: - print("It's a tie!") - ties += 1 - elif playermove == "R" and compMove == "P": - print("It's a loss!") - losses += 1 - elif playermove == "R" and compMove == "S": - print("It's a win!") - wins += 1 - elif playermove == "P" and compMove == "S": - print("It's a loss!") - losses += 1 - elif playermove == "P" and compMove == "R": - print("It's a win!") - wins += 1 - elif playermove == "S" and compMove == "R": - print("It's a loss!") - losses += 1 - elif playermove == "S" and compMove == "P": - print("It's a win!") - wins += 1 - else: - print("Thanks for trying my game")