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() .fullscreen() .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(), ); textures.insert( "heart", texture_creator .load_texture_bytes(include_bytes!("../assets/heart.png")) .unwrap(), ); 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, _ => {} } } // Find the most-exact match to show 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)); } 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 { // Advance the line so we don't leak chars skip_chars = i; } else { break; } chars.next(); } let (_, tline) = line.split_at(skip_chars); line = String::from(tline); //println!("Show {show}"); //println!("Matches {:?}", matches); //println!("Line {line}"); 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 } 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 }