Skip to content

Commit

Permalink
Add scoring options.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ramirisu committed Oct 6, 2024
1 parent 7a729b2 commit 237d166
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 17 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ Classic Tetris (NES Tetris) written in BEVY/RUST.
| ------: | :-------------------------------------- |
| System | System default random number generator. |

**SCORING**

| Options | | 123 | 1,234,567 | 3,704,567 | 39,504,567 |
| ------: | :---------------------------------------------------------------- | -------: | --------: | --------: | ---------: |
| Decimal | Display the score in decimal up to `2^64`. | `000123` | `1234567` | `3704567` | `39504567` |
| Classic | Display the score in decimal up to `999999`. | `000123` | `999999` | `999999` | `999999` |
| Base36 | Apply `base36` encoding for the 6th digit and above of the score. | `000123` | `C34567` | `1104567` | `AZ04567` |

**TV SYSTEM**

| Options | |
Expand Down
15 changes: 13 additions & 2 deletions src/game/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::collections::VecDeque;

use super::{
piece::{Piece, Square},
score::get_score,
seed::Seed,
transition::Transition,
};
Expand Down Expand Up @@ -142,7 +141,7 @@ impl Board {
self.squares.remove(*row);
});

self.score += get_score(rows.len(), self.level());
self.score += Self::get_score(rows.len(), self.level());
self.lines += rows.len();
match rows.len() {
1 => self.single += 1,
Expand Down Expand Up @@ -273,6 +272,18 @@ impl Board {
fn is_inside(x: i32, y: i32) -> bool {
x >= 0 && x < Self::BOARD_COLS as i32 && y >= 0 && y < Self::INTERNAL_BOARD_ROWS as i32
}

fn get_score(lines: usize, level: usize) -> usize {
(level + 1)
* match lines {
0 => 0,
1 => 40,
2 => 100,
3 => 300,
4 => 1200,
_ => panic!("can only clear lines between 1-4"),
}
}
}

impl Default for Board {
Expand Down
4 changes: 3 additions & 1 deletion src/game/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bevy::prelude::*;

use super::{
das_counter::DASCounter, gravity::Gravity, linecap::Linecap, next_piece_hint::NextPieceHint,
seed::Seed, transition::Transition, tv_system::TVSystem,
score::Scoring, seed::Seed, transition::Transition, tv_system::TVSystem,
};

#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, States)]
Expand All @@ -20,6 +20,7 @@ pub struct GameConfig {
pub linecap: Linecap,
pub gravity: Gravity,
pub seed: Seed,
pub scoring: Scoring,
pub tv_system: TVSystem,
pub next_piece_hint: NextPieceHint,
pub das_counter: DASCounter,
Expand All @@ -33,6 +34,7 @@ impl Default for GameConfig {
transition: Transition::default(),
gravity: Gravity::default(),
seed: Seed::default(),
scoring: Scoring::default(),
tv_system: TVSystem::default(),
next_piece_hint: NextPieceHint::default(),
das_counter: DASCounter::default(),
Expand Down
2 changes: 1 addition & 1 deletion src/game/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ fn update_statistics_system(
text.sections[1].value = format!("{:03}", player_data.board.lines());
}
if let Ok(mut text) = query.p0().p1().get_single_mut() {
text.sections[1].value = format!("{:07}", player_data.board.score());
text.sections[1].value = game_config.scoring.format(player_data.board.score());
}
if let Ok(mut text) = query.p0().p2().get_single_mut() {
text.sections[1].value = format!("{:02}", player_data.board.level());
Expand Down
131 changes: 122 additions & 9 deletions src/game/score.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,124 @@
pub fn get_score(lines: usize, level: usize) -> usize {
(level + 1)
* match lines {
0 => 0,
1 => 40,
2 => 100,
3 => 300,
4 => 1200,
_ => panic!("can only clear lines between 1-4"),
use std::fmt::Display;

use num_traits::FromPrimitive;

#[derive(Default, Clone, Copy, PartialEq, Eq, FromPrimitive)]
pub enum Scoring {
#[default]
Decimal,
Classic,
Base36,
}

impl Scoring {
pub fn enum_has_prev(&self) -> bool {
<Self as FromPrimitive>::from_i64(*self as i64 - 1).is_some()
}

pub fn enum_has_next(&self) -> bool {
<Self as FromPrimitive>::from_i64(*self as i64 + 1).is_some()
}

pub fn enum_prev(&mut self) -> bool {
match FromPrimitive::from_i64(*self as i64 - 1) {
Some(n) => {
*self = n;
true
}
None => false,
}
}

pub fn enum_next(&mut self) -> bool {
match FromPrimitive::from_i64(*self as i64 + 1) {
Some(n) => {
*self = n;
true
}
None => false,
}
}

pub fn format(&self, score: usize) -> String {
match self {
Scoring::Decimal => format!("{:06}", score),
Scoring::Classic => {
if score > 999999 {
"999999".into()
} else {
format!("{:06}", score)
}
}
Scoring::Base36 => format!(
"{}{:05}",
Self::format_base36(score / 100000),
score % 100000
),
}
}

pub fn format_base36(mut value: usize) -> String {
let mut s = String::new();

while value > 0 {
s.push(char::from_digit((value % 36) as u32, 36).unwrap());
value /= 36;
}

if s.is_empty() {
s.push_str("0");
}

s.chars().map(|c| c.to_ascii_uppercase()).rev().collect()
}
}

impl Display for Scoring {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Scoring::Decimal => f.write_str("DECIMAL"),
Scoring::Classic => f.write_str("CLASSIC"),
Scoring::Base36 => f.write_str("BASE36"),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_decimal() {
let scoring = Scoring::Decimal;
assert_eq!(scoring.format(123), "000123");
assert_eq!(scoring.format(123456), "123456");
assert_eq!(scoring.format(999999), "999999");
assert_eq!(scoring.format(1000000), "1000000");
}

#[test]
fn test_classic() {
let scoring = Scoring::Classic;
assert_eq!(scoring.format(123), "000123");
assert_eq!(scoring.format(123456), "123456");
assert_eq!(scoring.format(999999), "999999");
assert_eq!(scoring.format(1000000), "999999");
}

#[test]
fn test_base36() {
let scoring = Scoring::Base36;
assert_eq!(scoring.format(123), "000123");
assert_eq!(scoring.format(123456), "123456");
assert_eq!(scoring.format(999999), "999999");
assert_eq!(scoring.format(1000000), "A00000");
assert_eq!(scoring.format(1100000), "B00000");
assert_eq!(scoring.format(1500000), "F00000");
assert_eq!(scoring.format(1600000), "G00000");
assert_eq!(scoring.format(3500000), "Z00000");
assert_eq!(scoring.format(3600000), "1000000");
assert_eq!(scoring.format(3700000), "1100000");
assert_eq!(scoring.format(36000000), "A000000");
assert_eq!(scoring.format(39500000), "AZ00000");
}
}
37 changes: 33 additions & 4 deletions src/game_option_menu/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ enum GameOptionMenuSelection {
Linecap,
Gravity,
Seed,
Scoring,
TVSystem,
NextPieceHint,
DASCounter,
Expand All @@ -78,9 +79,9 @@ enum GameOptionMenuSelection {
impl GameOptionMenuSelection {
pub fn iter() -> std::slice::Iter<'static, GameOptionMenuSelection> {
#[cfg(not(target_arch = "wasm32"))]
type ArrayType = [GameOptionMenuSelection; 18];
type ArrayType = [GameOptionMenuSelection; 19];
#[cfg(target_arch = "wasm32")]
type ArrayType = [GameOptionMenuSelection; 16];
type ArrayType = [GameOptionMenuSelection; 17];
const STATES: ArrayType = [
GameOptionMenuSelection::Tetris,
GameOptionMenuSelection::BlankLine0,
Expand All @@ -90,6 +91,7 @@ impl GameOptionMenuSelection {
GameOptionMenuSelection::Linecap,
GameOptionMenuSelection::Gravity,
GameOptionMenuSelection::Seed,
GameOptionMenuSelection::Scoring,
GameOptionMenuSelection::TVSystem,
GameOptionMenuSelection::NextPieceHint,
GameOptionMenuSelection::DASCounter,
Expand Down Expand Up @@ -311,6 +313,14 @@ fn update_ui_system(
game_config.seed.enum_has_next(),
);
}
GameOptionMenuSelection::Scoring => {
text.sections[0].value = fname_opt("SCORING");
text.sections[1].value = fopt(
game_config.scoring.to_string(),
game_config.scoring.enum_has_prev(),
game_config.scoring.enum_has_next(),
);
}
GameOptionMenuSelection::TVSystem => {
text.sections[0].value = fname_opt("TV SYSTEM");
text.sections[1].value = fopt(
Expand Down Expand Up @@ -509,7 +519,7 @@ fn handle_input_system(
game_option_menu_data.selection = GameOptionMenuSelection::Gravity;
selection_changed = true;
} else if player_inputs.down.just_pressed {
game_option_menu_data.selection = GameOptionMenuSelection::TVSystem;
game_option_menu_data.selection = GameOptionMenuSelection::Scoring;
selection_changed = true;
}

Expand All @@ -523,10 +533,29 @@ fn handle_input_system(
}
}
}
GameOptionMenuSelection::TVSystem => {
GameOptionMenuSelection::Scoring => {
if player_inputs.up.just_pressed {
game_option_menu_data.selection = GameOptionMenuSelection::Seed;
selection_changed = true;
} else if player_inputs.down.just_pressed {
game_option_menu_data.selection = GameOptionMenuSelection::TVSystem;
selection_changed = true;
}

if player_inputs.right.just_pressed {
if game_config.scoring.enum_next() {
option_changed = true;
}
} else if player_inputs.left.just_pressed {
if game_config.scoring.enum_prev() {
option_changed = true;
}
}
}
GameOptionMenuSelection::TVSystem => {
if player_inputs.up.just_pressed {
game_option_menu_data.selection = GameOptionMenuSelection::Scoring;
selection_changed = true;
} else if player_inputs.down.just_pressed {
game_option_menu_data.selection = GameOptionMenuSelection::NextPieceHint;
selection_changed = true;
Expand Down

0 comments on commit 237d166

Please sign in to comment.