123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- // Board control and interaction. The view & controller.
- //
- extern crate pancurses;
- use self::pancurses::{
- initscr, endwin, noecho, has_colors, start_color, init_pair,
- Window,
- COLOR_GREEN, COLOR_BLACK
- };
- extern crate rand;
- use self::rand::Rng;
- use std::{thread, time};
- use config::{Config};
- use util::{copy_shuffle};
- use grid::Grid;
- mod board {}
- const BORDER_HEX_WIDTH: usize = 6;
- // Different actions are printed to the console at different speeds: the
- // "terminal" displaying output, vs. the player "typing", for example.
- const TERMINAL_PRINTING_SPEED: time::Duration = time::Duration::from_millis(20);
- const TYPING_SPEED: time::Duration = time::Duration::from_millis(70);
- // Everything displayed to the player, + a reference to the curses Window.
- #[derive(Debug)]
- pub struct Screen {
- pub w: Window,
- attempts_left: u8,
- board: Grid
- }
- impl Screen {
- pub fn new(conf: &Config) -> Screen {
- let window = initscr();
- noecho();
- window_enable_colors();
- let mut board = Grid::new(conf.rows, conf.cols);
- board.fill_with_garbage();
- Screen {
- w: window,
- attempts_left: 4,
- board: board
- }
- }
- pub fn intro(&self) {
- self.w.clear();
- thread::sleep(time::Duration::from_millis(250));
- self.print_with_delay(0, String::from("WELCOME TO ROBCO INDUSTRIES (TM) TERMLINK"), true, TERMINAL_PRINTING_SPEED);
- self.move_cursor_to(1, 0);
- thread::sleep(time::Duration::from_millis(30));
- // TODO the rest of the intro
- }
- 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(1, String::from("ENTER PASSWORD NOW"), false, TERMINAL_PRINTING_SPEED);
- self.print_with_delay(
- 3,
- self.build_attempts_display(),
- false,
- TERMINAL_PRINTING_SPEED
- );
- let shuffled_words = copy_shuffle(&conf.words);
- let words = &shuffled_words[..conf.choose];
- let coords = self.board.randomly_add_words(words);
- // The board of words + garbage characters has been built: now the screen must be displayed.
- let mut screen_buffer = Grid::new(Some(self.board.rows), Some(self.board.cols + (2 * BORDER_HEX_WIDTH) + 3));
- let border_hex = border_hex_gen(self.board.rows, self.board.cols);
- self.add_border_hex_to_grid(&mut screen_buffer, &border_hex);
- self.add_board_to_grid(&mut screen_buffer);
- // Debugging
- trace!("Screen:\n{}", screen_buffer.dump());
- }
- pub fn end_window(&self) {
- endwin();
- }
- fn move_cursor_to(&self, y: i32, x: i32) {
- self.w.mv(y, x);
- self.w.refresh();
- }
- fn print_with_delay(&self, line: i32, string: String, skippable: bool, delay: time::Duration) {
- self.w.mv(line, 0);
- for c in string.chars() {
- self.w.addch(c);
- self.w.refresh();
- if skippable {
- // TODO keyboard skip
- }
- thread::sleep(delay);
- }
- }
- fn build_attempts_display(&self) -> String {
- format!("{} ATTEMPT(S) LEFT:{}", self.attempts_left, " *".repeat(self.attempts_left as usize))
- }
- fn add_border_hex_to_grid(&self, grid: &mut Grid, hex: &Vec<u32>) {
- let left_side = (0..grid.rows).zip(hex.iter());
- let right_side = (0..grid.rows).zip(hex[grid.rows..].iter());
- trace!("Left side from 0..{}, right side from {}..{}", grid.rows, grid.rows, hex.len());
- for (row, hex_val) in left_side {
- trace!("Printing 0x{:x} at {}, 0", hex_val, row);
- grid.set_rowcol_str(row, 0, &format!("0x{:x}", hex_val));
- }
- // Half the board, plus characters for the first hex values, plus 2 spaces of padding.
- let right_hand_offset = (grid.cols / 2) + 1;
- for (row, hex_val) in right_side {
- trace!("Printing 0x{:x} at {}, {}", hex_val, row, right_hand_offset);
- grid.set_rowcol_str(row, right_hand_offset, &format!("0x{:x}", hex_val));
- }
- }
- fn add_board_to_grid(&self, grid: &mut Grid) {
- // TODO
- // The board is pressed to the right of each column
- // Where to start placing the board on each row: (grid.cols / 2) - (self.board.cols / 2)
- // TODO this should dynamically check size
- let left_side_start = (grid.cols / 2) - (self.board.cols / 2);
- let right_side_start = (grid.cols) - (self.board.cols / 2);
- let mut board_iter = self.board.iter();
- for row in 0..self.board.rows {
- for col in 0..(self.board.cols / 2) {
- grid.set_rowcol(row, left_side_start + col, *board_iter.next().unwrap());
- }
- }
- for row in 0..self.board.rows {
- for col in 0..(self.board.cols / 2) {
- grid.set_rowcol(row, right_side_start + col, *board_iter.next().unwrap());
- }
- }
- }
- }
- fn window_enable_colors() {
- if has_colors() {
- start_color();
- init_pair(1, COLOR_GREEN, COLOR_BLACK);
- }
- }
- fn border_hex_gen(rows: usize, cols: usize) -> Vec<u32> {
- // Build the hex values, printed alongside the text and garbage.
- // The vector will be of length rows * 2
- // TODO: this would make a nice iterator, or generator, once those are stable.
- let mut rng = rand::thread_rng();
- let mut hex = rng.gen_range(0,200) + 63744;
- let mut ls = Vec::with_capacity(rows * 2);
- for _ in 0..rows * 2 {
- ls.push(hex);
- hex += (cols / 2) as u32;
- }
- ls
- }
|