mirror of
https://github.com/lucaspalomodevelop/binbreak.git
synced 2026-03-13 00:07:28 +00:00
Compare commits
3 Commits
de05e0c91c
...
b0ba9e63bd
| Author | SHA1 | Date | |
|---|---|---|---|
| b0ba9e63bd | |||
| 1b91536a5e | |||
|
|
cb4ea13866 |
@ -1,4 +1,4 @@
|
|||||||
[](https://github.com/epic-64/binbreak/actions)
|
[](https://github.com/epic-64/binbreak/actions)
|
||||||
[](https://ratatui.rs/)
|
[](https://ratatui.rs/)
|
||||||
|
|
||||||
https://github.com/user-attachments/assets/4413fe8d-9a3f-4c00-9c1a-b9ca01a946fc
|
https://github.com/user-attachments/assets/4413fe8d-9a3f-4c00-9c1a-b9ca01a946fc
|
||||||
|
|||||||
164
main.diff
Normal file
164
main.diff
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
diff --git a/src/app.rs b/src/app.rs
|
||||||
|
index 8229747..a62f54e 100644
|
||||||
|
--- a/src/app.rs
|
||||||
|
+++ b/src/app.rs
|
||||||
|
@@ -264,6 +264,7 @@ impl StartMenuState {
|
||||||
|
fn with_selected(selected_index: usize) -> Self {
|
||||||
|
let items = vec![
|
||||||
|
("easy (4 bits)".to_string(), Bits::Four),
|
||||||
|
+ ("easy Two's complement (4 bits)".to_string(), Bits::FourTwosComplement),
|
||||||
|
("easy+16 (4 bits*16)".to_string(), Bits::FourShift4),
|
||||||
|
("easy+256 (4 bits*256)".to_string(), Bits::FourShift8),
|
||||||
|
("easy+4096 (4 bits*4096)".to_string(), Bits::FourShift12),
|
||||||
|
diff --git a/src/binary_numbers.rs b/src/binary_numbers.rs
|
||||||
|
index 7c3791b..21db1ce 100644
|
||||||
|
--- a/src/binary_numbers.rs
|
||||||
|
+++ b/src/binary_numbers.rs
|
||||||
|
@@ -190,7 +190,13 @@ impl BinaryNumbersPuzzle {
|
||||||
|
|
||||||
|
Block::bordered().border_type(border_type).fg(border_color).render(area, buf);
|
||||||
|
|
||||||
|
- let suggestion_str = format!("{suggestion}");
|
||||||
|
+ let suggestion_str = if self.bits.is_twos_complement() {
|
||||||
|
+ // Convert raw bit pattern to signed value for display
|
||||||
|
+ let signed_val = self.bits.raw_to_signed(*suggestion);
|
||||||
|
+ format!("{signed_val}")
|
||||||
|
+ } else {
|
||||||
|
+ format!("{suggestion}")
|
||||||
|
+ };
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
Paragraph::new(suggestion_str.to_string())
|
||||||
|
@@ -642,6 +648,7 @@ enum GuessResult {
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Bits {
|
||||||
|
Four,
|
||||||
|
+ FourTwosComplement,
|
||||||
|
FourShift4,
|
||||||
|
FourShift8,
|
||||||
|
FourShift12,
|
||||||
|
@@ -654,6 +661,7 @@ impl Bits {
|
||||||
|
pub const fn to_int(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 => 4,
|
||||||
|
+ Self::FourTwosComplement => 4,
|
||||||
|
Self::Eight => 8,
|
||||||
|
Self::Twelve => 12,
|
||||||
|
Self::Sixteen => 16,
|
||||||
|
@@ -662,6 +670,7 @@ impl Bits {
|
||||||
|
pub const fn scale_factor(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Four => 1,
|
||||||
|
+ Self::FourTwosComplement => 1,
|
||||||
|
Self::FourShift4 => 16,
|
||||||
|
Self::FourShift8 => 256,
|
||||||
|
Self::FourShift12 => 4096,
|
||||||
|
@@ -673,6 +682,7 @@ impl Bits {
|
||||||
|
pub const fn high_score_key(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Four => 4,
|
||||||
|
+ Self::FourTwosComplement => 42, // separate key for two's complement
|
||||||
|
Self::FourShift4 => 44,
|
||||||
|
Self::FourShift8 => 48,
|
||||||
|
Self::FourShift12 => 412,
|
||||||
|
@@ -686,7 +696,7 @@ impl Bits {
|
||||||
|
}
|
||||||
|
pub const fn suggestion_count(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
- Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 => 3,
|
||||||
|
+ Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 | Self::FourTwosComplement => 3,
|
||||||
|
Self::Eight => 4,
|
||||||
|
Self::Twelve => 5,
|
||||||
|
Self::Sixteen => 6,
|
||||||
|
@@ -695,6 +705,7 @@ impl Bits {
|
||||||
|
pub const fn label(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Four => "4 bits",
|
||||||
|
+ Self::FourTwosComplement => "4 bits (Two's complement)",
|
||||||
|
Self::FourShift4 => "4 bits*16",
|
||||||
|
Self::FourShift8 => "4 bits*256",
|
||||||
|
Self::FourShift12 => "4 bits*4096",
|
||||||
|
@@ -703,6 +714,25 @@ impl Bits {
|
||||||
|
Self::Sixteen => "16 bits",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /// Convert raw bit pattern to signed value for two's complement mode
|
||||||
|
+ pub const fn raw_to_signed(&self, raw: u32) -> i32 {
|
||||||
|
+ match self {
|
||||||
|
+ Self::FourTwosComplement => {
|
||||||
|
+ // 4-bit two's complement: range -8 to +7
|
||||||
|
+ if raw >= 8 {
|
||||||
|
+ (raw as i32) - 16
|
||||||
|
+ } else {
|
||||||
|
+ raw as i32
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
+ _ => raw as i32, // other modes use unsigned
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ pub const fn is_twos_complement(&self) -> bool {
|
||||||
|
+ matches!(self, Self::FourTwosComplement)
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BinaryNumbersPuzzle {
|
||||||
|
@@ -725,21 +755,40 @@ impl BinaryNumbersPuzzle {
|
||||||
|
|
||||||
|
let mut suggestions = Vec::new();
|
||||||
|
let scale = bits.scale_factor();
|
||||||
|
- while suggestions.len() < bits.suggestion_count() {
|
||||||
|
- let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
||||||
|
- let num = raw * scale;
|
||||||
|
- if !suggestions.contains(&num) {
|
||||||
|
- suggestions.push(num);
|
||||||
|
+
|
||||||
|
+ if bits.is_twos_complement() {
|
||||||
|
+ // For two's complement, generate unique raw bit patterns (0-15)
|
||||||
|
+ let mut raw_values: Vec<u32> = Vec::new();
|
||||||
|
+ while raw_values.len() < bits.suggestion_count() {
|
||||||
|
+ let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
||||||
|
+ if !raw_values.contains(&raw) {
|
||||||
|
+ raw_values.push(raw);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Store raw bit patterns directly
|
||||||
|
+ suggestions = raw_values;
|
||||||
|
+ } else {
|
||||||
|
+ // For unsigned modes
|
||||||
|
+ while suggestions.len() < bits.suggestion_count() {
|
||||||
|
+ let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
||||||
|
+ let num = raw * scale;
|
||||||
|
+ if !suggestions.contains(&num) {
|
||||||
|
+ suggestions.push(num);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- let current_number = suggestions[0]; // scaled value
|
||||||
|
- let raw_current_number = current_number / scale; // back-calculate raw bits
|
||||||
|
+ let current_number = suggestions[0]; // scaled value or raw for twos complement
|
||||||
|
+ let raw_current_number = if bits.is_twos_complement() {
|
||||||
|
+ current_number // for two's complement, it's already the raw bit pattern
|
||||||
|
+ } else {
|
||||||
|
+ current_number / scale // back-calculate raw bits
|
||||||
|
+ };
|
||||||
|
suggestions.shuffle(&mut rng);
|
||||||
|
|
||||||
|
// Base time by bits + difficulty scaling (shorter as streak increases)
|
||||||
|
let base_time = match bits {
|
||||||
|
- Bits::Four | Bits::FourShift4 | Bits::FourShift8 | Bits::FourShift12 => 8.0,
|
||||||
|
+ Bits::Four | Bits::FourShift4 | Bits::FourShift8 | Bits::FourShift12 | Bits::FourTwosComplement => 8.0,
|
||||||
|
Bits::Eight => 12.0,
|
||||||
|
Bits::Twelve => 16.0,
|
||||||
|
Bits::Sixteen => 20.0,
|
||||||
|
@@ -868,7 +917,7 @@ impl HighScores {
|
||||||
|
|
||||||
|
fn save(&self) -> std::io::Result<()> {
|
||||||
|
let mut data = String::new();
|
||||||
|
- for key in [4u32, 44u32, 48u32, 412u32, 8u32, 12u32, 16u32] {
|
||||||
|
+ for key in [4u32, 42u32, 44u32, 48u32, 412u32, 8u32, 12u32, 16u32] {
|
||||||
|
let val = self.get(key);
|
||||||
|
let _ = writeln!(data, "{key}={val}");
|
||||||
|
}
|
||||||
@ -264,6 +264,7 @@ impl StartMenuState {
|
|||||||
fn with_selected(selected_index: usize) -> Self {
|
fn with_selected(selected_index: usize) -> Self {
|
||||||
let items = vec![
|
let items = vec![
|
||||||
("easy (4 bits)".to_string(), Bits::Four),
|
("easy (4 bits)".to_string(), Bits::Four),
|
||||||
|
("easy Two's complement (4 bits)".to_string(), Bits::FourTwosComplement),
|
||||||
("easy+16 (4 bits*16)".to_string(), Bits::FourShift4),
|
("easy+16 (4 bits*16)".to_string(), Bits::FourShift4),
|
||||||
("easy+256 (4 bits*256)".to_string(), Bits::FourShift8),
|
("easy+256 (4 bits*256)".to_string(), Bits::FourShift8),
|
||||||
("easy+4096 (4 bits*4096)".to_string(), Bits::FourShift12),
|
("easy+4096 (4 bits*4096)".to_string(), Bits::FourShift12),
|
||||||
|
|||||||
@ -190,7 +190,13 @@ impl BinaryNumbersPuzzle {
|
|||||||
|
|
||||||
Block::bordered().border_type(border_type).fg(border_color).render(area, buf);
|
Block::bordered().border_type(border_type).fg(border_color).render(area, buf);
|
||||||
|
|
||||||
let suggestion_str = format!("{suggestion}");
|
let suggestion_str = if self.bits.is_twos_complement() {
|
||||||
|
// Convert raw bit pattern to signed value for display
|
||||||
|
let signed_val = self.bits.raw_to_signed(*suggestion);
|
||||||
|
format!("{signed_val}")
|
||||||
|
} else {
|
||||||
|
format!("{suggestion}")
|
||||||
|
};
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
Paragraph::new(suggestion_str.to_string())
|
Paragraph::new(suggestion_str.to_string())
|
||||||
@ -642,6 +648,7 @@ enum GuessResult {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Bits {
|
pub enum Bits {
|
||||||
Four,
|
Four,
|
||||||
|
FourTwosComplement,
|
||||||
FourShift4,
|
FourShift4,
|
||||||
FourShift8,
|
FourShift8,
|
||||||
FourShift12,
|
FourShift12,
|
||||||
@ -653,7 +660,7 @@ pub enum Bits {
|
|||||||
impl Bits {
|
impl Bits {
|
||||||
pub const fn to_int(&self) -> u32 {
|
pub const fn to_int(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 => 4,
|
Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 | Self::FourTwosComplement=> 4,
|
||||||
Self::Eight => 8,
|
Self::Eight => 8,
|
||||||
Self::Twelve => 12,
|
Self::Twelve => 12,
|
||||||
Self::Sixteen => 16,
|
Self::Sixteen => 16,
|
||||||
@ -662,6 +669,7 @@ impl Bits {
|
|||||||
pub const fn scale_factor(&self) -> u32 {
|
pub const fn scale_factor(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Four => 1,
|
Self::Four => 1,
|
||||||
|
Self::FourTwosComplement => 1,
|
||||||
Self::FourShift4 => 16,
|
Self::FourShift4 => 16,
|
||||||
Self::FourShift8 => 256,
|
Self::FourShift8 => 256,
|
||||||
Self::FourShift12 => 4096,
|
Self::FourShift12 => 4096,
|
||||||
@ -673,6 +681,7 @@ impl Bits {
|
|||||||
pub const fn high_score_key(&self) -> u32 {
|
pub const fn high_score_key(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Four => 4,
|
Self::Four => 4,
|
||||||
|
Self::FourTwosComplement => 42, // separate key for two's complement
|
||||||
Self::FourShift4 => 44,
|
Self::FourShift4 => 44,
|
||||||
Self::FourShift8 => 48,
|
Self::FourShift8 => 48,
|
||||||
Self::FourShift12 => 412,
|
Self::FourShift12 => 412,
|
||||||
@ -686,7 +695,7 @@ impl Bits {
|
|||||||
}
|
}
|
||||||
pub const fn suggestion_count(&self) -> usize {
|
pub const fn suggestion_count(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 => 3,
|
Self::Four | Self::FourShift4 | Self::FourShift8 | Self::FourShift12 | Self::FourTwosComplement => 3,
|
||||||
Self::Eight => 4,
|
Self::Eight => 4,
|
||||||
Self::Twelve => 5,
|
Self::Twelve => 5,
|
||||||
Self::Sixteen => 6,
|
Self::Sixteen => 6,
|
||||||
@ -695,6 +704,7 @@ impl Bits {
|
|||||||
pub const fn label(&self) -> &'static str {
|
pub const fn label(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Four => "4 bits",
|
Self::Four => "4 bits",
|
||||||
|
Self::FourTwosComplement => "4 bits (Two's complement)",
|
||||||
Self::FourShift4 => "4 bits*16",
|
Self::FourShift4 => "4 bits*16",
|
||||||
Self::FourShift8 => "4 bits*256",
|
Self::FourShift8 => "4 bits*256",
|
||||||
Self::FourShift12 => "4 bits*4096",
|
Self::FourShift12 => "4 bits*4096",
|
||||||
@ -703,6 +713,25 @@ impl Bits {
|
|||||||
Self::Sixteen => "16 bits",
|
Self::Sixteen => "16 bits",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert raw bit pattern to signed value for two's complement mode
|
||||||
|
pub const fn raw_to_signed(&self, raw: u32) -> i32 {
|
||||||
|
match self {
|
||||||
|
Self::FourTwosComplement => {
|
||||||
|
// 4-bit two's complement: range -8 to +7
|
||||||
|
if raw >= 8 {
|
||||||
|
(raw as i32) - 16
|
||||||
|
} else {
|
||||||
|
raw as i32
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => raw as i32, // other modes use unsigned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn is_twos_complement(&self) -> bool {
|
||||||
|
matches!(self, Self::FourTwosComplement)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BinaryNumbersPuzzle {
|
pub struct BinaryNumbersPuzzle {
|
||||||
@ -725,21 +754,40 @@ impl BinaryNumbersPuzzle {
|
|||||||
|
|
||||||
let mut suggestions = Vec::new();
|
let mut suggestions = Vec::new();
|
||||||
let scale = bits.scale_factor();
|
let scale = bits.scale_factor();
|
||||||
while suggestions.len() < bits.suggestion_count() {
|
|
||||||
let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
if bits.is_twos_complement() {
|
||||||
let num = raw * scale;
|
// For two's complement, generate unique raw bit patterns (0-15)
|
||||||
if !suggestions.contains(&num) {
|
let mut raw_values: Vec<u32> = Vec::new();
|
||||||
suggestions.push(num);
|
while raw_values.len() < bits.suggestion_count() {
|
||||||
|
let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
||||||
|
if !raw_values.contains(&raw) {
|
||||||
|
raw_values.push(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store raw bit patterns directly
|
||||||
|
suggestions = raw_values;
|
||||||
|
} else {
|
||||||
|
// For unsigned modes
|
||||||
|
while suggestions.len() < bits.suggestion_count() {
|
||||||
|
let raw = rng.random_range(0..u32::pow(2, bits.to_int()));
|
||||||
|
let num = raw * scale;
|
||||||
|
if !suggestions.contains(&num) {
|
||||||
|
suggestions.push(num);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_number = suggestions[0]; // scaled value
|
let current_number = suggestions[0]; // scaled value or raw for twos complement
|
||||||
let raw_current_number = current_number / scale; // back-calculate raw bits
|
let raw_current_number = if bits.is_twos_complement() {
|
||||||
|
current_number // for two's complement, it's already the raw bit pattern
|
||||||
|
} else {
|
||||||
|
current_number / scale // back-calculate raw bits
|
||||||
|
};
|
||||||
suggestions.shuffle(&mut rng);
|
suggestions.shuffle(&mut rng);
|
||||||
|
|
||||||
// Base time by bits + difficulty scaling (shorter as streak increases)
|
// Base time by bits + difficulty scaling (shorter as streak increases)
|
||||||
let base_time = match bits {
|
let base_time = match bits {
|
||||||
Bits::Four | Bits::FourShift4 | Bits::FourShift8 | Bits::FourShift12 => 8.0,
|
Bits::Four | Bits::FourShift4 | Bits::FourShift8 | Bits::FourShift12 | Bits::FourTwosComplement => 8.0,
|
||||||
Bits::Eight => 12.0,
|
Bits::Eight => 12.0,
|
||||||
Bits::Twelve => 16.0,
|
Bits::Twelve => 16.0,
|
||||||
Bits::Sixteen => 20.0,
|
Bits::Sixteen => 20.0,
|
||||||
@ -868,7 +916,7 @@ impl HighScores {
|
|||||||
|
|
||||||
fn save(&self) -> std::io::Result<()> {
|
fn save(&self) -> std::io::Result<()> {
|
||||||
let mut data = String::new();
|
let mut data = String::new();
|
||||||
for key in [4u32, 44u32, 48u32, 412u32, 8u32, 12u32, 16u32] {
|
for key in [4u32, 42u32, 44u32, 48u32, 412u32, 8u32, 12u32, 16u32] {
|
||||||
let val = self.get(key);
|
let val = self.get(key);
|
||||||
let _ = writeln!(data, "{key}={val}");
|
let _ = writeln!(data, "{key}={val}");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user