pneuma/src/main.rs

165 lines
4.2 KiB
Rust
Raw Normal View History

2019-12-17 23:58:57 +00:00
#![feature(proc_macro_hygiene, decl_macro)]
2020-02-14 15:22:31 +00:00
#[macro_use]
extern crate rocket;
2019-12-17 23:58:57 +00:00
2019-12-18 02:39:20 +00:00
use rocket::State;
2019-12-17 23:58:57 +00:00
use rocket_contrib::json::Json;
2019-12-18 02:39:20 +00:00
use std::collections::HashMap;
2020-02-14 15:22:31 +00:00
use std::sync::Mutex;
2019-12-17 23:58:57 +00:00
mod battlesnake;
2019-12-18 03:20:09 +00:00
type Cache = Mutex<HashMap<String, GameState>>;
#[derive(Debug, Clone)]
2019-12-18 02:39:20 +00:00
pub struct GameState {
path: Option<Vec<battlesnake::Coord>>,
target: battlesnake::Coord,
}
2019-12-17 23:58:57 +00:00
#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}
#[get("/ping")]
fn ping() -> &'static str {
"OK - Pneuma online"
}
2019-12-18 13:00:44 +00:00
#[post("/start", format = "json", data = "<msg>")]
2020-02-14 15:22:31 +00:00
fn start(
cache: State<Cache>,
msg: Json<battlesnake::SnakeRequest>,
) -> Json<battlesnake::StartResponse> {
2019-12-18 02:39:20 +00:00
let head = msg.you.body[0];
let target = find_target(&msg);
let path = find_path(&msg, &head, &target);
2020-02-14 15:22:31 +00:00
let gs = GameState {
2019-12-18 02:39:20 +00:00
target: *target,
path: path,
};
2019-12-18 12:39:47 +00:00
cache
.lock()
.expect("wanted to lock cache")
.insert(msg.game.id.clone(), gs);
2019-12-18 02:39:20 +00:00
2020-02-14 15:22:31 +00:00
Json(battlesnake::StartResponse {
2019-12-17 23:58:57 +00:00
color: "#5ce8c3".to_string(),
head_type: "beluga".to_string(),
tail_type: "skinny".to_string(),
})
}
2019-12-18 03:20:09 +00:00
fn find_path(
msg: &battlesnake::SnakeRequest,
head: &battlesnake::Coord,
2020-02-14 15:22:31 +00:00
target: &battlesnake::Coord,
2019-12-18 03:20:09 +00:00
) -> Option<Vec<battlesnake::Coord>> {
2019-12-18 02:39:20 +00:00
let path = pathfinding::directed::astar::astar(
head,
|n| msg.board.safe_neighbors(n).into_iter(),
|n| (battlesnake::manhattan(n, &target) as usize),
|n| n == target,
);
match path {
None => return None,
Some(x) => {
2020-02-15 13:14:21 +00:00
return Some(x.0.iter().rev().cloned().collect());
2020-02-14 15:22:31 +00:00
}
2019-12-18 02:39:20 +00:00
}
}
2019-12-18 12:39:47 +00:00
#[post("/end", format = "json", data = "<msg>")]
2020-02-14 15:22:31 +00:00
fn end(cache_state: State<Cache>, msg: Json<battlesnake::SnakeRequest>) -> String {
2019-12-18 12:39:47 +00:00
cache_state
.lock()
.expect("wanted cache to be lockable")
.remove(&msg.game.id);
"OK".to_string()
}
2019-12-17 23:58:57 +00:00
#[post("/move", format = "json", data = "<msg>")]
2019-12-18 05:07:13 +00:00
fn make_move(
cache_state: State<Cache>,
msg: Json<battlesnake::SnakeRequest>,
) -> Json<battlesnake::MoveResponse> {
2019-12-18 03:20:09 +00:00
let head = msg.you.body[0];
2019-12-18 05:01:43 +00:00
let mut cache = cache_state.lock().expect("wanted cache to be unlockable");
let gs = cache.get_mut(&msg.game.id).unwrap();
if gs.path.is_none() {
2019-12-18 13:47:51 +00:00
println!("recalculating path");
2019-12-18 05:01:43 +00:00
gs.target = *find_target(&msg);
gs.path = find_path(&msg, &head, &gs.target);
2019-12-18 01:37:11 +00:00
}
2019-12-17 23:58:57 +00:00
2019-12-18 05:01:43 +00:00
match gs.path.as_mut().unwrap().pop() {
None => {
gs.path = None;
2019-12-18 13:00:44 +00:00
let target = msg.board.safe_neighbors(&head)[0].0;
2020-02-14 15:22:31 +00:00
let next_move = battlesnake::Line {
2019-12-18 13:47:51 +00:00
start: &head,
end: &target,
}
.direction()
.to_string();
println!("moving to {}, target: {:?}", next_move, target);
2019-12-18 05:01:43 +00:00
Json(battlesnake::MoveResponse {
2019-12-18 13:47:51 +00:00
move_field: next_move,
2019-12-18 05:01:43 +00:00
})
2019-12-18 05:07:13 +00:00
}
2019-12-18 13:47:51 +00:00
Some(next) => {
let next_move = battlesnake::Line {
2019-12-18 05:07:13 +00:00
start: &head,
end: &next,
2020-02-14 15:22:31 +00:00
}
.direction()
.to_string();
println!(
"moving to {} {:?}, target: {:?}",
next_move, next, gs.target
);
2019-12-18 13:47:51 +00:00
Json(battlesnake::MoveResponse {
move_field: next_move,
})
2020-02-14 15:22:31 +00:00
}
2019-12-18 05:01:43 +00:00
}
2019-12-17 23:58:57 +00:00
}
2019-12-18 01:37:11 +00:00
fn find_target<'a>(gs: &'a battlesnake::SnakeRequest) -> &'a battlesnake::Coord {
2019-12-18 00:29:00 +00:00
let head = &gs.you.body[0];
2020-02-14 15:22:31 +00:00
if gs.you.health > 30 {
2019-12-18 01:37:11 +00:00
let mut lowest_score: u32 = 99999;
2019-12-18 00:29:00 +00:00
let mut coord: &battlesnake::Coord = &gs.you.body.last().unwrap();
2019-12-17 23:58:57 +00:00
for food in &gs.board.food {
2019-12-18 01:37:11 +00:00
let score = battlesnake::manhattan(&head, &food);
if score < lowest_score {
lowest_score = score;
2019-12-17 23:58:57 +00:00
coord = food;
}
}
return coord;
2020-02-14 15:22:31 +00:00
}
2019-12-17 23:58:57 +00:00
2020-02-14 15:22:31 +00:00
return gs.you.body.last().unwrap();
2019-12-17 23:58:57 +00:00
}
fn main() {
2019-12-18 02:39:20 +00:00
let map = HashMap::<String, GameState>::new();
let mutex_map = Mutex::from(map);
2020-02-15 13:14:21 +00:00
let prometheus = rocket_prometheus::PrometheusMetrics::new();
2020-02-14 15:22:31 +00:00
rocket::ignite()
2020-02-15 13:14:21 +00:00
.attach(prometheus.clone())
.mount("/metrics", prometheus)
2020-02-14 15:22:31 +00:00
.mount("/", routes![index, start, ping, make_move, end,])
2019-12-18 03:20:09 +00:00
.manage(mutex_map)
2019-12-18 02:39:20 +00:00
.launch();
2019-12-17 23:58:57 +00:00
}