use actors::*; use clap::Clap; use cli::*; use game::{Action, Controllable, Game, Tickable}; use graphics::standard_renderer; use graphics::COLOR_BACKGROUND; use log::{debug, info, trace}; use rand::SeedableRng; use sdl2::event::Event; use sdl2::keyboard::Keycode; use std::time::Duration; use tokio::time::interval; mod actors; mod cli; mod game; mod graphics; mod playfield; mod random; mod srs; mod tetromino; const TICKS_PER_SECOND: usize = 60; #[tokio::main(core_threads = 16)] async fn main() -> Result<(), Box> { let opts = crate::cli::Opts::parse(); init_verbosity(&opts)?; let agent = match opts.subcmd { SubCommand::Play(_) => None, SubCommand::Train(sub_opts) => Some(match sub_opts.agent { Agent::QLearning => { qlearning::train_actor(qlearning::QLearningAgent::default(), &sub_opts) } Agent::ApproximateQLearning => { let agent = qlearning::train_actor(qlearning::ApproximateQLearning::default(), &sub_opts); agent.dbg(); agent } Agent::HeuristicGenetic => { let agent = genetic::train_actor(&sub_opts).await; agent.dbg(); agent } }), }; play_game(agent).await } async fn play_game(mut actor: Option>) -> Result<(), Box> { let mut rng = rand::rngs::SmallRng::from_entropy(); let sdl_context = sdl2::init()?; // let video_subsystem = sdl_context.video()?; // let window = video_subsystem // .window("retris", 800, 800) // .position_centered() // .build()?; // let mut canvas = window.into_canvas().build()?; let mut event_pump = sdl_context.event_pump()?; let mut interval = interval(Duration::from_millis(1000 / TICKS_PER_SECOND as u64)); 'escape: for _ in 0..10 { let mut game = Game::default(); loop { match game.is_game_over() { Some(e) => { println!("Lost due to: {:?}", e); break; } None => (), } let cur_state = game.clone(); // If there's an actor, the player action will get overridden. If not, // then then the player action falls through, if there is one. This is // to allow for restarting and quitting the game from the GUI. let mut action = None; for event in event_pump.poll_iter() { match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { debug!("Escape registered"); break 'escape; } Event::KeyDown { keycode: Some(Keycode::Left), .. } => { debug!("Move left registered"); action = Some(Action::MoveLeft); } Event::KeyDown { keycode: Some(Keycode::Right), .. } => { debug!("Move right registered"); action = Some(Action::MoveRight); } Event::KeyDown { keycode: Some(Keycode::Down), .. } => { debug!("Soft drop registered"); action = Some(Action::SoftDrop); } Event::KeyDown { keycode: Some(Keycode::Z), .. } => { debug!("Rotate left registered"); action = Some(Action::RotateLeft); } Event::KeyDown { keycode: Some(Keycode::X), .. } => { debug!("Rotate right registered"); action = Some(Action::RotateRight); } Event::KeyDown { keycode: Some(Keycode::Space), .. } | Event::KeyDown { keycode: Some(Keycode::Up), .. } => { debug!("Hard drop registered"); action = Some(Action::HardDrop); } Event::KeyDown { keycode: Some(Keycode::LShift), .. } => { debug!("Hold registered"); action = Some(Action::Hold); } Event::KeyDown { keycode: Some(Keycode::R), .. } => { info!("Restarting game"); game = Game::default(); } Event::KeyDown { keycode: Some(e), .. } => trace!("Ignoring keycode {}", e), _ => (), } } actor.as_mut().map(|actor| { action = Some(actor.get_action(&mut rng, &cur_state, &((&game).get_legal_actions()))); }); action.map(|action| match action { Action::Nothing => (), Action::MoveLeft => game.move_left(), Action::MoveRight => game.move_right(), Action::SoftDrop => game.move_down(), Action::HardDrop => game.hard_drop(), Action::Hold => game.hold(), Action::RotateLeft => game.rotate_left(), Action::RotateRight => game.rotate_right(), }); game.tick(); // canvas.set_draw_color(COLOR_BACKGROUND); // canvas.clear(); // standard_renderer::render(&mut canvas, &game); // canvas.present(); interval.tick().await; } info!("Final score: {}", game.score()); } Ok(()) }