2024-12-21 00:38:36 -08:00
|
|
|
extern crate sdl2;
|
|
|
|
|
|
|
|
|
|
use sdl2::event::Event;
|
|
|
|
|
use sdl2::image::{InitFlag, LoadTexture};
|
|
|
|
|
use sdl2::keyboard::Keycode;
|
|
|
|
|
use sdl2::pixels::Color;
|
|
|
|
|
use sdl2::render::Texture;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
|
|
pub fn main() -> Result<(), String> {
|
|
|
|
|
let sdl_context = sdl2::init()?;
|
|
|
|
|
let video_subsystem = sdl_context.video()?;
|
|
|
|
|
let _image = sdl2::image::init(InitFlag::PNG);
|
|
|
|
|
|
|
|
|
|
let window = video_subsystem
|
|
|
|
|
.window("rust-sdl2 demo: Video", 1024, 600)
|
|
|
|
|
.position_centered()
|
|
|
|
|
.opengl()
|
2025-03-23 19:04:35 -07:00
|
|
|
.fullscreen()
|
2024-12-21 00:38:36 -08:00
|
|
|
.build()
|
|
|
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
|
|
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
|
|
|
|
|
|
|
|
|
|
let texture_creator = canvas.texture_creator();
|
|
|
|
|
|
|
|
|
|
let mut textures: HashMap<&str, Texture> = HashMap::default();
|
|
|
|
|
textures.insert(
|
|
|
|
|
"a",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/a.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"b",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/b.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"c",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/c.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"d",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/d.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"e",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/e.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"f",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/f.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"g",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/g.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"h",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/h.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"i",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/i.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"j",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/j.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"k",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/k.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"l",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/l.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"m",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/m.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"n",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/n.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"o",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/o.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"p",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/p.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"q",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/q.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"r",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/r.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"s",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/s.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"t",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/t.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"u",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/u.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"v",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/v.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"w",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/w.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"x",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/x.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"y",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/y.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"z",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/z.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Special words
|
|
|
|
|
textures.insert(
|
|
|
|
|
"cat",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/cat.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
|
|
|
|
textures.insert(
|
|
|
|
|
"dog",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/dog.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
2025-03-23 19:04:35 -07:00
|
|
|
textures.insert(
|
|
|
|
|
"heart",
|
|
|
|
|
texture_creator
|
|
|
|
|
.load_texture_bytes(include_bytes!("../assets/heart.png"))
|
|
|
|
|
.unwrap(),
|
|
|
|
|
);
|
2024-12-21 00:38:36 -08:00
|
|
|
|
|
|
|
|
let opts: Vec<&str> = textures.keys().map(|s| *s).collect();
|
|
|
|
|
|
|
|
|
|
canvas.set_draw_color(Color::RGB(255, 0, 0));
|
|
|
|
|
canvas.clear();
|
|
|
|
|
canvas.present();
|
|
|
|
|
let mut event_pump = sdl_context.event_pump()?;
|
|
|
|
|
|
|
|
|
|
let mut line = String::new();
|
|
|
|
|
|
|
|
|
|
'running: loop {
|
|
|
|
|
for event in event_pump.poll_iter() {
|
|
|
|
|
match event {
|
|
|
|
|
Event::KeyDown {
|
|
|
|
|
keycode: Some(kc), ..
|
|
|
|
|
} => {
|
|
|
|
|
line.extend(
|
|
|
|
|
match kc {
|
|
|
|
|
Keycode::A => "a",
|
|
|
|
|
Keycode::B => "b",
|
|
|
|
|
Keycode::C => "c",
|
|
|
|
|
Keycode::D => "d",
|
|
|
|
|
Keycode::E => "e",
|
|
|
|
|
Keycode::F => "f",
|
|
|
|
|
Keycode::G => "g",
|
|
|
|
|
Keycode::H => "h",
|
|
|
|
|
Keycode::I => "i",
|
|
|
|
|
Keycode::J => "j",
|
|
|
|
|
Keycode::K => "k",
|
|
|
|
|
Keycode::L => "l",
|
|
|
|
|
Keycode::M => "m",
|
|
|
|
|
Keycode::N => "n",
|
|
|
|
|
Keycode::O => "o",
|
|
|
|
|
Keycode::P => "p",
|
|
|
|
|
Keycode::Q => "q",
|
|
|
|
|
Keycode::R => "r",
|
|
|
|
|
Keycode::S => "s",
|
|
|
|
|
Keycode::T => "t",
|
|
|
|
|
Keycode::U => "u",
|
|
|
|
|
Keycode::V => "v",
|
|
|
|
|
Keycode::W => "w",
|
|
|
|
|
Keycode::X => "x",
|
|
|
|
|
Keycode::Y => "y",
|
|
|
|
|
Keycode::Z => "z",
|
|
|
|
|
|
|
|
|
|
Keycode::Escape => break 'running,
|
|
|
|
|
_ => "",
|
|
|
|
|
}
|
|
|
|
|
.chars(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
Event::Quit { .. } => break 'running,
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-23 19:04:35 -07:00
|
|
|
// Find the most-exact match to show
|
2024-12-21 00:38:36 -08:00
|
|
|
let mut matches = vec![];
|
|
|
|
|
let mut chars = line.chars();
|
|
|
|
|
for i in 0..line.len() {
|
|
|
|
|
let part_line = find_matches(chars.as_str(), &opts);
|
|
|
|
|
for part in part_line {
|
|
|
|
|
matches.push((i, part));
|
|
|
|
|
}
|
2025-03-23 19:04:35 -07:00
|
|
|
chars.next();
|
|
|
|
|
}
|
|
|
|
|
let matches: Vec<&str> = matches.into_iter().map(|(_, s)| s).collect();
|
|
|
|
|
let show = if matches.len() > 0 { matches[0] } else { "" };
|
|
|
|
|
|
|
|
|
|
// Discard extra characters from line; find any lines that could match
|
|
|
|
|
// and discard up to there
|
|
|
|
|
let mut skip_chars = 0;
|
|
|
|
|
let mut chars = line.chars();
|
|
|
|
|
for i in 0..line.len() {
|
|
|
|
|
let part_line = find_could_match(chars.as_str(), &opts);
|
|
|
|
|
if part_line.len() == 0 {
|
2024-12-21 00:38:36 -08:00
|
|
|
// Advance the line so we don't leak chars
|
|
|
|
|
skip_chars = i;
|
2025-03-23 19:04:35 -07:00
|
|
|
} else {
|
|
|
|
|
break;
|
2024-12-21 00:38:36 -08:00
|
|
|
}
|
|
|
|
|
chars.next();
|
|
|
|
|
}
|
|
|
|
|
let (_, tline) = line.split_at(skip_chars);
|
|
|
|
|
line = String::from(tline);
|
|
|
|
|
|
2025-03-23 19:04:35 -07:00
|
|
|
|
|
|
|
|
//println!("Show {show}");
|
|
|
|
|
//println!("Matches {:?}", matches);
|
|
|
|
|
//println!("Line {line}");
|
|
|
|
|
|
2024-12-21 00:38:36 -08:00
|
|
|
canvas.clear();
|
|
|
|
|
if let Some(tex) = textures.get(show) {
|
|
|
|
|
canvas.copy(tex, None, None).unwrap();
|
|
|
|
|
}
|
|
|
|
|
canvas.present();
|
|
|
|
|
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
|
|
|
|
|
// The rest of the game loop goes here...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_matches<'a, 'b>(word: &'b str, opts: &'a [&'a str]) -> Vec<&'a str> {
|
|
|
|
|
if word.len() == 0 {
|
|
|
|
|
return vec![];
|
|
|
|
|
}
|
|
|
|
|
let mut ret = vec![];
|
|
|
|
|
for opt in opts {
|
|
|
|
|
if &word == opt {
|
|
|
|
|
ret.push(*opt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ret
|
2024-12-20 19:39:28 -08:00
|
|
|
}
|
2025-03-23 19:04:35 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
fn find_could_match<'a, 'b>(word: &'b str, opts: &'a [&'a str]) -> Vec<&'a str> {
|
|
|
|
|
if word.len() == 0 {
|
|
|
|
|
return vec![];
|
|
|
|
|
}
|
|
|
|
|
let mut ret = vec![];
|
|
|
|
|
for opt in opts {
|
|
|
|
|
if opt.starts_with(word) {
|
|
|
|
|
ret.push(*opt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ret
|
|
|
|
|
}
|