Change the layout to fit the code on pyscript, now also with icons.

This commit is contained in:
Mr Finchum 2025-03-17 13:55:46 +01:00
parent 54cd9d838b
commit 25bc363a24
11 changed files with 170 additions and 170 deletions

View file

@ -1,9 +1,14 @@
# Rock Paper Scissors Card Game # Rock Paper Scissors Card Game
Play [now](https://codebymrfinchum.pyscriptapps.com/rock-paper-scissors-card-game/latest/). Play [now](https://codebymrfinchum.pyscriptapps.com/rock-paper-scissors-card-game/) on pyscriptapps.com or see info on [Gitlab](https://gitlab.com/CodeByMrFinchum/rock-paper-scissor-card-game).
A little game to play the classic Rock Paper Scissors game with a twist. A little game to play the classic Rock Paper Scissors game with a twist.
Instead of freely selecting between Rock, Paper, and Scissors, you get a hand of three cards, potentially with only rocks. Instead of freely selecting between Rock, Paper, and Scissors, you get a hand of three cards, potentially with only rocks.
It is a semi-random 52-card deck with an unbalanced distribution of cards, meaning some cards are less likely to occur. For example, only 5 out of 52 cards are stones, so it is very unlikely the other player has a stone. Selecting scissors gives a higher chance of winning. It is a semi-random 52-card deck with an unbalanced distribution of cards, meaning some cards are less likely to occur. For example, only 5 out of 52 cards are stones, so it is very unlikely the other player has a stone. Selecting scissors gives a higher chance of winning.
At the moment, there are two versions: a Python version for local usage (terminal), `local.py`, and a PyScript version, `main.py`. It is built with PyScript and developed on [PyScript.com](). It is available on my [PyScript profile](https://pyscript.com/@codebymrfinchum) and [Gitlab repo](https://gitlab.com/CodeByMrFinchum/rock-paper-scissor-card-game).
The PyScript version can actually be accessed and played [online](https://codebymrfinchum.pyscriptapps.com/rock-paper-scissors-card-game/) on my [PyScript profile](https://pyscript.com/@codebymrfinchum).
You can also start the program local, download the repository go into the folder and do 'python3 -m http.server' and then open 'http://localhost:8000/' in your browser.
## Acknowledgment
- Help from ChatGPT
- Icons are from Flaticon, which are free to use for personal purposes. I also provided attribution in the HTML for the used images.

BIN
images/card-back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
images/paper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/rock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/scissors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

124
index.html Normal file
View file

@ -0,0 +1,124 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Rock Paper Scissors Card Game</title>
<link
rel="stylesheet"
href="https://pyscript.net/releases/2025.3.1/core.css"
/>
<script
type="module"
src="https://pyscript.net/releases/2025.3.1/core.js"
></script>
</head>
<body>
<h1>Rock Paper Scissors Card Game</h1>
<p>
Play Rock Paper Scissors with a twist! Use a 52-card deck with an
uneven distribution of cards. Both you and the AI get three cards,
and the AI selects randomly. The rules follow the classic game, but
with an added element of chance!
</p>
<p>Select a card to play against the AI! Best out of 5 game mode.</p>
<h3>Score</h3>
<p>
You: <span id="user-score">0</span> - AI:
<span id="ai-score">0</span>
</p>
<h3 id="result">Generating deck, please wait...</h3>
<style>
.card-button {
width: 120px; /* Keep button size */
height: 120px;
background-size: contain; /* Ensures full image fits */
background-repeat: no-repeat; /* Prevents tiling */
background-position: center; /* Centers image */
border: none;
cursor: pointer;
border-radius: 10px;
box-shadow: 3px 3px 8px rgba(0, 0, 0, 0.5);
}
/* Default unknown card */
#card-0,
#card-1,
#card-2 {
background-image: url("images/card-back.png");
}
/* Reset button */
#reset-game {
margin-top: 15px;
width: 100px;
height: 50px;
font-size: 16px;
border-radius: 8px;
background-color: red;
color: white;
cursor: pointer;
}
</style>
<div id="card-buttons">
<button
id="card-0"
index="0"
py-click="game.play_card"
class="card-button"
></button>
<button
id="card-1"
index="1"
py-click="game.play_card"
class="card-button"
></button>
<button
id="card-2"
index="2"
py-click="game.play_card"
class="card-button"
></button>
</div>
<button id="reset-game" py-click="game.reset_game">Reset Game</button>
<div
id="attribution"
style="margin-top: 20px; font-size: 14px; text-align: center"
>
<p><strong>Attribution for the used icons:</strong></p>
<a
href="https://www.flaticon.com/free-icons/playing-card"
title="playing card icons"
>Playing card icons by ArtBit - Flaticon</a
><br />
<a
href="https://www.flaticon.com/free-icons/rock-paper-scissors"
title="rock paper scissors icons"
>Rock paper scissors icons by iconading - Flaticon</a
><br />
<a
href="https://www.flaticon.com/free-icons/hands-and-gestures"
title="hands and gestures icons"
>Hands and gestures icons by Voysla - Flaticon</a
><br />
<a
href="https://www.flaticon.com/free-icons/fist"
title="fist icons"
>Fist icons by Cuputo - Flaticon</a
><br />
<a
href="https://www.flaticon.com/free-icons/rock-paper-scissors"
title="rock-paper-scissors icons"
>Rock-paper-scissors icons created by Freepik - Flaticon</a
><br />
</div>
<script type="py" src="./main.py"></script>
</body>
</html>

View file

@ -6,24 +6,10 @@ class RPSGame:
self.user_score = 0 self.user_score = 0
self.ai_score = 0 self.ai_score = 0
self.deck = self.build_deck() self.deck = self.build_deck()
self.user_hand, self.ai_hand = self.give_cards() self.refresh_hand()
self.rounds_to_win = (best_of // 2) + 1 self.rounds_to_win = (best_of // 2) + 1
self.update_ui() self.update_ui()
def build_deck(self):
cards = [self.rock, self.paper, self.scissors]
deck = []
random.shuffle(cards)
for i in range(2):
n = random.randint(5, 20)
deck = cards[i](deck, n)
missing_cards = 52 - len(deck)
deck = cards[2](deck, missing_cards)
random.shuffle(deck)
return deck
def rock(self, lst, n): def rock(self, lst, n):
lst.extend(["Rock"] * n) lst.extend(["Rock"] * n)
return lst return lst
@ -36,6 +22,35 @@ class RPSGame:
lst.extend(["Scissors"] * n) lst.extend(["Scissors"] * n)
return lst return lst
def generate_deck(self):
cards = [self.rock, self.paper, self.scissors]
deck = []
random.shuffle(cards) # This is done, so the card types are not added in the same order everytime, is scissors is last everytime it could result in scissors always being low or high since the last card just are all sofar minus 52¨
for i in range(2):
n = random.randint(5, 20)
deck = cards[i](deck, n)
missing_cards = 52 - len(deck)
deck = cards[2](deck, missing_cards)
random.shuffle(deck)
return deck
def check_deck(self, lst):
card_types = ["Rock", "Paper", "Scissors"]
for card_type in card_types:
if lst.count(card_type) >= 25:
return False
return True
def build_deck(self):
acceptable_deck = False
while not acceptable_deck:
deck = self.generate_deck()
acceptable_deck = self.check_deck(deck)
return deck
def give_cards(self): def give_cards(self):
return [self.deck.pop(0) for _ in range(3)], [self.deck.pop(0) for _ in range(3)] return [self.deck.pop(0) for _ in range(3)], [self.deck.pop(0) for _ in range(3)]
@ -52,10 +67,10 @@ class RPSGame:
self.user_hand, self.ai_hand = self.give_cards() self.user_hand, self.ai_hand = self.give_cards()
print("New cards") print("New cards")
print(f"AI cards: {self.ai_hand}") print(f"AI cards: {self.ai_hand}")
print(f"{len(self.deck)} Cards left.")
def play_card(self, event): def play_card(self, event):
index = int(event.target.getAttribute("index")) index = int(event.target.getAttribute("index"))
#print(f"Button {index} clicked!") # Debugging
if index >= len(self.user_hand): if index >= len(self.user_hand):
return return
@ -80,16 +95,14 @@ class RPSGame:
pass pass
else: else:
if self.user_score < self.ai_score: if self.user_score < self.ai_score:
round_result = "You lost noob D:" round_result = "You lost D: Better luck next time"
self.update_ui(round_result) self.update_ui(round_result)
self.disable_buttons() self.disable_buttons()
#self.reset_game()
return return
else: else:
round_result = "You won great :D" round_result = "You won great :D"
self.update_ui(round_result) self.update_ui(round_result)
self.disable_buttons() self.disable_buttons()
#self.reset_game()
return return
self.update_ui(round_result) self.update_ui(round_result)
@ -103,16 +116,18 @@ class RPSGame:
for i in range(3): for i in range(3):
btn = document.querySelector(f"#card-{i}") btn = document.querySelector(f"#card-{i}")
if i < len(self.user_hand): if i < len(self.user_hand):
btn.innerText = self.user_hand[i] card_name = self.user_hand[i].lower() # Convert "Rock" -> "rock"
btn.style.backgroundImage = f"url('images/{card_name}.png')"
btn.disabled = False btn.disabled = False
else: else:
btn.innerText = "?" btn.style.backgroundImage = "url('images/card-back.png')" # Unknown card
btn.disabled = True btn.disabled = True
def disable_buttons(self): def disable_buttons(self):
print("disable button function")
for i in range(3): for i in range(3):
btn = document.querySelector(f"#card-{i}") btn = document.querySelector(f"#card-{i}")
btn.innerText = "?" btn.style.backgroundImage = "url('images/card-back.png')"
btn.disabled = True btn.disabled = True
def reset_game(self, event=None): def reset_game(self, event=None):
@ -120,13 +135,11 @@ class RPSGame:
self.user_score = 0 self.user_score = 0
self.ai_score = 0 self.ai_score = 0
self.deck = self.build_deck() self.deck = self.build_deck()
self.user_hand, self.ai_hand = self.give_cards() self.refresh_hand()
self.deck_overview() self.deck_overview()
self.update_ui("Game reset! Pick a card to start.") self.update_ui("Game reset! Pick a card to start.")
def deck_overview(self): def deck_overview(self):
#print(f"{len(self.deck)} Cards left")
print(f"{self.deck.count('Rock')} Rock cards") print(f"{self.deck.count('Rock')} Rock cards")
print(f"{self.deck.count('Paper')} Paper cards") print(f"{self.deck.count('Paper')} Paper cards")
print(f"{self.deck.count('Scissors')} Scissors cards") print(f"{self.deck.count('Scissors')} Scissors cards")

View file

@ -1,44 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Rock Paper Scissors Card Game</title>
<link
rel="stylesheet"
href="https://pyscript.net/releases/2025.3.1/core.css"
/>
<script
type="module"
src="https://pyscript.net/releases/2025.3.1/core.js"
></script>
</head>
<body>
<h1>Rock Paper Scissors Card Game</h1>
<p>
Play Rock Paper Scissors with a twist! Use a 52-card deck with an
uneven distribution of cards. Both you and the AI get three cards,
and the AI selects randomly. The rules follow the classic game, but
with an added element of chance!
</p>
<p>Select a card to play against the AI! Best out of 5 game mode.</p>
<h3>Score</h3>
<p>
You: <span id="user-score">0</span> - AI:
<span id="ai-score">0</span>
</p>
<h3 id="result">Waiting for your move...</h3>
<div id="card-buttons">
<button id="card-0" index="0" py-click="game.play_card">?</button>
<button id="card-1" index="1" py-click="game.play_card">?</button>
<button id="card-2" index="2" py-click="game.play_card">?</button>
</div>
<p></p>
<button id="reset-game" py-click="game.reset_game">Reset Game</button>
<script type="py" src="./main.py"></script>
</body>
</html>

View file

@ -1,98 +0,0 @@
import random
class RPSGame:
def __init__(self, best_of = 3):
self.deck = self.build_deck()
self.user_score = 0
self.ai_score = 0
self.rounds_to_win = (best_of // 2) + 1
def build_deck(self):
cards = [self.rock, self.paper, self.scissors]
deck = []
random.shuffle(cards)
for i in range(2):
n = random.randint(5, 20)
deck = cards[i](deck, n)
missing_cards = 52 - len(deck)
deck = cards[2](deck, missing_cards)
random.shuffle(deck)
return deck
def rock(self, lst, n):
lst.extend(["Rock"] * n)
return lst
def paper(self, lst, n):
lst.extend(["Paper"] * n)
return lst
def scissors(self, lst, n):
lst.extend(["Scissors"] * n)
return lst
def give_cards(self):
return [self.deck.pop(0) for _ in range(3)], [self.deck.pop(0) for _ in range(3)]
def battle(self, user_card, ai_card):
if user_card == ai_card:
return 0
if (user_card == "Rock" and ai_card == "Scissors") or \
(user_card == "Paper" and ai_card == "Rock") or \
(user_card == "Scissors" and ai_card == "Paper"):
return 1
return -1
def play_cards(self, user_hand, ai_hand):
while user_hand and ai_hand:
print(f"\nYour cards: {user_hand}")
while True:
try:
user_choice = int(input(f"Select a card (1-{len(user_hand)}): ")) - 1
if 0 <= user_choice < len(user_hand):
break
except ValueError:
pass
print("Invalid choice. Try again.")
user_card = user_hand.pop(user_choice)
ai_card = ai_hand.pop(random.randint(0, len(ai_hand) - 1))
print(f"You played: {user_card}, AI played: {ai_card}")
result = self.battle(user_card, ai_card)
if result == 1:
print("You win this round!")
return 1
elif result == -1:
print("AI wins this round!")
return -1
else:
print("It's a tie! Play again with remaining cards.")
print("No cards left, this round is a draw.")
return 0
def play_game(self):
while self.user_score < self.rounds_to_win and self.ai_score < self.rounds_to_win and len(self.deck) >= 6:
user_hand, ai_hand = self.give_cards()
round_result = self.play_cards(user_hand, ai_hand)
if round_result == 1:
self.user_score += 1
elif round_result == -1:
self.ai_score += 1
print(f"Score - You: {self.user_score}, AI: {self.ai_score}")
if self.user_score > self.ai_score:
print("\n🎉 You won the match!")
else:
print("\n🤖 AI won the match!")
if __name__ == "__main__":
game = RPSGame(best_of = 3)
game.play_game()