Created
June 26, 2023 19:37
-
-
Save Patryk27/df2294ecdb63856f881adcd027ab641e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use core::fmt::{self, Write}; | |
use rand::{seq::SliceRandom, Rng}; | |
use yew::prelude::*; | |
#[derive(Debug)] | |
struct App { | |
players: [Player; 4], | |
cards: Vec<Card>, | |
turn: usize, | |
revealed: bool, | |
} | |
impl Component for App { | |
type Message = ModelMessage; | |
type Properties = (); | |
fn create(_: &Context<Self>) -> Self { | |
let mut cards = Card::all(); | |
cards.shuffle(&mut rand::thread_rng()); | |
let mut players = [ | |
Player::default(), | |
Player::default(), | |
Player::default(), | |
Player::default(), | |
]; | |
for (card_idx, card) in cards.into_iter().enumerate() { | |
players[card_idx % 4].cards.push(card); | |
} | |
Self { | |
players, | |
cards: Default::default(), | |
turn: 1, | |
revealed: false, | |
} | |
} | |
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool { | |
match msg { | |
ModelMessage::NextCard => { | |
let player = &mut self.players[self.turn]; | |
let card_idx = rand::thread_rng().gen_range(0..player.cards.len()); | |
self.cards.push(player.cards.remove(card_idx)); | |
self.turn = (self.turn + 1) % 4; | |
} | |
ModelMessage::RevealCards => { | |
self.revealed = true; | |
} | |
ModelMessage::HideCards => { | |
self.revealed = false; | |
} | |
ModelMessage::Restart => { | |
*self = <Self as Component>::create(ctx); | |
} | |
} | |
true | |
} | |
fn view(&self, ctx: &Context<Self>) -> Html { | |
let done = self.players.iter().all(|player| player.cards.is_empty()); | |
let mut board = String::new(); | |
for n in 1..4 { | |
_ = writeln!(board, "Player {}:", n); | |
_ = writeln!(board, "{}", self.players[n].cards(self.revealed)); | |
_ = writeln!(board); | |
} | |
_ = writeln!(board, "You:"); | |
_ = writeln!(board, "{}", self.players[0].cards(true)); | |
_ = writeln!(board); | |
_ = writeln!(board, "Latest:"); | |
if let Some(card) = self.cards.last() { | |
let player = (self.turn + 3) % 4; | |
let player = if player == 0 { | |
"you".to_owned() | |
} else { | |
format!("player {}", player) | |
}; | |
_ = writeln!(board, "{} ({})", card, player); | |
} else { | |
_ = writeln!(board, "-"); | |
} | |
if self.revealed { | |
_ = writeln!(board); | |
_ = writeln!(board, "Cards so far:"); | |
for card in &self.cards { | |
_ = write!(board, "{} ", card); | |
} | |
_ = writeln!(board); | |
} | |
html! { | |
<div class="container"> | |
<pre class="board"> | |
{ board } | |
</pre> | |
<div class="actions"> | |
if done { | |
<button | |
onclick={ctx.link().callback(|_| ModelMessage::Restart)}> | |
{ "Restart" } | |
</button> | |
} else { | |
<button | |
onclick={ctx.link().callback(|_| ModelMessage::NextCard)}> | |
{ "Next Card" } | |
</button> | |
if self.revealed { | |
<button | |
onclick={ctx.link().callback(|_| ModelMessage::HideCards)}> | |
{ "Hide Cards" } | |
</button> | |
} else { | |
<button | |
onclick={ctx.link().callback(|_| ModelMessage::RevealCards)}> | |
{ "Reveal Cards" } | |
</button> | |
} | |
} | |
</div> | |
</div> | |
} | |
} | |
} | |
enum ModelMessage { | |
NextCard, | |
RevealCards, | |
HideCards, | |
Restart, | |
} | |
#[derive(Clone, Debug, Default)] | |
struct Player { | |
cards: Vec<Card>, | |
} | |
impl Player { | |
fn cards(&self, revealed: bool) -> String { | |
if revealed { | |
self.cards | |
.iter() | |
.map(|card| card.to_string()) | |
.collect::<Vec<_>>() | |
.join(" ") | |
} else { | |
"▯ ".repeat(self.cards.len()).trim().to_owned() | |
} | |
} | |
} | |
#[derive(Copy, Clone, Debug)] | |
struct Card { | |
rank: &'static str, | |
color: &'static str, | |
} | |
impl Card { | |
fn all() -> Vec<Self> { | |
let mut cards = Vec::new(); | |
for rank in Self::ranks() { | |
for color in Self::colors() { | |
cards.push(Card { rank, color }); | |
} | |
} | |
cards | |
} | |
fn ranks() -> [&'static str; 13] { | |
[ | |
"A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3", "2", | |
] | |
} | |
fn colors() -> [&'static str; 4] { | |
["♤", "♡", "♢", "♧"] | |
} | |
} | |
impl fmt::Display for Card { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
write!(f, "{}{}", self.rank, self.color) | |
} | |
} | |
fn main() { | |
yew::Renderer::<App>::new().render(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment