2019-12-17 23:58:57 +00:00
|
|
|
#![feature(proc_macro_hygiene, decl_macro)]
|
|
|
|
|
|
|
|
#[macro_use] extern crate rocket;
|
|
|
|
#[macro_use] extern crate rocket_contrib;
|
|
|
|
#[macro_use] extern crate serde_derive;
|
|
|
|
|
2019-12-18 02:39:20 +00:00
|
|
|
use rocket::State;
|
2019-12-17 23:58:57 +00:00
|
|
|
use rocket_contrib::json::Json;
|
|
|
|
use pathfinding::grid::Grid;
|
2019-12-18 02:39:20 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::sync::{Arc, 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"
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("/begin", format = "json", data = "<msg>")]
|
2019-12-18 02:39:20 +00:00
|
|
|
fn begin(cache: State<Cache>, msg: Json<battlesnake::SnakeRequest>) -> Json<battlesnake::StartResponse> {
|
|
|
|
let head = msg.you.body[0];
|
|
|
|
let target = find_target(&msg);
|
|
|
|
let path = find_path(&msg, &head, &target);
|
|
|
|
let gs = GameState{
|
|
|
|
target: *target,
|
|
|
|
path: path,
|
|
|
|
};
|
|
|
|
|
2019-12-18 03:20:09 +00:00
|
|
|
if let Some(x) = cache.lock().expect("wanted cache to be unlockable").get_mut(&msg.game.id) {
|
|
|
|
*x = gs;
|
|
|
|
};
|
2019-12-18 02:39:20 +00:00
|
|
|
|
2019-12-17 23:58:57 +00:00
|
|
|
Json(battlesnake::StartResponse{
|
|
|
|
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,
|
|
|
|
target: &battlesnake::Coord
|
|
|
|
) -> 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) => {
|
|
|
|
return Some(x.0);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
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;
|
|
|
|
Json(battlesnake::MoveResponse {
|
|
|
|
move_field: "up".to_string(),
|
|
|
|
})
|
2019-12-18 05:07:13 +00:00
|
|
|
}
|
|
|
|
Some(next) => Json(battlesnake::MoveResponse {
|
|
|
|
move_field: battlesnake::Line {
|
|
|
|
start: &head,
|
|
|
|
end: &next,
|
|
|
|
}
|
|
|
|
.direction()
|
|
|
|
.to_string(),
|
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];
|
2019-12-17 23:58:57 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gs.you.body.last().unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2019-12-18 02:39:20 +00:00
|
|
|
let map = HashMap::<String, GameState>::new();
|
|
|
|
let mutex_map = Mutex::from(map);
|
2019-12-17 23:58:57 +00:00
|
|
|
rocket::ignite().mount("/", routes![
|
|
|
|
index,
|
|
|
|
begin,
|
|
|
|
ping,
|
2019-12-18 00:29:00 +00:00
|
|
|
make_move,
|
2019-12-18 02:39:20 +00:00
|
|
|
])
|
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
|
|
|
}
|