From eb46f6b1e0d93d8687bc5b138a6954371279dd1c Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 17 Jul 2025 21:15:38 +0530 Subject: [PATCH 1/8] gave correctc name to file and made a tkinter gui based rock papre scissors --- stone-paper-scissors.py | 210 ++++++++++++++++++++++++++++++++++++++++ stone-paper-sssc.py | 59 ----------- 2 files changed, 210 insertions(+), 59 deletions(-) create mode 100644 stone-paper-scissors.py delete mode 100644 stone-paper-sssc.py 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") From 7efe7a7c0220aac66540621ccabbb1dc091a43f7 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 17 Jul 2025 21:16:08 +0530 Subject: [PATCH 2/8] gave correctc name to file and made a tkinter gui based rock papre scissors --- stone-paper-sssc.py | 210 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 stone-paper-sssc.py diff --git a/stone-paper-sssc.py b/stone-paper-sssc.py new file mode 100644 index 0000000..ac04aab --- /dev/null +++ b/stone-paper-sssc.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() From ea97c60088f58aaefeabe7d7fb6e902cf246b234 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 17 Jul 2025 22:09:55 +0530 Subject: [PATCH 3/8] deleted old file --- stone-paper-sssc.py | 210 -------------------------------------------- 1 file changed, 210 deletions(-) delete mode 100644 stone-paper-sssc.py diff --git a/stone-paper-sssc.py b/stone-paper-sssc.py deleted file mode 100644 index ac04aab..0000000 --- a/stone-paper-sssc.py +++ /dev/null @@ -1,210 +0,0 @@ -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() From d1df7413f4ab7286ce69bb26e5bad074bf792b14 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 22 Jul 2025 21:49:29 +0530 Subject: [PATCH 4/8] added mobile app friendly version of stone paper scissors --- assets/paper.png | Bin 0 -> 7189 bytes assets/rock.png | Bin 0 -> 4432 bytes assets/scissors.png | Bin 0 -> 6001 bytes mobile-stone-paper-scissors.py | 166 +++++++++++++++++++++++++++++++++ rps.kv | 164 ++++++++++++++++++++++++++++++++ 5 files changed, 330 insertions(+) create mode 100644 assets/paper.png create mode 100644 assets/rock.png create mode 100644 assets/scissors.png create mode 100644 mobile-stone-paper-scissors.py create mode 100644 rps.kv diff --git a/assets/paper.png b/assets/paper.png new file mode 100644 index 0000000000000000000000000000000000000000..29d3d346f37965d8cc3d1dfd5eb8873e2bf5275b GIT binary patch literal 7189 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 S+ue3S9#-{j+hfp|pZ^CES8SL7 literal 0 HcmV?d00001 diff --git a/assets/rock.png b/assets/rock.png new file mode 100644 index 0000000000000000000000000000000000000000..1c8ca9e478a9d440ae1c715bac6b473e433d3d78 GIT binary patch literal 4432 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 literal 0 HcmV?d00001 diff --git a/assets/scissors.png b/assets/scissors.png new file mode 100644 index 0000000000000000000000000000000000000000..b15487010a86b1392d6c1f6f0bfb9a1493550936 GIT binary patch literal 6001 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 literal 0 HcmV?d00001 diff --git a/mobile-stone-paper-scissors.py b/mobile-stone-paper-scissors.py new file mode 100644 index 0000000..940dc97 --- /dev/null +++ b/mobile-stone-paper-scissors.py @@ -0,0 +1,166 @@ +from kivy.app import App +from kivy.lang import Builder +from kivy.uix.screenmanager import ScreenManager, Screen +from kivy.properties import StringProperty, NumericProperty, ListProperty +from kivy.uix.behaviors import ButtonBehavior +from kivy.uix.image import Image +from datetime import datetime +import random +import json +import os + + +class ImageButton(ButtonBehavior, Image): + pass + + +MOVES = {'R': 'Rock', 'P': 'Paper', 'S': 'Scissors'} + + +class HomeScreen(Screen): + pass + + +class GameScreen(Screen): + result_text = StringProperty("") + result_bg_color = ListProperty([1, 1, 1, 1]) + + wins = NumericProperty(0) + losses = NumericProperty(0) + ties = NumericProperty(0) + streak = NumericProperty(0) + + def on_pre_enter(self): + self.load_data() + self.update_stats() + + def adaptive_ai(self): + if len(self.manager.history) < 3: + return random.choice(['R', 'P', 'S']) + last_moves = [h['player'] for h in self.manager.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.manager.history.append({ + 'time': datetime.now().strftime("%Y-%m-%d %H:%M"), + 'player': user_move, + 'computer': computer_move, + 'result': result + }) + + feedback = { + 'win': ("You Win!", [0.36, 0.85, 0.35, 1]), + 'loss': ("Computer Wins!", [0.95, 0.42, 0.42, 1]), + 'tie': ("It's a Draw!", [0.99, 0.85, 0.24, 1]) + } + text, color = feedback[result] + self.result_text = f"{MOVES[user_move]} vs {MOVES[computer_move]} — {text}" + self.result_bg_color = 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.ids.stats_label.text = f"Wins: {self.wins} Losses: {self.losses} Ties: {self.ties}\nStreak: {self.streak} Win Rate: {win_rate:.1f}%" + + def load_data(self): + if os.path.exists('rps_kivy_save.json'): + try: + with open('rps_kivy_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.manager.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.manager.history + } + with open('rps_kivy_save.json', 'w') as f: + json.dump(data, f) + + def reset_game(self): + self.wins = self.losses = self.ties = self.streak = 0 + self.manager.history = [] + self.update_stats() + self.result_text = "" + self.result_bg_color = [1, 1, 1, 1] + self.save_data() + + +class HistoryScreen(Screen): + def on_pre_enter(self): + self.ids.history_text.text = "\n".join([ + f"{h['time']} | {MOVES[h['player']]} vs {MOVES[h['computer']]} : {h['result'].capitalize()}" + for h in self.manager.history[-10:] + ]) or "No history yet." + + +class LeaderboardScreen(Screen): + def on_pre_enter(self): + gs = self.manager.get_screen('game') + max_streak = 0 + current_streak = 0 + for h in self.manager.history: + if h['result'] == 'win': + current_streak += 1 + max_streak = max(max_streak, current_streak) + else: + current_streak = 0 + total = len(self.manager.history) + win_rate = (gs.wins / total * 100) if total > 0 else 0 + + self.ids.leaderboard_label.text = f""" +Total Games: {total} +Wins: {gs.wins} +Losses: {gs.losses} +Ties: {gs.ties} +Longest Win Streak: {max_streak} +Current Streak: {gs.streak} +Win Rate: {win_rate:.1f}% + """ + + +class RPSApp(App): + def build(self): + Builder.load_file('rps.kv') + sm = ScreenManager() + sm.history = [] + sm.add_widget(HomeScreen(name='home')) + sm.add_widget(GameScreen(name='game')) + sm.add_widget(HistoryScreen(name='history')) + sm.add_widget(LeaderboardScreen(name='leaderboard')) + return sm + + +if __name__ == '__main__': + RPSApp().run() diff --git a/rps.kv b/rps.kv new file mode 100644 index 0000000..d524c63 --- /dev/null +++ b/rps.kv @@ -0,0 +1,164 @@ +#:import Window kivy.core.window.Window +#:import dp kivy.metrics.dp +#:import FadeTransition kivy.uix.screenmanager.FadeTransition +#:import ImageButton mobile-stone-paper-scissors.ImageButton + +ScreenManager: + transition: FadeTransition() + HomeScreen: + GameScreen: + HistoryScreen: + LeaderboardScreen: + +: + name: "home" + BoxLayout: + orientation: 'vertical' + padding: dp(20) + spacing: dp(20) + canvas.before: + Color: + rgba: .1, .1, .1, 1 + Rectangle: + pos: self.pos + size: self.size + Label: + text: "Rock Paper Scissors" + font_size: Window.width / 15 + color: 1, 1, 1, 1 + Button: + text: "Start Game" + font_size: Window.width / 25 + size_hint_y: None + height: dp(60) + on_press: root.manager.current = "game" + Button: + text: "Quit" + font_size: Window.width / 25 + size_hint_y: None + height: dp(60) + on_press: app.stop() + +: + name: "game" + BoxLayout: + orientation: 'vertical' + padding: dp(20) + spacing: dp(20) + canvas.before: + Color: + rgba: 0.05, 0.05, 0.05, 1 + Rectangle: + pos: self.pos + size: self.size + Label: + id: stats_label + text: "" + font_size: Window.width / 30 + color: 1, 1, 1, 1 + GridLayout: + cols: 3 + spacing: dp(15) + size_hint_y: None + height: dp(180) + + ImageButton: + source: "assets/rock.png" + on_release: root.play('R') + + ImageButton: + source: "assets/paper.png" + on_release: root.play('P') + + ImageButton: + source: "assets/scissors.png" + on_release: root.play('S') + + Label: + text: root.result_text + font_size: Window.width / 30 + color: 1, 1, 1, 1 + size_hint_y: None + height: dp(120) + canvas.before: + Color: + rgba: root.result_bg_color + RoundedRectangle: + pos: self.pos + size: self.size + radius: [20,] + BoxLayout: + size_hint_y: None + height: dp(50) + spacing: dp(10) + Button: + text: "History" + on_press: root.manager.current = "history" + Button: + text: "Leaderboard" + on_press: root.manager.current = "leaderboard" + Button: + text: "Reset" + on_press: root.reset_game() + Button: + text: "Back to Home" + size_hint_y: None + height: dp(50) + on_press: root.manager.current = "home" + +: + name: "history" + BoxLayout: + orientation: 'vertical' + padding: dp(20) + spacing: dp(20) + canvas.before: + Color: + rgba: 0.1, 0.1, 0.1, 1 + Rectangle: + pos: self.pos + size: self.size + Label: + text: "Last 10 Matches" + font_size: Window.width / 20 + color: 1, 1, 1, 1 + ScrollView: + Label: + id: history_text + size_hint_y: None + height: self.texture_size[1] + text_size: self.width, None + font_size: Window.width / 35 + color: 1, 1, 1, 1 + Button: + text: "Back" + size_hint_y: None + height: dp(50) + on_press: root.manager.current = "game" + +: + name: "leaderboard" + BoxLayout: + orientation: 'vertical' + padding: dp(20) + spacing: dp(20) + canvas.before: + Color: + rgba: 0.1, 0.1, 0.1, 1 + Rectangle: + pos: self.pos + size: self.size + Label: + text: "Leaderboard" + font_size: Window.width / 20 + color: 1, 1, 1, 1 + Label: + id: leaderboard_label + text: "" + font_size: Window.width / 35 + color: 1, 1, 1, 1 + Button: + text: "Back" + size_hint_y: None + height: dp(50) + on_press: root.manager.current = "game" From da30513db8e9485d36adc43b391911c1ceb22e24 Mon Sep 17 00:00:00 2001 From: = <=> Date: Sun, 3 Aug 2025 23:18:55 +0530 Subject: [PATCH 5/8] added a simple snake game --- snake game/snake_game.py | 160 ++++++++++++++++++++++++++++++++ snake game/snake_game_save.json | 1 + 2 files changed, 161 insertions(+) create mode 100644 snake game/snake_game.py create mode 100644 snake game/snake_game_save.json diff --git a/snake game/snake_game.py b/snake game/snake_game.py new file mode 100644 index 0000000..d8934e0 --- /dev/null +++ b/snake game/snake_game.py @@ -0,0 +1,160 @@ +import tkinter as tk +import random +import json +import os + +CELL_SIZE = 20 +GRID_WIDTH = 25 +GRID_HEIGHT = 25 +UPDATE_DELAY = 100 # ms + +SAVE_FILE = 'snake_game_save.json' + +class SnakeGame: + def __init__(self, root): + self.root = root + self.root.title("🐍 Snake Game Deluxe 🐍") + self.root.resizable(False, False) + + self.canvas = tk.Canvas(root, width=CELL_SIZE * GRID_WIDTH, + height=CELL_SIZE * GRID_HEIGHT, bg="#1e1e1e", bd=0, highlightthickness=0) + self.canvas.pack() + + self.score = 0 + self.high_score = 0 + self.snake = [(5, 5)] + self.direction = (1, 0) + self.food = None + self.game_running = False + + self.load_data() + self.draw_ui() + self.reset_game() + + self.root.bind("", self.change_direction) + + def draw_ui(self): + self.top_frame = tk.Frame(self.root, bg="#282c34") + self.top_frame.pack(fill="x") + + self.score_label = tk.Label(self.top_frame, text="Score: 0", fg="white", bg="#282c34", + font=("Consolas", 14, "bold")) + self.score_label.pack(side="left", padx=10) + + self.high_score_label = tk.Label(self.top_frame, text=f"High Score: {self.high_score}", fg="white", + bg="#282c34", font=("Consolas", 14, "bold")) + self.high_score_label.pack(side="right", padx=10) + + self.reset_button = tk.Button(self.top_frame, text="🔁 Restart", command=self.reset_game, + bg="#61afef", fg="white", font=("Consolas", 12, "bold"), bd=0, relief="flat") + self.reset_button.pack(side="left", padx=10) + + def load_data(self): + if os.path.exists(SAVE_FILE): + try: + with open(SAVE_FILE, 'r') as f: + data = json.load(f) + self.high_score = data.get("high_score", 0) + except: + self.high_score = 0 + + def save_data(self): + with open(SAVE_FILE, 'w') as f: + json.dump({"high_score": self.high_score}, f) + + def reset_game(self): + self.snake = [(5, 5)] + self.direction = (1, 0) + self.score = 0 + self.game_running = True + self.spawn_food() + self.update_ui() + self.game_loop() + + def spawn_food(self): + while True: + x = random.randint(0, GRID_WIDTH - 1) + y = random.randint(0, GRID_HEIGHT - 1) + if (x, y) not in self.snake: + self.food = (x, y) + break + + def change_direction(self, event): + key = event.keysym + new_dir = { + 'Up': (0, -1), + 'Down': (0, 1), + 'Left': (-1, 0), + 'Right': (1, 0) + }.get(key) + + if new_dir: + opposite = (-self.direction[0], -self.direction[1]) + if new_dir != opposite: # Prevent reversing + self.direction = new_dir + + def game_loop(self): + if not self.game_running: + return + + head_x, head_y = self.snake[-1] + dx, dy = self.direction + new_head = (head_x + dx, head_y + dy) + + if (new_head in self.snake or + new_head[0] < 0 or new_head[0] >= GRID_WIDTH or + new_head[1] < 0 or new_head[1] >= GRID_HEIGHT): + self.end_game() + return + + self.snake.append(new_head) + + if new_head == self.food: + self.score += 1 + self.spawn_food() + else: + self.snake.pop(0) + + self.update_ui() + self.root.after(UPDATE_DELAY, self.game_loop) + + def update_ui(self): + self.canvas.delete("all") + + # Draw snake + for segment in self.snake: + x1 = segment[0] * CELL_SIZE + y1 = segment[1] * CELL_SIZE + x2 = x1 + CELL_SIZE + y2 = y1 + CELL_SIZE + self.canvas.create_rectangle(x1, y1, x2, y2, fill="#98c379", outline="#1e1e1e") + + # Draw head with highlight + hx, hy = self.snake[-1] + self.canvas.create_rectangle(hx * CELL_SIZE, hy * CELL_SIZE, + hx * CELL_SIZE + CELL_SIZE, hy * CELL_SIZE + CELL_SIZE, + fill="#e06c75", outline="#1e1e1e") + + # Draw food + fx, fy = self.food + self.canvas.create_oval(fx * CELL_SIZE, fy * CELL_SIZE, + fx * CELL_SIZE + CELL_SIZE, fy * CELL_SIZE + CELL_SIZE, + fill="#d19a66", outline="#1e1e1e") + + self.score_label.config(text=f"Score: {self.score}") + + def end_game(self): + self.game_running = False + if self.score > self.high_score: + self.high_score = self.score + self.save_data() + self.high_score_label.config(text=f"High Score: {self.high_score}") + self.canvas.create_text(CELL_SIZE * GRID_WIDTH // 2, + CELL_SIZE * GRID_HEIGHT // 2, + text="Game Over", fill="white", + font=("Consolas", 24, "bold")) + +if __name__ == "__main__": + root = tk.Tk() + app = SnakeGame(root) + root.mainloop() diff --git a/snake game/snake_game_save.json b/snake game/snake_game_save.json new file mode 100644 index 0000000..1480e41 --- /dev/null +++ b/snake game/snake_game_save.json @@ -0,0 +1 @@ +{"high_score": 3} \ No newline at end of file From bb4b306cd0e2ecd700c8f2c210e34d9b65786788 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Gaur Date: Wed, 6 Aug 2025 22:56:01 +0530 Subject: [PATCH 6/8] added mobile version --- snake game/snake_game_mobile.py | 176 ++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 snake game/snake_game_mobile.py diff --git a/snake game/snake_game_mobile.py b/snake game/snake_game_mobile.py new file mode 100644 index 0000000..dac1810 --- /dev/null +++ b/snake game/snake_game_mobile.py @@ -0,0 +1,176 @@ +from kivy.app import App +from kivy.uix.widget import Widget +from kivy.uix.button import Button +from kivy.graphics import Color, Rectangle, Ellipse +from kivy.clock import Clock +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.label import Label +from kivy.core.window import Window +import random +import json +import os + +CELL_SIZE = 20 +GRID_WIDTH = 25 +GRID_HEIGHT = 25 +UPDATE_DELAY = 0.1 +SAVE_FILE = "snake_game_save.json" + + +class SnakeGame(Widget): + def __init__(self, score_label, high_score_label, **kwargs): + super().__init__(**kwargs) + self.score_label = score_label + self.high_score_label = high_score_label + + self.snake = [(5, 5)] + self.direction = (1, 0) + self.food = None + self.score = 0 + self.high_score = 0 + self.game_running = True + + self.load_data() + self.spawn_food() + self.update_canvas() + + Clock.schedule_interval(self.update, UPDATE_DELAY) + Window.bind(on_key_down=self.on_key_down) + + def load_data(self): + if os.path.exists(SAVE_FILE): + try: + with open(SAVE_FILE, 'r') as f: + data = json.load(f) + self.high_score = data.get("high_score", 0) + except: + self.high_score = 0 + + def save_data(self): + with open(SAVE_FILE, 'w') as f: + json.dump({"high_score": self.high_score}, f) + + def reset_game(self): + self.snake = [(5, 5)] + self.direction = (1, 0) + self.score = 0 + self.game_running = True + self.spawn_food() + self.update_canvas() + self.score_label.text = f"Score: {self.score}" + self.high_score_label.text = f"High Score: {self.high_score}" + + def spawn_food(self): + while True: + x = random.randint(0, GRID_WIDTH - 1) + y = random.randint(0, GRID_HEIGHT - 1) + if (x, y) not in self.snake: + self.food = (x, y) + break + + def on_key_down(self, window, key, *args): + key_map = { + 273: (0, 1), # Up + 274: (0, -1), # Down + 276: (-1, 0), # Left + 275: (1, 0) # Right + } + if key in key_map: + new_dir = key_map[key] + opposite = (-self.direction[0], -self.direction[1]) + if new_dir != opposite: + self.direction = new_dir + + def update(self, dt): + if not self.game_running: + return + + head_x, head_y = self.snake[-1] + dx, dy = self.direction + new_head = (head_x + dx, head_y + dy) + + if (new_head in self.snake or + new_head[0] < 0 or new_head[0] >= GRID_WIDTH or + new_head[1] < 0 or new_head[1] >= GRID_HEIGHT): + self.end_game() + return + + self.snake.append(new_head) + + if new_head == self.food: + self.score += 1 + self.spawn_food() + else: + self.snake.pop(0) + + self.update_canvas() + self.score_label.text = f"Score: {self.score}" + + def update_canvas(self): + self.canvas.clear() + with self.canvas: + # Snake body + for segment in self.snake[:-1]: + Color(0.6, 0.8, 0.5) + Rectangle(pos=(segment[0] * CELL_SIZE, segment[1] * CELL_SIZE), + size=(CELL_SIZE, CELL_SIZE)) + + # Snake head + head = self.snake[-1] + Color(1, 0.4, 0.4) + Rectangle(pos=(head[0] * CELL_SIZE, head[1] * CELL_SIZE), + size=(CELL_SIZE, CELL_SIZE)) + + # Food + Color(0.8, 0.6, 0.3) + Ellipse(pos=(self.food[0] * CELL_SIZE, self.food[1] * CELL_SIZE), + size=(CELL_SIZE, CELL_SIZE)) + + def end_game(self): + self.game_running = False + if self.score > self.high_score: + self.high_score = self.score + self.save_data() + + self.high_score_label.text = f"High Score: {self.high_score}" + self.score_label.text = f"Game Over! Final Score: {self.score}" + self.canvas.clear() + with self.canvas: + Color(1, 1, 1) + Rectangle(pos=(0, (GRID_HEIGHT * CELL_SIZE) // 2 - 20), + size=(GRID_WIDTH * CELL_SIZE, 40)) + + +class SnakeApp(App): + def build(self): + Window.size = (GRID_WIDTH * CELL_SIZE, GRID_HEIGHT * CELL_SIZE + 40) + main_layout = BoxLayout(orientation="vertical", padding=0, spacing=0) + + # Score bar + top_bar = BoxLayout(size_hint_y=None, height=40, padding=10, spacing=10) + self.score_label = Label(text="Score: 0", color=(1, 1, 1, 1), + bold=True, font_size=16) + self.high_score_label = Label(text="High Score: 0", color=(1, 1, 1, 1), + bold=True, font_size=16) + + restart_btn = Button(text="🔁 Restart", background_color=(0.2, 0.6, 1, 1), + color=(1, 1, 1, 1), bold=True) + restart_btn.bind(on_press=self.restart_game) + + top_bar.add_widget(self.score_label) + top_bar.add_widget(self.high_score_label) + top_bar.add_widget(restart_btn) + + # Game + self.game = SnakeGame(score_label=self.score_label, high_score_label=self.high_score_label) + + main_layout.add_widget(top_bar) + main_layout.add_widget(self.game) + return main_layout + + def restart_game(self, instance): + self.game.reset_game() + + +if __name__ == '__main__': + SnakeApp().run() From 2d138fec25f927dd0b60056966d9c3340920c39d Mon Sep 17 00:00:00 2001 From: Ayush Kumar Gaur Date: Fri, 8 Aug 2025 08:16:59 +0530 Subject: [PATCH 7/8] added flappy bird --- ...obile-stone-paper-scissors.cpython-313.pyc | Bin 0 -> 9823 bytes flappy_bird/flappy_bird.py | 381 ++++++++++++++++++ flappy_bird/flappy_highscore.json | 1 + rps_kivy_save.json | 1 + 4 files changed, 383 insertions(+) create mode 100644 __pycache__/mobile-stone-paper-scissors.cpython-313.pyc create mode 100644 flappy_bird/flappy_bird.py create mode 100644 flappy_bird/flappy_highscore.json create mode 100644 rps_kivy_save.json diff --git a/__pycache__/mobile-stone-paper-scissors.cpython-313.pyc b/__pycache__/mobile-stone-paper-scissors.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22d0ede72f9afae79806f4b70a650230f28c032d GIT binary patch literal 9823 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 literal 0 HcmV?d00001 diff --git a/flappy_bird/flappy_bird.py b/flappy_bird/flappy_bird.py new file mode 100644 index 0000000..350d065 --- /dev/null +++ b/flappy_bird/flappy_bird.py @@ -0,0 +1,381 @@ +""" +Flappy Bird - Polished Tkinter Version +Controls: + - Space / Up arrow / Left mouse click -> flap / start / restart + - P -> pause / resume + - R -> restart after game over +""" +import tkinter as tk +import random +import time +import json +import os + +# ----------------- Config ----------------- +WIDTH = 420 +HEIGHT = 640 +FPS_MS = 16 # ~60 FPS +BIRD_SIZE = 34 +BIRD_X = 110 # fixed horizontal position for bird +GRAVITY = 900.0 # pixels / s^2 +FLAP_V = -340.0 # instant velocity on flap (px / s) +PIPE_WIDTH = 72 +PIPE_GAP = 170 +PIPE_SPEED = 180.0 # pixels / second +SPAWN_INTERVAL = 1.6 # seconds between pipes +SAVE_FILE = "flappy_highscore.json" +BG_COLOR = "#70c5ce" +GROUND_HEIGHT = 80 +TEXT_FONT = ("Arial", 18, "bold") +SCORE_FONT = ("Arial", 28, "bold") + +# ----------------- Helpers ----------------- +def load_highscore(): + if os.path.exists(SAVE_FILE): + try: + with open(SAVE_FILE, "r") as f: + data = json.load(f) + return int(data.get("high_score", 0)) + except Exception: + return 0 + return 0 + +def save_highscore(score): + try: + with open(SAVE_FILE, "w") as f: + json.dump({"high_score": int(score)}, f) + except Exception: + pass + +def rects_intersect(a, b): + # a and b are (x1,y1,x2,y2) + return not (a[2] <= b[0] or a[0] >= b[2] or a[3] <= b[1] or a[1] >= b[3]) + +# ----------------- Game Class ----------------- +class FlappyBird: + def __init__(self, root): + self.root = root + self.root.title("Flappy Bird — Polished Tkinter") + self.canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg=BG_COLOR, highlightthickness=0) + self.canvas.pack() + + # state + self.state = "menu" # menu | playing | paused | gameover + self.last_time = None + self._job = None + + # game objects + self.bird_id = None + self.bird_v = 0.0 + self.pipes = [] # list of dicts {x, gap_y, top_id, bottom_id, scored} + self.spawn_timer = 0.0 + self.score = 0 + self.high_score = load_highscore() + + # ui + self.score_text_id = None + self.overlay_ids = [] + self.pause_text_id = None + + # input bindings + root.bind("", self.on_flap) + root.bind("", self.on_flap) + root.bind("", self.on_flap) # mouse left click + root.bind("p", self.toggle_pause) + root.bind("P", self.toggle_pause) + root.bind("r", self.force_restart) + root.protocol("WM_DELETE_WINDOW", self._on_close) + + # draw static ground + self.draw_background() + self.show_menu() + + # ---------- drawing ---------- + def draw_background(self): + self.canvas.delete("background") + # sky already BG_COLOR; draw ground strip + self.canvas.create_rectangle(0, HEIGHT - GROUND_HEIGHT, WIDTH, HEIGHT, fill="#de9b5c", width=0, tags="background") + # ground detail + self.canvas.create_rectangle(0, HEIGHT - GROUND_HEIGHT - 6, WIDTH, HEIGHT - GROUND_HEIGHT, fill="#c17e45", width=0, tags="background") + + def create_bird(self): + cy = HEIGHT//2 + x1 = BIRD_X - BIRD_SIZE//2 + y1 = cy - BIRD_SIZE//2 + x2 = BIRD_X + BIRD_SIZE//2 + y2 = cy + BIRD_SIZE//2 + self.bird_id = self.canvas.create_oval(x1, y1, x2, y2, fill="#ffeb3b", outline="#d8b41b", width=2) + # simple eye + self.canvas.create_oval(BIRD_X+6, cy-6, BIRD_X+11, cy-1, fill="#222", tags=("bird_eye",)) + # wing (animated by moving it slightly) + self.wing_id = self.canvas.create_polygon(BIRD_X-4, cy, BIRD_X+2, cy-4, BIRD_X+6, cy, fill="#f0c419", outline="") + + def clear_game_objects(self): + if self.bird_id: + self.canvas.delete(self.bird_id) + self.canvas.delete("pipe") + self.canvas.delete("score") + self.canvas.delete("overlay") + self.canvas.delete("bird_eye") + try: + del self.wing_id + except Exception: + pass + self.pipes.clear() + + # ---------- state screens ---------- + def show_menu(self): + self.canvas.delete("all") + self.draw_background() + self.overlay_ids = [] + title = self.canvas.create_text(WIDTH//2, HEIGHT//2 - 70, text="Flappy Bird", font=("Helvetica", 40, "bold"), fill="white", tags="overlay") + hint = self.canvas.create_text(WIDTH//2, HEIGHT//2 - 20, text="Press SPACE / Click to Start", font=TEXT_FONT, fill="#ffc107", tags="overlay") + sub = self.canvas.create_text(WIDTH//2, HEIGHT//2 + 20, text="Space/Up/Click = Flap P = Pause R = Restart", font=("Helvetica", 12), fill="white", tags="overlay") + hs = self.canvas.create_text(WIDTH//2, HEIGHT//2 + 70, text=f"High Score: {self.high_score}", font=("Helvetica", 16), fill="white", tags="overlay") + self.overlay_ids = [title, hint, sub, hs] + self.state = "menu" + # set up a light demo bird to bob up/down + self.demo_bob = 0.0 + self._demo_bob_job() + + def _demo_bob_job(self): + # small bob animation while on menu + if self.state != "menu": + return + self.canvas.delete("demo_bird") + bob_y = HEIGHT//2 + int(8 * (1 + random.random()) * (0.5 - 0.5)) + # draw a simple bird sample + bx1 = BIRD_X - 20 + by1 = HEIGHT//2 - 20 + bx2 = BIRD_X + 20 + by2 = HEIGHT//2 + 20 + self.canvas.create_oval(bx1, by1, bx2, by2, fill="#ffeb3b", outline="#d8b41b", width=2, tags="demo_bird") + # loop slow + self.root.after(700, self._demo_bob_job) + + def show_gameover(self): + self.state = "gameover" + # overlay + self.overlay_ids = [] + panel = self.canvas.create_rectangle(WIDTH//2 - 180, HEIGHT//2 - 90, WIDTH//2 + 180, HEIGHT//2 + 90, fill="#000000cc", outline="", tags="overlay") + t1 = self.canvas.create_text(WIDTH//2, HEIGHT//2 - 30, text="GAME OVER", font=("Helvetica", 32, "bold"), fill="#ff5252", tags="overlay") + t2 = self.canvas.create_text(WIDTH//2, HEIGHT//2 + 10, text=f"Score: {self.score} High: {self.high_score}", font=TEXT_FONT, fill="white", tags="overlay") + t3 = self.canvas.create_text(WIDTH//2, HEIGHT//2 + 50, text="Press SPACE / Click / R to Replay", font=("Helvetica", 14), fill="#ffc107", tags="overlay") + self.overlay_ids = [panel, t1, t2, t3] + + # ---------- input handlers ---------- + def on_flap(self, event=None): + # universal handler: acts depending on state + if self.state == "menu": + # start playing + self.start_game() + return + if self.state == "playing": + # flap + self.bird_v = FLAP_V + # small wing animation + try: + self.canvas.coords(self.wing_id, BIRD_X-4, (self.canvas.coords(self.bird_id)[1]+self.canvas.coords(self.bird_id)[3])/2, + BIRD_X+2, self.canvas.coords(self.bird_id)[1]+6, BIRD_X+6, (self.canvas.coords(self.bird_id)[1]+self.canvas.coords(self.bird_id)[3])/2) + except Exception: + pass + return + if self.state == "gameover": + # restart on flap/click + self.restart() + return + if self.state == "paused": + # unpause + flap + self.toggle_pause() + self.bird_v = FLAP_V + return + + def toggle_pause(self, event=None): + if self.state == "playing": + self.state = "paused" + if self.pause_text_id is None: + self.pause_text_id = self.canvas.create_text(WIDTH//2, HEIGHT//2, text="PAUSED", font=("Helvetica", 36, "bold"), fill="white", tags="overlay") + elif self.state == "paused": + self.canvas.delete(self.pause_text_id) + self.pause_text_id = None + self.last_time = time.time() + self.state = "playing" + self._schedule_next_frame() + + def force_restart(self, event=None): + # user pressed R + if self.state in ("playing", "paused", "gameover"): + self.restart() + + # ---------- game lifecycle ---------- + def start_game(self): + # clear overlays + demo + self.canvas.delete("demo_bird") + for item in self.overlay_ids: + try: self.canvas.delete(item) + except: pass + self.overlay_ids.clear() + + # reset + self.clear_game_objects() + self.create_bird() + self.score = 0 + self.pipes = [] + self.spawn_timer = 0.4 # spawn first pipe quickly + self.last_time = time.time() + self.bird_v = 0.0 + self.state = "playing" + + # score label + if self.score_text_id: + self.canvas.delete(self.score_text_id) + self.score_text_id = self.canvas.create_text(WIDTH - 16, 12, anchor="ne", text=f"{self.score}", font=SCORE_FONT, fill="white", tags="score") + + # start main loop + self._schedule_next_frame() + + def restart(self): + # cleanup any scheduled callback to avoid dupes + if self._job: + try: + self.root.after_cancel(self._job) + except Exception: + pass + self._job = None + # save high score + if self.score > self.high_score: + self.high_score = self.score + save_highscore(self.high_score) + # tiny flash or sound could go here + self.clear_game_objects() + self.start_game() + + def end_game(self): + self.state = "gameover" + # save high score + if self.score > self.high_score: + self.high_score = self.score + save_highscore(self.high_score) + self.show_gameover() + # stop loop (no scheduling next) + if self._job: + try: + self.root.after_cancel(self._job) + except Exception: + pass + self._job = None + + def _on_close(self): + # cancel scheduled job before closing + if self._job: + try: + self.root.after_cancel(self._job) + except Exception: + pass + self.root.destroy() + + # ---------- pipes ---------- + def spawn_pipe(self): + gap_y = random.randint(110, HEIGHT - GROUND_HEIGHT - 110 - PIPE_GAP) + x = WIDTH + 4 + top_id = self.canvas.create_rectangle(x, 0, x + PIPE_WIDTH, gap_y, fill="#2e8b57", width=0, tags="pipe") + bottom_id = self.canvas.create_rectangle(x, gap_y + PIPE_GAP, x + PIPE_WIDTH, HEIGHT - GROUND_HEIGHT, fill="#2e8b57", width=0, tags="pipe") + pipe = {"x": float(x), "gap_y": gap_y, "top": top_id, "bottom": bottom_id, "scored": False} + self.pipes.append(pipe) + + # ---------- main loop ---------- + def _schedule_next_frame(self): + # schedule next frame if playing + if self.state == "playing": + self._job = self.root.after(FPS_MS, self._frame) + + def _frame(self): + now = time.time() + dt = now - (self.last_time or now) + # clamp dt to avoid huge jumps + if dt > 0.05: + dt = 0.05 + self.last_time = now + + # update physics + self.bird_v += GRAVITY * dt + # convert bird velocity to movement in pixels this frame + dy = self.bird_v * dt + self.canvas.move(self.bird_id, 0, dy) + # move wing to follow + try: + bx1, by1, bx2, by2 = self.canvas.coords(self.bird_id) + mid_y = (by1 + by2)/2 + # basic wing follow + self.canvas.coords(self.wing_id, BIRD_X-4, mid_y, BIRD_X+2, mid_y-8, BIRD_X+6, mid_y) + self.canvas.coords("bird_eye", BIRD_X+6, mid_y-6, BIRD_X+11, mid_y-1) + except Exception: + pass + + # bird bounds check top/bottom (collide with ground) + bx1, by1, bx2, by2 = self.canvas.coords(self.bird_id) + if by1 <= 4: + # hit ceiling -> clamp and bounce a little + self.canvas.coords(self.bird_id, bx1, 4, bx2, 4 + (by2-by1)) + self.bird_v = 0.0 + by1 = 4 + if by2 >= HEIGHT - GROUND_HEIGHT: + # hit ground -> game over + self.end_game() + return + + # update pipes + remove_list = [] + for p in list(self.pipes): + p["x"] -= PIPE_SPEED * dt + x = p["x"] + # update rectangle coords + self.canvas.coords(p["top"], x, 0, x + PIPE_WIDTH, p["gap_y"]) + self.canvas.coords(p["bottom"], x, p["gap_y"] + PIPE_GAP, x + PIPE_WIDTH, HEIGHT - GROUND_HEIGHT) + + # scoring: when pipe right edge crosses bird_x and not yet scored + if (not p["scored"]) and (x + PIPE_WIDTH < BIRD_X): + p["scored"] = True + self.score += 1 + self.canvas.itemconfigure(self.score_text_id, text=str(self.score)) + + # remove off-screen pipes + if x + PIPE_WIDTH < -10: + remove_list.append(p) + + for p in remove_list: + try: + self.canvas.delete(p["top"]) + self.canvas.delete(p["bottom"]) + except Exception: + pass + if p in self.pipes: + self.pipes.remove(p) + + # spawn logic + self.spawn_timer -= dt + if self.spawn_timer <= 0.0: + self.spawn_pipe() + self.spawn_timer = SPAWN_INTERVAL + + # collision detection with pipes + bird_bbox = self.canvas.coords(self.bird_id) + for p in self.pipes: + top_bbox = self.canvas.coords(p["top"]) + bot_bbox = self.canvas.coords(p["bottom"]) + if rects_intersect(bird_bbox, top_bbox) or rects_intersect(bird_bbox, bot_bbox): + self.end_game() + return + + # schedule next + self._schedule_next_frame() + + # ---------- run ---------- + def run(self): + self.root.mainloop() + +# ----------------- run the game ----------------- +if __name__ == "__main__": + root = tk.Tk() + game = FlappyBird(root) + game.run() diff --git a/flappy_bird/flappy_highscore.json b/flappy_bird/flappy_highscore.json new file mode 100644 index 0000000..8338a01 --- /dev/null +++ b/flappy_bird/flappy_highscore.json @@ -0,0 +1 @@ +{"high_score": 17} \ No newline at end of file diff --git a/rps_kivy_save.json b/rps_kivy_save.json new file mode 100644 index 0000000..4fc9fe9 --- /dev/null +++ b/rps_kivy_save.json @@ -0,0 +1 @@ +{"wins": 1, "losses": 1, "ties": 0, "streak": 1, "history": [{"time": "2025-07-22 21:56", "player": "P", "computer": "S", "result": "loss"}, {"time": "2025-07-22 21:57", "player": "R", "computer": "S", "result": "win"}]} \ No newline at end of file From d585a4ce18a6ad523b80badd20c0e96c3cfe0cdc Mon Sep 17 00:00:00 2001 From: Ayush Kumar Gaur Date: Sat, 9 Aug 2025 10:30:26 +0530 Subject: [PATCH 8/8] added flappy mobile version --- flappy_bird/flappy_bird_mobile.py | 234 ++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 flappy_bird/flappy_bird_mobile.py diff --git a/flappy_bird/flappy_bird_mobile.py b/flappy_bird/flappy_bird_mobile.py new file mode 100644 index 0000000..d1bf379 --- /dev/null +++ b/flappy_bird/flappy_bird_mobile.py @@ -0,0 +1,234 @@ +# flappy_bird_kivy_fixed.py +import kivy +kivy.require("2.3.0") + +from kivy.app import App +from kivy.uix.widget import Widget +from kivy.uix.label import Label +from kivy.graphics import Color, Rectangle, Ellipse +from kivy.clock import Clock +from kivy.core.window import Window +from kivy.utils import get_color_from_hex +import random, json, os, time + +WIDTH, HEIGHT = 420, 640 +FPS = 1 / 60 +BIRD_SIZE = 34 +BIRD_X = 110 +GRAVITY = -900.0 # Negative because up is positive in Kivy +FLAP_V = 340.0 +PIPE_WIDTH = 72 +PIPE_GAP = 170 +PIPE_SPEED = 180.0 +SPAWN_INTERVAL = 1.6 +SAVE_FILE = "flappy_highscore.json" +BG_COLOR = "#70c5ce" +GROUND_HEIGHT = 80 + +def load_highscore(): + if os.path.exists(SAVE_FILE): + try: + with open(SAVE_FILE, "r") as f: + return int(json.load(f).get("high_score", 0)) + except: + return 0 + return 0 + +def save_highscore(score): + try: + with open(SAVE_FILE, "w") as f: + json.dump({"high_score": int(score)}, f) + except: + pass + +def rects_intersect(a, b): + return not (a[2] <= b[0] or a[0] >= b[2] or a[3] <= b[1] or a[1] >= b[3]) + +class FlappyGame(Widget): + def __init__(self, **kwargs): + super().__init__(**kwargs) + Window.size = (WIDTH, HEIGHT) + Window.clearcolor = get_color_from_hex(BG_COLOR) + + self.state = "menu" + self.bird_y = HEIGHT // 2 + self.bird_v = 0 + self.pipes = [] + self.spawn_timer = 0 + self.score = 0 + self.high_score = load_highscore() + self.last_time = time.time() + + self.score_label = Label(text="", font_size=28, color=(1, 1, 1, 1), + pos=(WIDTH - 60, HEIGHT - 40)) + self.add_widget(self.score_label) + self.overlay_label = Label(text="", font_size=22, color=(1, 1, 0, 1), + halign="center", valign="middle", + size=(WIDTH, HEIGHT), pos=(0, 0)) + self.add_widget(self.overlay_label) + + self.show_menu() + + Window.bind(on_key_down=self._on_key_down) + Window.bind(on_mouse_down=self._on_mouse_down) + + def show_menu(self): + self.state = "menu" + self.overlay_label.text = ( + f"[b]Flappy Bird[/b]\n\nPress SPACE / Click to Start\n" + f"P = Pause R = Restart\nHigh Score: {self.high_score}" + ) + self.overlay_label.markup = True + + def start_game(self): + self.state = "playing" + self.bird_y = HEIGHT // 2 + self.bird_v = 0 + self.pipes.clear() + self.score = 0 + self.spawn_timer = 0.4 + self.overlay_label.text = "" + self.last_time = time.time() + Clock.schedule_interval(self.update, FPS) + + def spawn_pipe(self): + gap_y = random.randint(110, HEIGHT - GROUND_HEIGHT - 110 - PIPE_GAP) + self.pipes.append({"x": WIDTH, "gap_y": gap_y, "scored": False}) + + def update(self, _): + if self.state != "playing": + return + + now = time.time() + dt = now - self.last_time + if dt > 0.05: + dt = 0.05 + self.last_time = now + + # Bird physics + self.bird_v += GRAVITY * dt + self.bird_y += self.bird_v * dt + + # Ground / ceiling + if self.bird_y <= GROUND_HEIGHT: + self.bird_y = GROUND_HEIGHT + self.end_game() + if self.bird_y + BIRD_SIZE >= HEIGHT: + self.bird_y = HEIGHT - BIRD_SIZE + self.bird_v = 0 + + # Pipes + for p in self.pipes: + p["x"] -= PIPE_SPEED * dt + self.pipes = [p for p in self.pipes if p["x"] + PIPE_WIDTH > 0] + + # Spawn + self.spawn_timer -= dt + if self.spawn_timer <= 0: + self.spawn_pipe() + self.spawn_timer = SPAWN_INTERVAL + + # Collision & scoring + bird_rect = (BIRD_X, self.bird_y, + BIRD_X + BIRD_SIZE, self.bird_y + BIRD_SIZE) + for p in self.pipes: + if not p["scored"] and p["x"] + PIPE_WIDTH < BIRD_X: + p["scored"] = True + self.score += 1 + top_rect = (p["x"], p["gap_y"] + PIPE_GAP, + p["x"] + PIPE_WIDTH, HEIGHT) + bottom_rect = (p["x"], 0, + p["x"] + PIPE_WIDTH, p["gap_y"]) + if rects_intersect(bird_rect, top_rect) or rects_intersect(bird_rect, bottom_rect): + self.end_game() + + self.draw() + + def draw(self): + self.canvas.clear() + + # Background + with self.canvas: + Color(*get_color_from_hex(BG_COLOR)) + Rectangle(pos=(0, 0), size=(WIDTH, HEIGHT)) + + # Pipes + with self.canvas: + Color(*get_color_from_hex("#2e8b57")) + for p in self.pipes: + Rectangle(pos=(p["x"], 0), size=(PIPE_WIDTH, p["gap_y"])) + Rectangle(pos=(p["x"], p["gap_y"] + PIPE_GAP), + size=(PIPE_WIDTH, HEIGHT - (p["gap_y"] + PIPE_GAP))) + + # Ground + with self.canvas: + Color(*get_color_from_hex("#de9b5c")) + Rectangle(pos=(0, 0), size=(WIDTH, GROUND_HEIGHT)) + Color(*get_color_from_hex("#c17e45")) + Rectangle(pos=(0, GROUND_HEIGHT), size=(WIDTH, 6)) + + # Bird + with self.canvas: + Color(1, 0.92, 0.23) + Ellipse(pos=(BIRD_X, self.bird_y), size=(BIRD_SIZE, BIRD_SIZE)) + + self.score_label.text = str(self.score) + + def end_game(self): + self.state = "gameover" + Clock.unschedule(self.update) + if self.score > self.high_score: + self.high_score = self.score + save_highscore(self.high_score) + self.overlay_label.text = ( + f"[b]GAME OVER[/b]\nScore: {self.score} High: {self.high_score}\n" + "Press SPACE / Click / R to Restart" + ) + self.overlay_label.markup = True + + def flap(self): + if self.state == "menu": + self.start_game() + elif self.state == "playing": + self.bird_v = FLAP_V + elif self.state == "paused": + self.state = "playing" + self.overlay_label.text = "" + self.last_time = time.time() + Clock.schedule_interval(self.update, FPS) + elif self.state == "gameover": + self.start_game() + + def toggle_pause(self): + if self.state == "playing": + self.state = "paused" + Clock.unschedule(self.update) + self.overlay_label.text = "[b]PAUSED[/b]" + self.overlay_label.markup = True + elif self.state == "paused": + self.state = "playing" + self.overlay_label.text = "" + self.last_time = time.time() + Clock.schedule_interval(self.update, FPS) + + def restart(self): + self.start_game() + + def _on_key_down(self, window, key, *_): + if key in (32, 273): # Space / Up + self.flap() + elif key in (112, 80): # P + self.toggle_pause() + elif key in (114, 82): # R + self.restart() + + def _on_mouse_down(self, window, x, y, button, *_): + if button == "left": + self.flap() + +class FlappyApp(App): + def build(self): + return FlappyGame() + +if __name__ == "__main__": + FlappyApp().run()