Change the layout to fit the code on pyscript, now also with icons.
This commit is contained in:
parent
54cd9d838b
commit
25bc363a24
11 changed files with 170 additions and 170 deletions
11
README.md
11
README.md
|
@ -1,9 +1,14 @@
|
|||
# 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.
|
||||
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.
|
||||
|
||||
At the moment, there are two versions: a Python version for local usage (terminal), `local.py`, and a PyScript version, `main.py`.
|
||||
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).
|
||||
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).
|
||||
|
||||
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
BIN
images/card-back.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
images/paper.png
Normal file
BIN
images/paper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
images/rock-paper-scissors.png
Normal file
BIN
images/rock-paper-scissors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
images/rock.png
Normal file
BIN
images/rock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
images/scissors.png
Normal file
BIN
images/scissors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
124
index.html
Normal file
124
index.html
Normal 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>
|
|
@ -6,24 +6,10 @@ class RPSGame:
|
|||
self.user_score = 0
|
||||
self.ai_score = 0
|
||||
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.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):
|
||||
lst.extend(["Rock"] * n)
|
||||
return lst
|
||||
|
@ -36,6 +22,35 @@ class RPSGame:
|
|||
lst.extend(["Scissors"] * n)
|
||||
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):
|
||||
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()
|
||||
print("New cards")
|
||||
print(f"AI cards: {self.ai_hand}")
|
||||
print(f"{len(self.deck)} Cards left.")
|
||||
|
||||
def play_card(self, event):
|
||||
index = int(event.target.getAttribute("index"))
|
||||
#print(f"Button {index} clicked!") # Debugging
|
||||
if index >= len(self.user_hand):
|
||||
return
|
||||
|
||||
|
@ -80,16 +95,14 @@ class RPSGame:
|
|||
pass
|
||||
else:
|
||||
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.disable_buttons()
|
||||
#self.reset_game()
|
||||
return
|
||||
else:
|
||||
round_result = "You won great :D"
|
||||
self.update_ui(round_result)
|
||||
self.disable_buttons()
|
||||
#self.reset_game()
|
||||
return
|
||||
|
||||
self.update_ui(round_result)
|
||||
|
@ -103,16 +116,18 @@ class RPSGame:
|
|||
for i in range(3):
|
||||
btn = document.querySelector(f"#card-{i}")
|
||||
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
|
||||
else:
|
||||
btn.innerText = "?"
|
||||
btn.style.backgroundImage = "url('images/card-back.png')" # Unknown card
|
||||
btn.disabled = True
|
||||
|
||||
def disable_buttons(self):
|
||||
print("disable button function")
|
||||
for i in range(3):
|
||||
btn = document.querySelector(f"#card-{i}")
|
||||
btn.innerText = "?"
|
||||
btn.style.backgroundImage = "url('images/card-back.png')"
|
||||
btn.disabled = True
|
||||
|
||||
def reset_game(self, event=None):
|
||||
|
@ -120,13 +135,11 @@ class RPSGame:
|
|||
self.user_score = 0
|
||||
self.ai_score = 0
|
||||
self.deck = self.build_deck()
|
||||
self.user_hand, self.ai_hand = self.give_cards()
|
||||
self.refresh_hand()
|
||||
self.deck_overview()
|
||||
self.update_ui("Game reset! Pick a card to start.")
|
||||
|
||||
|
||||
def deck_overview(self):
|
||||
#print(f"{len(self.deck)} Cards left")
|
||||
print(f"{self.deck.count('Rock')} Rock cards")
|
||||
print(f"{self.deck.count('Paper')} Paper cards")
|
||||
print(f"{self.deck.count('Scissors')} Scissors cards")
|
|
@ -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>
|
98
src/local.py
98
src/local.py
|
@ -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()
|
Loading…
Add table
Add a link
Reference in a new issue