|
@@ -21,6 +21,7 @@ mod board {}
|
|
|
|
|
|
const DEFAULT_ROWS: usize = 17;
|
|
const DEFAULT_ROWS: usize = 17;
|
|
const DEFAULT_COLS: usize = 24;
|
|
const DEFAULT_COLS: usize = 24;
|
|
|
|
+const BORDER_HEX_WIDTH: usize = 6;
|
|
|
|
|
|
// Different actions are printed to the console at different speeds: the
|
|
// Different actions are printed to the console at different speeds: the
|
|
// "terminal" displaying output, vs. the player "typing", for example.
|
|
// "terminal" displaying output, vs. the player "typing", for example.
|
|
@@ -69,40 +70,45 @@ impl Board {
|
|
Board {
|
|
Board {
|
|
rows: r,
|
|
rows: r,
|
|
cols: c,
|
|
cols: c,
|
|
- c: Board::garbage_vec(r, c)
|
|
|
|
|
|
+ c: vec![' '; r * c]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- fn garbage_vec(rows: usize, cols: usize) -> Vec<char> {
|
|
|
|
|
|
+ fn fill_with_garbage(&mut self) {
|
|
let g: Vec<char> = "!@#$%^*()_-=+\\|/[]{}?\"\':;,.<>".chars().collect();
|
|
let g: Vec<char> = "!@#$%^*()_-=+\\|/[]{}?\"\':;,.<>".chars().collect();
|
|
- let mut b = Vec::with_capacity(rows * cols);
|
|
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
|
- for _ in 0..rows * cols {
|
|
|
|
- b.push(*g.choose(&mut rng).unwrap());
|
|
|
|
|
|
+ for i in 0..self.rows * self.cols {
|
|
|
|
+ self.c[i] = *g.choose(&mut rng).unwrap();
|
|
}
|
|
}
|
|
-
|
|
|
|
- b
|
|
|
|
}
|
|
}
|
|
|
|
|
|
fn capacity(&self) -> usize {
|
|
fn capacity(&self) -> usize {
|
|
self.c.len()
|
|
self.c.len()
|
|
}
|
|
}
|
|
|
|
|
|
- fn get(&self, i: usize) -> char {
|
|
|
|
|
|
+ fn get_i(&self, i: usize) -> char {
|
|
self.c[i]
|
|
self.c[i]
|
|
}
|
|
}
|
|
|
|
|
|
- fn getxy(&self, x: usize, y: usize) -> char {
|
|
|
|
|
|
+ fn get_xy(&self, x: usize, y: usize) -> char {
|
|
self.c[x*y]
|
|
self.c[x*y]
|
|
}
|
|
}
|
|
|
|
|
|
- fn set(&mut self, i: usize, c: char) {
|
|
|
|
|
|
+ fn set_i(&mut self, i: usize, c: char) {
|
|
self.c[i] = c;
|
|
self.c[i] = c;
|
|
}
|
|
}
|
|
|
|
|
|
- fn setxy(&mut self, x: usize, y: usize, c: char) {
|
|
|
|
- self.c[x*y] = c;
|
|
|
|
|
|
+ fn set_xy(&mut self, x: usize, y: usize, c: char) {
|
|
|
|
+ self.set_i(x*y, c);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn set_i_str(&mut self, i: usize, s: &str) {
|
|
|
|
+ s.chars().enumerate().for_each(|(str_index, c)| self.set_i(i+str_index, c));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn set_xy_str(&mut self, x: usize, y: usize, s: &str) {
|
|
|
|
+ s.chars().enumerate().for_each(|(str_index, c)| self.set_i((x*y)+str_index, c));
|
|
}
|
|
}
|
|
|
|
|
|
// Think of the board in word_len "chunks": place a slot for a word in each chunk
|
|
// Think of the board in word_len "chunks": place a slot for a word in each chunk
|
|
@@ -115,47 +121,55 @@ impl Board {
|
|
word_len+1, word_len, chunk_len);
|
|
word_len+1, word_len, chunk_len);
|
|
}
|
|
}
|
|
let mut coords: Vec<Coord> = Vec::with_capacity(num_of_words);
|
|
let mut coords: Vec<Coord> = Vec::with_capacity(num_of_words);
|
|
- let mut starting_coord = 0;
|
|
|
|
|
|
+ let mut starting_coord: usize = 0;
|
|
for _ in 0..num_of_words {
|
|
for _ in 0..num_of_words {
|
|
let coord = Coord::new(starting_coord, word_len);
|
|
let coord = Coord::new(starting_coord, word_len);
|
|
- coords.push(coord);
|
|
|
|
starting_coord+=chunk_len;
|
|
starting_coord+=chunk_len;
|
|
|
|
+ assert!(starting_coord > coord.end);
|
|
|
|
+ coords.push(coord);
|
|
}
|
|
}
|
|
coords
|
|
coords
|
|
}
|
|
}
|
|
|
|
|
|
// "shake" each word slot around, in a random order, 3 times/word.
|
|
// "shake" each word slot around, in a random order, 3 times/word.
|
|
- fn shake_words(&self, word_coords: &mut Vec<Coord>) {
|
|
|
|
|
|
+ fn shake_coords(&self, word_coords: &mut Vec<Coord>) {
|
|
let mut rng = rand::thread_rng();
|
|
let mut rng = rand::thread_rng();
|
|
|
|
|
|
for _ in 0..3 {
|
|
for _ in 0..3 {
|
|
- let mut positions: Vec<usize> = (0..word_coords.len()).collect();
|
|
|
|
- positions.shuffle(&mut rng);
|
|
|
|
- for i in positions {
|
|
|
|
|
|
+ let indices: Vec<usize> = (0..word_coords.len()).collect();
|
|
|
|
+ let shuffled_indices = copy_shuffle(&indices);
|
|
|
|
+
|
|
|
|
+ for i in shuffled_indices {
|
|
let coord = &word_coords[i];
|
|
let coord = &word_coords[i];
|
|
// Where can this coord move (leaving at least 1 space between words)?
|
|
// Where can this coord move (leaving at least 1 space between words)?
|
|
let mut movement_options = Vec::with_capacity(2);
|
|
let mut movement_options = Vec::with_capacity(2);
|
|
|
|
|
|
- let mut start = coord.start as i32;
|
|
|
|
- let mut end = -2;
|
|
|
|
- if i > 0 {
|
|
|
|
|
|
+ let start = coord.start as i32;
|
|
|
|
+ let previous_coord_end: i32;
|
|
|
|
+ if i == 0 {
|
|
|
|
+ previous_coord_end = coord.start as i32;
|
|
|
|
+ } else {
|
|
let prev_coord = &word_coords[i-1];
|
|
let prev_coord = &word_coords[i-1];
|
|
- end = prev_coord.end as i32;
|
|
|
|
|
|
+ previous_coord_end = prev_coord.end as i32;
|
|
}
|
|
}
|
|
- if start - end > 1 {
|
|
|
|
|
|
+ let space_behind = start - previous_coord_end;
|
|
|
|
+ if space_behind > 1 {
|
|
// It can move backwards
|
|
// It can move backwards
|
|
- movement_options.push((start-end-1) * -1);
|
|
|
|
|
|
+ movement_options.push((space_behind-1) * -1);
|
|
}
|
|
}
|
|
|
|
|
|
- start = self.capacity() as i32;
|
|
|
|
- end = coord.end as i32;
|
|
|
|
- if i < word_coords.len()-1 {
|
|
|
|
|
|
+ let next_coord_start: i32;
|
|
|
|
+ let end = coord.end as i32;
|
|
|
|
+ if i == word_coords.len()-1 {
|
|
|
|
+ next_coord_start = self.capacity() as i32;
|
|
|
|
+ } else {
|
|
let next_coord = &word_coords[i+1];
|
|
let next_coord = &word_coords[i+1];
|
|
- start = next_coord.start as i32;
|
|
|
|
|
|
+ next_coord_start = next_coord.start as i32;
|
|
}
|
|
}
|
|
- if start - end > 1 {
|
|
|
|
|
|
+ let space_in_front = next_coord_start - end;
|
|
|
|
+ if space_in_front > 1 {
|
|
// It can move forwards
|
|
// It can move forwards
|
|
- movement_options.push(start-end-1);
|
|
|
|
|
|
+ movement_options.push(space_in_front-1);
|
|
}
|
|
}
|
|
|
|
|
|
// Pick a movement option, & pick some amount to move
|
|
// Pick a movement option, & pick some amount to move
|
|
@@ -174,6 +188,23 @@ impl Board {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ fn insert_words(&mut self, words: &[String], coords: &Vec<Coord>) {
|
|
|
|
+ assert_eq!(words.len(), coords.len());
|
|
|
|
+ for (word, coord) in words.iter().zip(coords.iter()) {
|
|
|
|
+ assert_eq!(word.len(), coord.end - coord.start + 1);
|
|
|
|
+ for (ch, coord_index) in word.chars().zip(coord.start..coord.end+1) {
|
|
|
|
+ self.c[coord_index] = ch;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn dump(&self) {
|
|
|
|
+ for chunk in self.c.chunks(self.rows) {
|
|
|
|
+ let s: String = chunk.iter().collect();
|
|
|
|
+ println!("{}", s);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
impl Screen {
|
|
impl Screen {
|
|
@@ -181,10 +212,12 @@ impl Screen {
|
|
let window = initscr();
|
|
let window = initscr();
|
|
noecho();
|
|
noecho();
|
|
window_enable_colors();
|
|
window_enable_colors();
|
|
|
|
+ let mut b = Board::new(conf.rows, conf.cols);
|
|
|
|
+ b.fill_with_garbage();
|
|
Screen {
|
|
Screen {
|
|
w: window,
|
|
w: window,
|
|
attempts_left: 4,
|
|
attempts_left: 4,
|
|
- b: Board::new(conf.rows, conf.cols)
|
|
|
|
|
|
+ b: b
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -199,7 +232,7 @@ impl Screen {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn initialize_game(&self, conf: Config) {
|
|
|
|
|
|
+ pub fn initialize_game(&mut self, conf: Config) {
|
|
self.print_with_delay(0, String::from("ROBCO INDUSTRIES (TM) TERMLINK PROTOCOL"), false, TERMINAL_PRINTING_SPEED);
|
|
self.print_with_delay(0, String::from("ROBCO INDUSTRIES (TM) TERMLINK PROTOCOL"), false, TERMINAL_PRINTING_SPEED);
|
|
self.print_with_delay(1, String::from("ENTER PASSWORD NOW"), false, TERMINAL_PRINTING_SPEED);
|
|
self.print_with_delay(1, String::from("ENTER PASSWORD NOW"), false, TERMINAL_PRINTING_SPEED);
|
|
self.print_with_delay(
|
|
self.print_with_delay(
|
|
@@ -208,7 +241,6 @@ impl Screen {
|
|
false,
|
|
false,
|
|
TERMINAL_PRINTING_SPEED
|
|
TERMINAL_PRINTING_SPEED
|
|
);
|
|
);
|
|
- let border_hex = border_hex_gen(self.b.rows);
|
|
|
|
|
|
|
|
let shuffled_words = copy_shuffle(&conf.words);
|
|
let shuffled_words = copy_shuffle(&conf.words);
|
|
let words = &shuffled_words[..conf.choose];
|
|
let words = &shuffled_words[..conf.choose];
|
|
@@ -222,11 +254,16 @@ impl Screen {
|
|
}
|
|
}
|
|
|
|
|
|
let mut coords = self.b.build_word_coords(words.len(), word_len);
|
|
let mut coords = self.b.build_word_coords(words.len(), word_len);
|
|
- self.b.shake_words(&mut coords);
|
|
|
|
-
|
|
|
|
|
|
+ self.b.shake_coords(&mut coords);
|
|
println!("{:?}", coords);
|
|
println!("{:?}", coords);
|
|
- println!("{:?}", self.b);
|
|
|
|
|
|
+ self.b.insert_words(words, &coords);
|
|
|
|
+
|
|
|
|
+ let mut screen_buffer = Board::new(Some(self.b.rows), Some(self.b.cols + (2 * BORDER_HEX_WIDTH) + 3));
|
|
|
|
+ let border_hex = border_hex_gen(self.b.rows, self.b.cols);
|
|
|
|
+ self.add_border_hex_to_board(&mut screen_buffer, &border_hex);
|
|
|
|
|
|
|
|
+ self.b.dump();
|
|
|
|
+ screen_buffer.dump();
|
|
}
|
|
}
|
|
|
|
|
|
pub fn end_window(&self) {
|
|
pub fn end_window(&self) {
|
|
@@ -250,10 +287,27 @@ impl Screen {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- fn attempts_display(&self) -> String {
|
|
|
|
|
|
+ fn build_attempts_display(&self) -> String {
|
|
format!("{} ATTEMPT(S) LEFT:{}", self.attempts_left, " *".repeat(self.attempts_left as usize))
|
|
format!("{} ATTEMPT(S) LEFT:{}", self.attempts_left, " *".repeat(self.attempts_left as usize))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ fn add_border_hex_to_board(&self, board: &mut Board, hex: &Vec<u32>) {
|
|
|
|
+ let left_side = (0..board.rows).zip(hex.iter());
|
|
|
|
+ let right_side = (board.rows..).zip(hex[board.rows..].iter());
|
|
|
|
+
|
|
|
|
+ for (y, hex_val) in left_side {
|
|
|
|
+ println!("Printing 0x{:x} at 0, {}", hex_val, y);
|
|
|
|
+ board.set_xy_str(0, y, &format!("0x{:x}", hex_val));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Half the board, plus characters for the first hex values, plus 2 spaces of padding.
|
|
|
|
+ let right_hand_offset = board.cols / 2;
|
|
|
|
+ for (y, hex_val) in right_side {
|
|
|
|
+ println!("Printing 0x{:x} at {}, {}", hex_val, right_hand_offset, y);
|
|
|
|
+ board.set_xy_str(right_hand_offset, y, &format!("0x{:x}", hex_val));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
fn window_enable_colors() {
|
|
fn window_enable_colors() {
|
|
@@ -263,7 +317,7 @@ fn window_enable_colors() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-fn border_hex_gen(rows: usize) -> Vec<u32> {
|
|
|
|
|
|
+fn border_hex_gen(rows: usize, cols: usize) -> Vec<u32> {
|
|
// Build the hex values, printed alongside the text and garbage.
|
|
// Build the hex values, printed alongside the text and garbage.
|
|
// The vector will be of length rows * 2
|
|
// The vector will be of length rows * 2
|
|
// TODO: this would make a nice generator, once those are stable.
|
|
// TODO: this would make a nice generator, once those are stable.
|
|
@@ -273,7 +327,7 @@ fn border_hex_gen(rows: usize) -> Vec<u32> {
|
|
let mut ls = Vec::with_capacity(rows * 2);
|
|
let mut ls = Vec::with_capacity(rows * 2);
|
|
for _ in 0..rows * 2 {
|
|
for _ in 0..rows * 2 {
|
|
ls.push(hex);
|
|
ls.push(hex);
|
|
- hex += 12;
|
|
|
|
|
|
+ hex += (cols / 2) as u32;
|
|
}
|
|
}
|
|
|
|
|
|
ls
|
|
ls
|