diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/bot/src/algos/mod.rs | 1 | ||||
-rw-r--r-- | server/bot/src/algos/test.rs | 51 | ||||
-rw-r--r-- | server/bot/src/main.rs | 144 |
3 files changed, 77 insertions, 119 deletions
diff --git a/server/bot/src/algos/mod.rs b/server/bot/src/algos/mod.rs new file mode 100644 index 00000000..7b788c20 --- /dev/null +++ b/server/bot/src/algos/mod.rs @@ -0,0 +1 @@ +pub mod test; diff --git a/server/bot/src/algos/test.rs b/server/bot/src/algos/test.rs new file mode 100644 index 00000000..17999f5e --- /dev/null +++ b/server/bot/src/algos/test.rs @@ -0,0 +1,51 @@ +use crate::{ + pathfinding::{find_path, Path}, + BotAlgo, BotInput, +}; +use hurrycurry_client_lib::Game; +use hurrycurry_protocol::{glam::IVec2, ItemIndex, Message, PlayerID}; +use log::info; + +#[derive(Default)] +pub struct Test { + path: Option<Path>, +} + +impl BotAlgo for Test { + fn tick(&mut self, me: PlayerID, game: &Game, _dt: f32) -> BotInput { + let Some(player) = game.players.get(&me) else { + return BotInput::default(); + }; + let pos = player.movement.position; + + if let Some(path) = &mut self.path { + let direction = path.next_direction(pos); + return BotInput { + direction, + boost: false, + interact: None, + }; + } else { + if let Some((item, near)) = find_demand(game) { + info!("demand {item:?} near {near}"); + if let Some(path) = find_path(&game.walkable, pos.as_ivec2(), near) { + self.path = Some(path); + } + } + } + BotInput::default() + } +} + +fn find_demand(game: &Game) -> Option<(ItemIndex, IVec2)> { + game.players + .iter() + .find_map(|(_, pl)| match &pl.communicate_persist { + Some(Message::Item(item)) => { + let pos = pl.movement.position.as_ivec2(); + let t = pos; + Some((*item, t)) + } + _ => None, + }) +} diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs index 864141b0..00756fd7 100644 --- a/server/bot/src/main.rs +++ b/server/bot/src/main.rs @@ -16,18 +16,27 @@ */ #![feature(isqrt)] +pub mod algos; pub mod pathfinding; use anyhow::Result; use hurrycurry_client_lib::{network::sync::Network, Game}; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, - ItemIndex, Message, PacketC, PacketS, PlayerID, RecipeIndex, + PacketC, PacketS, PlayerID, }; -use log::{info, warn}; -use pathfinding::{find_path, Path}; use std::{thread::sleep, time::Duration}; +#[derive(Default, Clone, Copy)] +pub struct BotInput { + direction: Vec2, + boost: bool, + interact: Option<IVec2>, +} +pub trait BotAlgo { + fn tick(&mut self, me: PlayerID, game: &Game, dt: f32) -> BotInput; +} + fn main() -> Result<()> { env_logger::init_from_env("LOG"); let mut network = Network::connect("ws://127.0.0.1")?; @@ -48,14 +57,22 @@ fn main() -> Result<()> { while let Some(packet) = network.queue_in.pop_front() { match &packet { - PacketC::Joined { id } => bots.push(Bot::new(*id)), + PacketC::Joined { id } => bots.push(BotDriver { + id: *id, + interacting: false, + state: Box::new(algos::test::Test::default()), + }), _ => (), } game.apply_packet(packet); } for b in &mut bots { - let (dir, boost, interact) = b.tick(&game); + let BotInput { + direction, + boost, + interact, + } = b.state.tick(b.id, &game, dt); if interact.is_some() != b.interacting { b.interacting = interact.is_some(); network.queue_out.push_back(PacketS::Interact { @@ -65,7 +82,7 @@ fn main() -> Result<()> { } network.queue_out.push_back(PacketS::Movement { player: b.id, - dir, + dir: direction, boost, pos: None, }); @@ -75,119 +92,8 @@ fn main() -> Result<()> { } } -pub struct Bot { +pub struct BotDriver { pub interacting: bool, - id: PlayerID, - want: Option<ItemIndex>, - take: Option<IVec2>, - put: Option<IVec2>, - path: Option<Path>, -} - -impl Bot { - pub fn new(id: PlayerID) -> Self { - Self { - id, - want: None, - path: None, - take: None, - put: None, - interacting: false, - } - } - pub fn tick(&mut self, game: &Game) -> (Vec2, bool, Option<IVec2>) { - if let Some(player) = game.players.get(&self.id) { - let pos = player.movement.position; - - if let Some(path) = &mut self.path { - let dir = path.next_direction(pos); - if path.is_done() { - self.path = None; - } - return (dir, false, None); - } - if let Some(interact) = self.take.take() { - return (Vec2::ZERO, false, Some(interact)); - } - if let Some(item) = &player.item { - if Some(item.kind) == self.want { - if let Some(interact) = self.put.take() { - return (Vec2::ZERO, false, Some(interact)); - } - } - } - - if let Some(item) = self.want { - if let Some((path, target)) = find_item_on_map(game, pos.as_ivec2(), item) { - info!("target={target}"); - info!("path found"); - self.path = Some(path); - self.take = Some(target); - } else if let Some(recipe) = find_item_as_recipe_output(game, item) { - info!("recipe={recipe:?}"); - self.want = game.data.recipes[recipe.0].outputs().first().copied(); - info!("want={:?}", self.want) - } else { - warn!("stuck"); - } - } else { - if let Some((item, dest)) = select_demand(game) { - info!("want={item:?}"); - self.want = Some(item); - self.put = Some(dest); - } - } - } - (Vec2::ZERO, false, None) - } -} - -fn find_item_as_recipe_output(game: &Game, item: ItemIndex) -> Option<RecipeIndex> { - game.data - .recipes - .iter() - .enumerate() - .find(|(_, r)| r.inputs().contains(&item)) - .map(|r| RecipeIndex(r.0)) -} - -fn find_item_on_map(game: &Game, player: IVec2, item: ItemIndex) -> Option<(Path, IVec2)> { - game.tiles.iter().find_map(|(pos, tile)| { - if let Some(i) = &tile.item { - if i.kind == item { - for xo in -1..=1 { - for yo in -1..=1 { - let t = *pos + IVec2::new(xo, yo); - if let Some(path) = find_path(&game.walkable, player, t) { - return Some((path, *pos)); - } - } - } - } - } - None - }) -} - -fn select_demand(game: &Game) -> Option<(ItemIndex, IVec2)> { - game.players - .iter() - .find_map(|(_, pl)| match &pl.communicate_persist { - Some(Message::Item(item)) => { - let pos = pl.movement.position.as_ivec2(); - for xo in -1..=1 { - for yo in -1..=1 { - let t = pos + IVec2::new(xo, yo); - if let Some(tile) = game.tiles.get(&t) { - if game.data.tile_interact[tile.kind.0] { - return Some((*item, t)); - } - } - } - } - None - } - _ => None, - }) + state: Box<dyn BotAlgo>, } |