Skip to content

Commit

Permalink
first pass at rendering actual cards
Browse files Browse the repository at this point in the history
  • Loading branch information
boldandbrad committed Mar 18, 2024
1 parent 0d0de53 commit e4efad6
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 41 deletions.
Binary file modified assets/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/table.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/engine/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Player {
Player {
name,
player_type,
..Default::default()
hand: vec![],
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/engine/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use rand::{
};
use std::fmt::{Display, Formatter};

pub static SEAT_VARIANTS: &[Seat] = &[Seat::Bottom, Seat::Left, Seat::Top, Seat::Right];

#[derive(Default, Clone, PartialEq, Eq, Hash)]
pub enum Seat {
#[default]
Expand Down
3 changes: 2 additions & 1 deletion src/engine/team.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ impl Team {
Team {
name,
seats,
..Default::default()
game_score: 0,
hand_score: 0,
}
}
}
64 changes: 64 additions & 0 deletions src/interface/components/cards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::engine::card::Card;
use ratatui::{
text::{Line, Text},
widgets::Paragraph,
};

pub const VERTICAL_CARD_LEFT_EDGE: [&str; 7] = ["╭", "│", "│", "│", "│", "│", "╰"];
pub const VERTICAL_CARD_RIGHT_EDGE: [&str; 7] = ["╮", "│", "│", "│", "│", "│", "╯"];

// TODO: figure out how to make these dynamic based on the screen size
pub const CARD_WIDTH: usize = 9;
pub const CARD_HEIGHT: usize = 7;

// pub fn horizontal_cards(cards: Vec<Card>, splayed: bool, show_values: bool) {}

// pub fn vertical_cards(show_values: bool) {}

pub fn card_area(card: Card) -> Vec<String> {
let card_area = vec![
"─".repeat(CARD_WIDTH),
format!(" {}{}", card.face.get_symbol(), " ".repeat(CARD_WIDTH - 2)),
" ".repeat(CARD_WIDTH),
format!(
"{}{}{}",
" ".repeat(CARD_WIDTH / 2),
card.suit.get_symbol(),
" ".repeat(CARD_WIDTH / 2),
),
" ".repeat(CARD_WIDTH),
format!("{}{} ", " ".repeat(CARD_WIDTH - 2), card.face.get_symbol()),
"─".repeat(CARD_WIDTH),
];
card_area
}

pub fn bottom_player_cards(cards: Vec<Card>) -> Paragraph<'static> {
let mut card_areas: Vec<Vec<String>> = vec![];
for card in cards {
card_areas.push(card_area(card));
}

let mut hand_area = vec!["".to_string(); CARD_HEIGHT];
for (_idx, card_area) in card_areas.iter().enumerate() {
for (idx, line) in card_area.iter().enumerate() {
hand_area[idx].push_str(VERTICAL_CARD_LEFT_EDGE[idx]);
hand_area[idx].push_str(&line);
hand_area[idx].push_str(VERTICAL_CARD_RIGHT_EDGE[idx]);
}
}

string_vec_to_paragraph(hand_area)
}

// pub fn top_player_cards(cards: Vec<Card>) -> Paragraph<'static> {
// string_vec_to_paragraph(cards.into_iter().map(card_area).flatten().collect())
// }

pub fn string_vec_to_paragraph(strings: Vec<String>) -> Paragraph<'static> {
let mut lines = Vec::new();
for line in strings {
lines.push(Line::from(line))
}
Paragraph::new(Text::from(lines)).alignment(ratatui::layout::Alignment::Center)
}
44 changes: 36 additions & 8 deletions src/interface/components/layouts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::engine::table::Seat;
use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
Frame,
Expand Down Expand Up @@ -45,13 +46,31 @@ impl MenuLayout {
}
}

pub struct PlayerLayout {
pub name_area: Rect,
pub hand_area: Rect,
}

impl PlayerLayout {
pub fn new(rect: Rect) -> Self {
let layout_base = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(2), Constraint::Fill(1)])
.split(rect);
Self {
name_area: layout_base[0],
hand_area: layout_base[1],
}
}
}

pub struct GameLayout {
pub left_score_area: Rect,
pub right_score_area: Rect,
pub top_player_area: Rect,
pub left_player_area: Rect,
pub right_player_area: Rect,
pub bottom_player_area: Rect,
pub top_player_area: PlayerLayout,
pub left_player_area: PlayerLayout,
pub right_player_area: PlayerLayout,
pub bottom_player_area: PlayerLayout,
pub table_area: Rect,
pub msg_input_area: Rect,
pub debug_area: Rect,
Expand Down Expand Up @@ -83,15 +102,24 @@ impl GameLayout {
Self {
left_score_area: layout_top[0],
right_score_area: layout_top[2],
top_player_area: layout_top[1],
left_player_area: layout_mid[0],
right_player_area: layout_mid[2],
bottom_player_area: layout_bot[1],
top_player_area: PlayerLayout::new(layout_top[1]),
left_player_area: PlayerLayout::new(layout_mid[0]),
right_player_area: PlayerLayout::new(layout_mid[2]),
bottom_player_area: PlayerLayout::new(layout_bot[1]),
table_area: layout_mid[1],
msg_input_area: layout_base[3],
debug_area: layout_bot[2],
}
}

pub fn get_player_area_by_seat(&self, seat: Seat) -> &PlayerLayout {
match seat {
Seat::Bottom => &self.bottom_player_area,
Seat::Left => &self.left_player_area,
Seat::Top => &self.top_player_area,
Seat::Right => &self.right_player_area,
}
}
}

// TODO: implement GameTableLayout
Expand Down
1 change: 1 addition & 0 deletions src/interface/components/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod ascii_text;
pub mod cards;
pub mod inputs;
pub mod layouts;
pub mod popups;
64 changes: 33 additions & 31 deletions src/interface/screens/game_screen.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use crate::engine::{
game::{Game, GameState},
player::Player,
table::Seat,
};
use crate::interface::{
components::{layouts::GameLayout, popups::centered_popup_area},
interface_callback::InterfaceCallback,
screens::Screen,
};
use crate::{
engine::{
card::Card,
game::{Game, GameState},
player::Player,
table::{Seat, SEAT_VARIANTS},
},
interface::components::cards::bottom_player_cards,
};
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
use ratatui::{
text::{Line, Text},
Expand Down Expand Up @@ -45,45 +49,43 @@ impl Screen for GameScreen {
// TODO: make reusable components for score boards and player areas
// TODO: implement score boards

// left score board
// render score boards
frame.render_widget(
Block::new().borders(Borders::ALL).title("Left Score"),
game_layout.left_score_area,
);

// top player area
let partner: &Player = self.game.get_player_in_seat(Seat::Top);
frame.render_widget(build_card_lines(partner), game_layout.top_player_area);

// right score board
frame.render_widget(
Block::new().borders(Borders::ALL).title("Right Score"),
game_layout.right_score_area,
);

// left player area
let left_player: &Player = self.game.get_player_in_seat(Seat::Left);
frame.render_widget(build_card_lines(left_player), game_layout.left_player_area);
// render player areas
for seat in SEAT_VARIANTS {
let player: &Player = self.game.get_player_in_seat(seat.clone());
let player_area = game_layout.get_player_area_by_seat(seat.clone());
frame.render_widget(Paragraph::new(player.name.as_str()), player_area.name_area);
// TODO: once all the card rendering logic is sorted out, this will be fully dynamic
match seat {
Seat::Bottom => {
frame.render_widget(
bottom_player_cards(player.hand.clone()),
game_layout.bottom_player_area.hand_area,
);
}
_ => {
frame.render_widget(build_card_lines(&player.hand), player_area.hand_area);
}
}
}

// table area
// render table area
frame.render_widget(
Block::new().borders(Borders::ALL).title("Table"),
game_layout.table_area,
);

// right player area
let right_player: &Player = self.game.get_player_in_seat(Seat::Right);
frame.render_widget(
build_card_lines(right_player),
game_layout.right_player_area,
);

// bottom player panel (user)
let user: &Player = self.game.get_player_in_seat(Seat::Bottom);
frame.render_widget(build_card_lines(user), game_layout.bottom_player_area);

// TODO: eventually remove debug area or hide behind cli flag
// debug area
// render debug area
let debug_block = Block::default().title("Debug");
let debug_area = debug_block.inner(game_layout.debug_area);
frame.render_widget(debug_block, game_layout.debug_area);
Expand Down Expand Up @@ -186,9 +188,9 @@ impl Screen for GameScreen {
}
}

fn build_card_lines(player: &Player) -> Text {
let mut lines = vec![Line::from(player.name.clone()), Line::from("")];
for card in player.hand.clone() {
fn build_card_lines(hand: &Vec<Card>) -> Text {
let mut lines = vec![];
for card in hand.clone() {
let line = Line::from(card.get_name());
lines.push(line);
}
Expand Down

0 comments on commit e4efad6

Please sign in to comment.