From f13c7d6eae7989d00540298cc77d8fd8d3488ec9 Mon Sep 17 00:00:00 2001 From: Tim Schubert Date: Sat, 28 Dec 2024 01:34:56 +0100 Subject: [PATCH] rename and refactor --- Cargo.lock | 18 ++--- Cargo.toml | 2 +- run.sh | 2 +- src/main.rs | 204 +++++++++++++++++++++++++++++++++------------------- 4 files changed, 141 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c8ecbb..0b0fa8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,15 @@ dependencies = [ "uguid", ] +[[package]] +name = "uefi-gol" +version = "0.1.0" +dependencies = [ + "heapless", + "log", + "uefi", +] + [[package]] name = "uefi-macros" version = "0.17.0" @@ -164,15 +173,6 @@ dependencies = [ "uguid", ] -[[package]] -name = "uefi-textadventure" -version = "0.1.0" -dependencies = [ - "heapless", - "log", - "uefi", -] - [[package]] name = "uguid" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index f23a761..f4eee96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "uefi-textadventure" +name = "uefi-gol" version = "0.1.0" edition = "2021" diff --git a/run.sh b/run.sh index 566dee0..84b5a87 100755 --- a/run.sh +++ b/run.sh @@ -5,7 +5,7 @@ set -e cargo build --target x86_64-unknown-uefi mkdir -p esp/efi/boot -cp target/x86_64-unknown-uefi/debug/uefi-textadventure.efi esp/efi/boot/bootx64.efi +cp target/x86_64-unknown-uefi/debug/uefi-gol.efi esp/efi/boot/bootx64.efi qemu-system-x86_64 -enable-kvm \ -drive if=pflash,format=raw,readonly=on,file=edk2-x86_64-code.fd \ -drive format=raw,file=fat:rw:esp diff --git a/src/main.rs b/src/main.rs index f956fd7..97c5cee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,95 +1,151 @@ #![no_main] #![no_std] -use core::{fmt::Write, iter::repeat}; +use core::{ + fmt::Write, + iter::repeat, + ops::{Deref, DerefMut}, +}; use heapless::{String, Vec}; -use log::info; use system::with_stdout; use uefi::prelude::*; +const WIDTH: usize = 30; +const HEIGHT: usize = 30; + +type Matrix = Vec, HEIGHT>; + +#[derive(Debug, Clone)] +struct Life { + matrix: Matrix, +} + +impl Deref for Life { + type Target = Matrix; + + fn deref(&self) -> &Self::Target { + &self.matrix + } +} + +impl Default for Life { + fn default() -> Self { + let mut matrix: Vec, HEIGHT> = Vec::default(); + for _ in 0..HEIGHT { + matrix.push(repeat(false).take(WIDTH).collect()).unwrap(); + } + Life { matrix } + } +} + +impl DerefMut for Life { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.matrix + } +} + +impl Life { + fn with_starter(starter: &[(usize, usize)]) -> Self { + let mut life = Self::default(); + for (i, j) in starter.iter() { + life[*i][*j] = true; + } + life + } + + fn play(self) -> Life { + const OFFSETS: &[(i64, i64)] = &[ + (-1, -1), + (-1, 0), + (-1, 1), + (0, -1), + (0, 1), + (1, -1), + (1, 0), + (1, 1), + ]; + let mut future = Life::default(); + self.iter().enumerate().for_each(|(row, line)| { + line.iter().enumerate().for_each(|(column, alive)| { + let neighbors = OFFSETS + .iter() + .filter(|offset| { + let neighbor = ((row as i64) + offset.0, (column as i64) + offset.1); + let i = neighbor.0; + let j = neighbor.1; + i >= 0 + && j >= 0 + && (i as usize) < HEIGHT + && (j as usize) < WIDTH + && self[i as usize][j as usize] + }) + .count(); + future[row][column] = + (*alive && (neighbors == 2 || neighbors == 3)) || (!*alive && neighbors == 3); + }) + }); + future + } + + /// Buffers output into one string per frame since println does not buffer output in uefi-rs. + fn render(&self) -> Frame { + let mut frame = Frame::default(); + for l in self.iter() { + for cell in l.iter() { + if *cell { + frame.push('X').unwrap() + } else { + frame.push(' ').unwrap() + } + } + frame.push('\n').unwrap() + } + frame + } +} + +type FrameBuffer = String<{ (WIDTH * HEIGHT) + HEIGHT }>; + +#[derive(Default)] +struct Frame { + buffer: FrameBuffer, +} + +impl Deref for Frame { + type Target = FrameBuffer; + + fn deref(&self) -> &Self::Target { + &self.buffer + } +} + +impl DerefMut for Frame { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer + } +} + +const BREEDER: &[(usize, usize)] = &[(15, 16), (16, 15), (16, 16), (17, 16), (17, 17)]; +const RENDER_DELAY: usize = 100_000; + #[entry] fn main() -> Status { uefi::helpers::init().unwrap(); - info!("Hello world!"); - const W: usize = 30; - const H: usize = 30; + let mut life = Life::with_starter(&BREEDER); - let mut life: Vec, H> = life(); - for (i, j) in [(15, 16), (16, 15), (16, 16), (17, 16), (17, 17)] { - life[i][j] = true; - } + for _ in repeat(()) { + life = life.play(); - for _i in 0..100_000 { - life = gol(life.clone()); - let mut out: String<{ (W * H) + H }> = String::default(); - for l in life.iter() { - for cell in l.iter() { - if *cell { - out.push('X').unwrap() - } else { - out.push(' ').unwrap() - } - } - out.push('\n').unwrap() - } + let frame = life.render(); with_stdout(|stdout| { stdout.reset(true).unwrap(); - stdout.write_str(&out).unwrap() + stdout.write_str(&frame).unwrap() }); - boot::stall(100_000); + // Stall the loop a bit so it is easier to watch + boot::stall(RENDER_DELAY); } - boot::stall(100_000_000); Status::SUCCESS } - -fn gol(cells: Vec, H>) -> Vec, H> { - let mut future = life(); - cells.iter().enumerate().for_each(|(row, line)| { - line.iter().enumerate().for_each(|(column, cell)| { - let neighbors = [ - (-1 as i64, -1), - (-1, 0), - (-1, 1 as i64), - (0, -1), - (0, 1), - (1, -1), - (1, 0), - (1, 1), - ] - .iter() - .filter_map(|offset| { - let neighbor = ( - (row as i64).checked_add(offset.0), - (column as i64).checked_add(offset.1), - ); - match neighbor { - (Some(r), Some(w)) - if r >= 0 - && w >= 0 - && (r as usize) < H - && (w as usize) < W - && cells[r as usize][w as usize] => - { - Some(()) - } - _ => None, - } - }) - .count(); - future[row][column] = - (*cell && (neighbors == 2 || neighbors == 3)) || (!*cell && neighbors == 3); - }) - }); - future -} - -fn life() -> Vec, H> { - let mut future: Vec, H> = Vec::default(); - for _ in 0..H { - future.push(repeat(false).take(W).collect()).unwrap(); - } - future -}