Working Version
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
117
Cargo.lock
generated
Normal file
117
Cargo.lock
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "game_of_life"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"sdl2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"sdl2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2-sys"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "game_of_life"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sdl2 = "0.35.2"
|
||||
rand = "0.8.5"
|
||||
251
src/main.rs
Normal file
251
src/main.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::event::Event;
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::keyboard::Scancode;
|
||||
use std::time::Duration;
|
||||
use sdl2::rect::Point;
|
||||
use sdl2::rect::Rect;
|
||||
use rand::Rng;
|
||||
|
||||
const WINDOW_WIDTH:i32 = 1280;
|
||||
const WINDOW_HEIGHT:i32 = 720;
|
||||
|
||||
const DEFAULT_MAP_WIDTH:i32 = WINDOW_WIDTH / 20;
|
||||
const DEFAULT_MAP_HEIGHT:i32 = WINDOW_HEIGHT / 20;
|
||||
const TILE_WIDTH:i32 = WINDOW_WIDTH / DEFAULT_MAP_WIDTH;
|
||||
const TILE_HEIGHT:i32 = WINDOW_HEIGHT / DEFAULT_MAP_HEIGHT;
|
||||
|
||||
const DEAD:i32 = 0;
|
||||
const ALIVE:i32 = 1;
|
||||
|
||||
pub struct Map{
|
||||
size:Point,
|
||||
grid:Vec<i32>,
|
||||
}
|
||||
impl Map{
|
||||
fn new() -> Self{
|
||||
let (width,height) = (DEFAULT_MAP_WIDTH,DEFAULT_MAP_HEIGHT);
|
||||
Map{
|
||||
size:Point::new(DEFAULT_MAP_WIDTH,DEFAULT_MAP_HEIGHT),
|
||||
grid:vec![0;(width*height) as usize],
|
||||
}
|
||||
}
|
||||
fn randomize(&mut self){
|
||||
let mut rng = rand::thread_rng();
|
||||
for x in 0..self.size.x{
|
||||
for y in 0..self.size.y{
|
||||
let index = x + self.size.x * y;
|
||||
let rnd:i32 = rng.gen_range(0..2);
|
||||
self.grid[index as usize] = rnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn render(&mut self,ctx:&mut sdl2::render::Canvas<sdl2::video::Window>,debug:bool){
|
||||
for x in 0..self.size.x{
|
||||
for y in 0..self.size.y{
|
||||
let rect = Rect::new(x * TILE_WIDTH,y * TILE_HEIGHT,TILE_WIDTH as u32,TILE_HEIGHT as u32);
|
||||
let index = x + self.size.x * y;
|
||||
let debug_color:Color = Color::RGB(0xFF, 0x00, 0x00);
|
||||
let tile_bg:Color;
|
||||
|
||||
match self.grid[index as usize]{
|
||||
DEAD => {
|
||||
tile_bg = Color::RGB(0xFF,0xFF,0xFF);
|
||||
}
|
||||
ALIVE =>{
|
||||
tile_bg = Color::RGB(0x00, 0x00, 0x00);
|
||||
}
|
||||
_ => {
|
||||
tile_bg = Color::RGB(0xd1, 0x00, 0xd1);
|
||||
},
|
||||
}
|
||||
ctx.set_draw_color(tile_bg);
|
||||
ctx.fill_rect(rect).expect("Could not render grid");
|
||||
if debug{
|
||||
ctx.set_draw_color(debug_color);
|
||||
ctx.draw_rect(rect).expect("Could not render debug grid");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct Game{
|
||||
draw_debug:bool,
|
||||
started:bool,
|
||||
map:Map,
|
||||
}
|
||||
impl Game{
|
||||
pub fn render(&mut self,ctx:&mut sdl2::render::Canvas<sdl2::video::Window>){
|
||||
let background_color:Color = Color::RGB(0xFF,0xFF,0xFF);
|
||||
ctx.set_draw_color(background_color);
|
||||
ctx.clear();
|
||||
//map
|
||||
self.map.render(ctx,self.draw_debug);
|
||||
}
|
||||
pub fn toggle_debug(&mut self){
|
||||
self.draw_debug = !self.draw_debug;
|
||||
}
|
||||
pub fn place_new_cell(&mut self,mouse_position:Point){
|
||||
let two_d_index = Point::new(mouse_position.x / TILE_WIDTH,mouse_position.y / TILE_HEIGHT);
|
||||
let one_d_index = two_d_index.y * DEFAULT_MAP_WIDTH + two_d_index.x;
|
||||
self.map.grid[one_d_index as usize] = 1;
|
||||
}
|
||||
pub fn update(&mut self){
|
||||
//to copy and not own
|
||||
let mut grid_2 = self.map.grid.to_vec();
|
||||
if self.started{
|
||||
let mut neighbour_count = 0;
|
||||
let array_size = DEFAULT_MAP_HEIGHT*DEFAULT_MAP_WIDTH;
|
||||
let mut two_d_index:Point;
|
||||
let mut one_d_index:i32;
|
||||
let mut neighbours:Vec<Point>;
|
||||
for index in 0..array_size{
|
||||
two_d_index = Point::new(index % DEFAULT_MAP_WIDTH,index / DEFAULT_MAP_WIDTH);
|
||||
let cell_state = self.map.grid[index as usize];
|
||||
neighbours = Vec::new();
|
||||
//Checks if the cell is in a border
|
||||
if two_d_index.x > 0 && two_d_index.x < DEFAULT_MAP_WIDTH-1 && two_d_index.y > 0 && two_d_index.y < DEFAULT_MAP_HEIGHT-1{
|
||||
//its not on the edge
|
||||
neighbours.push(Point::new(two_d_index.x -1,two_d_index.y -1));
|
||||
neighbours.push(Point::new(two_d_index.x,two_d_index.y -1));
|
||||
neighbours.push(Point::new(two_d_index.x + 1,two_d_index.y -1));
|
||||
|
||||
neighbours.push(Point::new(two_d_index.x -1,two_d_index.y));
|
||||
neighbours.push(Point::new(two_d_index.x + 1,two_d_index.y));
|
||||
|
||||
neighbours.push(Point::new(two_d_index.x -1,two_d_index.y +1));
|
||||
neighbours.push(Point::new(two_d_index.x,two_d_index.y +1));
|
||||
neighbours.push(Point::new(two_d_index.x + 1,two_d_index.y +1));
|
||||
|
||||
neighbour_count = 0;
|
||||
for friend in neighbours.iter(){
|
||||
one_d_index = friend.y * DEFAULT_MAP_WIDTH + friend.x;
|
||||
if self.map.grid[one_d_index as usize] == 1{
|
||||
neighbour_count +=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Rules Source wikipedia
|
||||
if cell_state == ALIVE{
|
||||
// 1 Any live cell with fewer than two live neighbours dies, as if by underpopulation.
|
||||
if neighbour_count < 2{
|
||||
grid_2[index as usize] = DEAD;
|
||||
}
|
||||
// 2 Any live cell with two or three live neighbours lives on to the next generation.
|
||||
// 3 Any live cell with more than three live neighbours dies, as if by overpopulation.
|
||||
if neighbour_count > 3{
|
||||
grid_2[index as usize] = DEAD;
|
||||
}
|
||||
}else {
|
||||
// 4 Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
|
||||
if neighbour_count == 3{
|
||||
grid_2[index as usize] = ALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
self.map.grid = grid_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
//https://stackoverflow.com/questions/65723827/sdl2-function-to-draw-a-filled-circle ## Translated to Rust
|
||||
fn is_random_pressed(e: &sdl2::EventPump)-> bool{
|
||||
e.keyboard_state().is_scancode_pressed(Scancode::R)
|
||||
}
|
||||
fn is_tab_pressed(e: &sdl2::EventPump)-> bool{
|
||||
e.keyboard_state().is_scancode_pressed(Scancode::Tab)
|
||||
}
|
||||
fn is_space_pressed(e: &sdl2::EventPump)-> bool{
|
||||
e.keyboard_state().is_scancode_pressed(Scancode::Space)
|
||||
}
|
||||
fn check_mouse_left_pressed(e: &sdl2::EventPump) -> Point{
|
||||
if e.mouse_state().left(){
|
||||
return Point::new(e.mouse_state().x(),e.mouse_state().y());
|
||||
}else{
|
||||
return Point::new(-1,-1);
|
||||
}
|
||||
}
|
||||
fn check_mouse_right_pressed(e: &sdl2::EventPump) -> Point{
|
||||
if e.mouse_state().right(){
|
||||
return Point::new(e.mouse_state().x(),e.mouse_state().y());
|
||||
}else{
|
||||
return Point::new(-1,-1);
|
||||
}
|
||||
}
|
||||
pub fn main_loop(canvas: &mut sdl2::render::Canvas<sdl2::video::Window>,event_pump:&mut sdl2::EventPump,game:&mut Game){
|
||||
//let (mut up_state,mut down_state,mut left_state,mut right_state) = (false,false,false,false);
|
||||
let mut tab_state = false;
|
||||
let mut quit = false;
|
||||
let mut space_state = false;
|
||||
loop{
|
||||
if is_random_pressed(event_pump){
|
||||
game.map.randomize();
|
||||
}
|
||||
if is_space_pressed(event_pump){
|
||||
if space_state == false{
|
||||
//KeyDown
|
||||
space_state = true;
|
||||
game.started = !game.started;
|
||||
}else{
|
||||
//KeyUp
|
||||
space_state = false;
|
||||
}
|
||||
}
|
||||
if is_tab_pressed(event_pump){
|
||||
if tab_state == false{
|
||||
//Keydown
|
||||
tab_state = true;
|
||||
game.toggle_debug();
|
||||
}
|
||||
}else{
|
||||
if tab_state == true{
|
||||
//keyUp
|
||||
tab_state = false
|
||||
}
|
||||
}
|
||||
let mouse_position = check_mouse_left_pressed(event_pump);
|
||||
if mouse_position.x >= 0 && mouse_position.y >= 0{
|
||||
game.place_new_cell(mouse_position);
|
||||
}
|
||||
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
Event::Quit {..} |
|
||||
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
||||
quit = true;
|
||||
break
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// MAIN LOOP
|
||||
game.update();
|
||||
game.render(canvas);
|
||||
// MAIN LOOP
|
||||
|
||||
canvas.present();
|
||||
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
||||
|
||||
if quit{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
|
||||
let window = video_subsystem.window("Game Of Life", WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32)
|
||||
.position_centered()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut canvas = window.into_canvas().build().unwrap();
|
||||
let mut event_pump = sdl_context.event_pump().unwrap();
|
||||
|
||||
canvas.set_draw_color(Color::RGB(0x6D, 0x6D, 0x64));
|
||||
let mut game = Game{started:false,draw_debug:false,map:Map::new()};
|
||||
main_loop(&mut canvas,&mut event_pump,&mut game);
|
||||
}
|
||||
Reference in New Issue
Block a user