before removing side effects
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+102
@@ -0,0 +1,102 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "antf"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ncurses",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.83"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.151"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ncurses"
|
||||||
|
version = "5.101.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e2c5d34d72657dc4b638a1c25d40aae81e4f1c699062f72f467237920752032"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
|
[[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.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "antf"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ncurses = "5.101.0"
|
||||||
|
rand = "0.8.5"
|
||||||
+300
@@ -0,0 +1,300 @@
|
|||||||
|
extern crate ncurses;
|
||||||
|
|
||||||
|
use ncurses::*;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Clone, Debug, Copy)]
|
||||||
|
struct Point(i32, i32);
|
||||||
|
|
||||||
|
struct Board {
|
||||||
|
center: Point,
|
||||||
|
max_x: i32,
|
||||||
|
max_y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_neighbors(pos: &Point) -> Vec<Point> {
|
||||||
|
vec![
|
||||||
|
Point(pos.0, pos.1 + 1),
|
||||||
|
Point(pos.0, pos.1 - 1),
|
||||||
|
Point(pos.0 - 1, pos.1),
|
||||||
|
Point(pos.0 + 1, pos.1),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
fn new(max_x: i32, max_y: i32) -> Board {
|
||||||
|
Board {
|
||||||
|
center: Point(max_x / 2, max_y / 2),
|
||||||
|
max_x,
|
||||||
|
max_y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_in_bounds(&self, pos: &Point) -> bool {
|
||||||
|
(pos.0 > -self.max_x && pos.0 < self.max_x) && (pos.1 > -self.max_y && pos.1 < self.max_y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_valid_movements(&self, pos: &Point) -> Vec<Point> {
|
||||||
|
let binding = get_neighbors(pos);
|
||||||
|
binding
|
||||||
|
.iter()
|
||||||
|
.filter(|e| self.is_in_bounds(e))
|
||||||
|
.map(|e| e.clone())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct World {
|
||||||
|
cleared: HashSet<Point>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl World {
|
||||||
|
fn new() -> World {
|
||||||
|
World {
|
||||||
|
cleared: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self, pos: Point) {
|
||||||
|
self.cleared.insert(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Colony {
|
||||||
|
ants: Vec<Box<dyn AI>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Colony {
|
||||||
|
fn new() -> Colony {
|
||||||
|
Colony { ants: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_ant(&mut self, x: i32, y: i32) {
|
||||||
|
self.ants.push(Box::new(Ant::new(x, y)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_entity<T: AI + 'static>(&mut self, e: T) {
|
||||||
|
self.ants.push(Box::new(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AI {
|
||||||
|
fn step(&mut self, b: &Board, w: &World) -> BoardCommand;
|
||||||
|
fn get_position(&self) -> Point;
|
||||||
|
fn set_position(&mut self, p: Point);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Ant {
|
||||||
|
pos: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ant {
|
||||||
|
fn new(x: i32, y: i32) -> Ant {
|
||||||
|
Ant { pos: Point(x, y) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Queen {
|
||||||
|
pos: Point,
|
||||||
|
egg_count: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Queen {
|
||||||
|
fn new(x: i32, y: i32) -> Queen {
|
||||||
|
Queen {
|
||||||
|
pos: Point(x, y),
|
||||||
|
egg_count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Egg {
|
||||||
|
pos: Point,
|
||||||
|
counter: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Egg {
|
||||||
|
fn new(x: i32, y: i32) -> Egg {
|
||||||
|
Egg {
|
||||||
|
pos: Point(x, y),
|
||||||
|
counter: 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AI for Egg {
|
||||||
|
fn step(&mut self, b: &Board, w: &World) -> BoardCommand {
|
||||||
|
if self.counter > 0 {
|
||||||
|
self.counter -= 1;
|
||||||
|
return BoardCommand::Noop;
|
||||||
|
} else {
|
||||||
|
BoardCommand::Hatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_position(&self) -> Point {
|
||||||
|
self.pos.clone()
|
||||||
|
}
|
||||||
|
fn set_position(&mut self, p: Point) {
|
||||||
|
self.pos = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BoardCommand<'a> {
|
||||||
|
Move(Box<&'a mut dyn AI>, Point),
|
||||||
|
Dig(Point),
|
||||||
|
LayEgg(Point),
|
||||||
|
Hatch,
|
||||||
|
Noop,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AI for Ant {
|
||||||
|
// return the next move for this ant
|
||||||
|
fn step(&mut self, b: &Board, w: &World) -> BoardCommand {
|
||||||
|
let valid = b.get_valid_movements(&self.pos);
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let choice = valid.choose(&mut rng).cloned();
|
||||||
|
|
||||||
|
if choice.is_none() {
|
||||||
|
return BoardCommand::Noop;
|
||||||
|
} else {
|
||||||
|
let pos = choice.unwrap();
|
||||||
|
if w.cleared.contains(&pos) {
|
||||||
|
return BoardCommand::Move(Box::new(self), pos);
|
||||||
|
} else {
|
||||||
|
return BoardCommand::Dig(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> Point {
|
||||||
|
self.pos.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_position(&mut self, p: Point) {
|
||||||
|
self.pos = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AI for Queen {
|
||||||
|
fn step(&mut self, b: &Board, w: &World) -> BoardCommand {
|
||||||
|
let valid = b.get_valid_movements(&self.pos);
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let choice = valid.choose(&mut rng).cloned();
|
||||||
|
|
||||||
|
if choice.is_none() {
|
||||||
|
return BoardCommand::Noop;
|
||||||
|
} else {
|
||||||
|
let pos = choice.unwrap();
|
||||||
|
if w.cleared.contains(&pos) {
|
||||||
|
// choose between laying an egg and moving
|
||||||
|
if self.egg_count < 3 {
|
||||||
|
self.egg_count -= 1;
|
||||||
|
return BoardCommand::LayEgg(pos);
|
||||||
|
} else {
|
||||||
|
return BoardCommand::Move(Box::new(self), pos);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return BoardCommand::Noop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> Point {
|
||||||
|
self.pos.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_position(&mut self, p: Point) {
|
||||||
|
self.pos = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(c: &Colony, w: &World, b: &Board) {
|
||||||
|
for c in w.cleared.iter() {
|
||||||
|
mvprintw(c.1 + b.center.1, c.0 + b.center.0, "x");
|
||||||
|
}
|
||||||
|
|
||||||
|
for a in c.ants.iter() {
|
||||||
|
let pos = a.get_position();
|
||||||
|
mvprintw(pos.1 + b.center.1, pos.0 + b.center.0, "o");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// TODO: tests, cleanup code in general
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn board() {
|
||||||
|
let max_x = 20;
|
||||||
|
let max_y = 20;
|
||||||
|
|
||||||
|
let mut board = Board::new(max_x, max_y);
|
||||||
|
let mut world = World::new();
|
||||||
|
|
||||||
|
dbg!(board.is_in_bounds(&Point(0, 0)));
|
||||||
|
dbg!(board.get_valid_movements(&Point(0, 0)));
|
||||||
|
|
||||||
|
let mut ant = Ant { pos: Point(0, 0) };
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::iter::zip;
|
||||||
|
|
||||||
|
fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) {
|
||||||
|
let world = w.clone();
|
||||||
|
let cmds: Vec<BoardCommand> = c.ants.iter_mut().map(|a| a.step(b, &world)).collect();
|
||||||
|
|
||||||
|
for cmd in cmds {
|
||||||
|
match cmd {
|
||||||
|
BoardCommand::Move(a, pos) => {
|
||||||
|
a.set_position(pos);
|
||||||
|
}
|
||||||
|
BoardCommand::Dig(pos) => {
|
||||||
|
w.clear(pos);
|
||||||
|
}
|
||||||
|
BoardCommand::LayEgg(pos) => {
|
||||||
|
//c.add_entity(Egg::new(pos.0, pos.1));
|
||||||
|
}
|
||||||
|
BoardCommand::Hatch => {}
|
||||||
|
BoardCommand::Noop => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
initscr();
|
||||||
|
|
||||||
|
/* Invisible cursor. */
|
||||||
|
curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
|
||||||
|
|
||||||
|
let mut max_x = 0;
|
||||||
|
let mut max_y = 0;
|
||||||
|
|
||||||
|
getmaxyx(stdscr(), &mut max_y, &mut max_x);
|
||||||
|
|
||||||
|
// might move all of contents of board into world
|
||||||
|
|
||||||
|
let mut board = Board::new(max_x, max_y);
|
||||||
|
let mut world = World::new();
|
||||||
|
let mut colony = Colony::new();
|
||||||
|
|
||||||
|
colony.add_ant(0,0);
|
||||||
|
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// TODO: add way to break out of the loop by hitting a random key
|
||||||
|
simulate(&mut colony, &mut world, &mut board);
|
||||||
|
render(&colony, &world, &board);
|
||||||
|
sleep(time::Duration::from_millis(100));
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
endwin();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user