get basic tui set up

This commit is contained in:
markichnich 2023-08-14 23:08:37 +02:00
commit 22a9742102
4 changed files with 444 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

261
Cargo.lock generated Normal file
View File

@ -0,0 +1,261 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.4.0",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "mio"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "shdoku"
version = "0.1.0"
dependencies = [
"crossterm",
]
[[package]]
name = "signal-hook"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "shdoku"
description = "a basic tui-sudoku game"
version = "0.1.0"
edition = "2021"
authors = ["markichnich"]
license = "GPL-3.0-or-later"
keywords = ["sudoku", "tui", "game", "crossterm"]
categories = ["games", "mathematics", "science", "algorithms"]
[dependencies]
crossterm = "0.27.0"

170
src/main.rs Normal file
View File

@ -0,0 +1,170 @@
extern crate crossterm;
use crossterm::{
cursor::{MoveTo, SetCursorStyle},
event::{poll, read, Event::*, KeyCode::*},
execute, queue,
terminal::{disable_raw_mode, enable_raw_mode, size, Clear, ClearType::All},
};
use std::{
io::{self, stdout, Stdout, Write},
time::Duration,
};
fn main() -> io::Result<()> {
let (width, height) = size()?;
let (mut width, mut height) = (width as usize, height as usize);
let mut screen = vec![String::with_capacity(width); height];
let modifiable = [
[false, false, true, true, false, true, true, true, true],
[false, true, true, false, false, false, true, true, true],
[true, false, false, true, true, true, true, false, true],
[false, true, true, true, false, true, true, true, false],
[false, true, true, false, true, false, true, true, false],
[false, true, true, true, false, true, true, true, false],
[true, false, true, true, true, true, false, false, true],
[true, true, true, false, false, false, true, true, false],
[true, true, true, true, false, true, true, false, false],
];
let mut board = [
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9],
];
let mut cur_row = 0;
let mut cur_col = 0;
let mut stdout = stdout();
enable_raw_mode()?;
loop {
let (w, h) = size()?;
(width, height) = (w as usize, h as usize);
if poll(Duration::from_millis(250))? {
if let Ok(Key(k)) = read() {
match k.code {
Char('q') => break,
Char('h') => cur_col = (cur_col + 8) % 9,
Char('j') => cur_row = (cur_row + 1) % 9,
Char('k') => cur_row = (cur_row + 8) % 9,
Char('l') => cur_col = (cur_col + 1) % 9,
Char('H') => cur_col = (cur_col + 6) % 9,
Char('J') => cur_row = (cur_row + 3) % 9,
Char('K') => cur_row = (cur_row + 6) % 9,
Char('L') => cur_col = (cur_col + 3) % 9,
Char('x') => board[cur_row][cur_col] = 0,
Char(num) if ('1'..='9').contains(&num) => {
if modifiable[cur_row][cur_col] {
board[cur_row][cur_col] = num as u8 - b'0'
}
}
_ => {}
}
}
}
render_to_screen(&mut screen, width, height, board);
draw_screen(&mut stdout, &screen)?;
place_cursor(&mut stdout, cur_row, cur_col, width, height)?;
}
disable_raw_mode()?;
Ok(())
}
fn place_cursor(
stdout: &mut Stdout,
cur_row: usize,
cur_col: usize,
width: usize,
height: usize,
) -> io::Result<()> {
let (x, y) = ((width / 2 - 14) as u16, (height / 2 - 7) as u16);
let (x, y) = (x + 2, y + 1);
let (x, y) = (x + 2 * cur_col as u16, y + cur_row as u16);
let x = match cur_col {
0..=2 => x,
3..=5 => x + 3,
_ => x + 6,
};
let y = match cur_row {
0..=2 => y,
3..=5 => y + 1,
_ => y + 2,
};
execute!(stdout, MoveTo(x, y), SetCursorStyle::SteadyBlock)
}
fn draw_screen(stdout: &mut Stdout, screen: &[String]) -> io::Result<()> {
queue!(stdout, Clear(All))?;
let s: String = screen.join("\r\n");
write!(stdout, "{}", s)?;
stdout.flush()?;
Ok(())
}
fn render_to_screen(screen: &mut Vec<String>, cols: usize, rows: usize, board: [[u8; 9]; 9]) {
let mut lines = Vec::new();
lines.push("┌────────┬────────┬────────┐".to_string().chars().collect());
for (row, row_slice) in board.iter().enumerate() {
match row {
3 | 6 => {
lines.push("├────────┼────────┼────────┤".to_string().chars().collect());
}
_ => {}
}
let mut line = String::new();
for (col, cur_field) in row_slice.iter().enumerate() {
match col {
0 => {
line.push_str("");
}
3 | 6 => {
line.push_str("");
}
_ => {}
}
line.push(match cur_field {
0 => ' ',
n => (b'0' + n) as char,
});
line.push(' ');
}
line.push_str("");
lines.push(line);
}
lines.push("└────────┴────────┴────────┘".to_string().chars().collect());
let pad_hori = cols / 2 + lines[0].chars().count() / 2;
let pad_vert = rows - lines.len();
let pad_top = pad_vert / 2;
let pad_bot = pad_vert - pad_top;
let mut new_screen = Vec::new();
for _ in 0..pad_top {
new_screen.push(String::new());
}
for line in lines {
let padded = format!("{: >width$}", line, width = pad_hori);
new_screen.push(padded);
}
for _ in 0..pad_bot {
new_screen.push(String::new());
}
*screen = new_screen;
}