Skip to content
Permalink
Browse files

Partial puzzle solver

  • Loading branch information...
ichyo committed Jun 23, 2019
1 parent 6cae83e commit 827943b91be26afd2836e8c698a3ffbc1b90bdd2
Showing with 335 additions and 22 deletions.
  1. +1 −0 .gitignore
  2. +2 −1 src/bin/mining.rs
  3. +1 −0 src/lib.rs
  4. +50 −1 src/mine.rs
  5. +49 −0 src/models.rs
  6. +2 −2 src/parse.rs
  7. +185 −0 src/puzzle.rs
  8. +12 −18 src/solve.rs
  9. +33 −0 src/utils.rs
@@ -1,3 +1,4 @@
/target
**/*.rs.bk
solutions/test
blocks
@@ -1,5 +1,6 @@
use icfpc::mine::Client;

fn main() {
let _client = Client::new();
let mut client = Client::new();
client.execute();
}
@@ -6,3 +6,4 @@ pub mod models;
pub mod parse;
pub mod solve;
pub mod utils;
pub mod puzzle;
@@ -1,6 +1,14 @@
use jsonrpc_client_http::{HttpHandle, HttpTransport};
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::{HashMap, HashSet, VecDeque};
use std::{thread, time};

use crate::models::*;
use crate::parse::{read_puzzle, read_task};
use crate::puzzle::solve_pazzle;
use crate::solve::solve_small;

#[derive(Debug, Serialize, Deserialize)]
pub struct BlockChainInfo {
@@ -13,14 +21,22 @@ pub struct BlockChainInfo {
#[derive(Debug, Serialize, Deserialize)]
pub struct MiningInfo {
block: usize,
excluded: Vec<usize>,
//excluded: Vec<usize>,
puzzle: String,
task: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct BlockInfo {
block: usize,
puzzle: String,
task: String,
}

jsonrpc_client!(pub struct LambdaClient {
pub fn getblockchaininfo(&mut self) -> RpcRequest<BlockChainInfo>;
pub fn getmininginfo(&mut self) -> RpcRequest<MiningInfo>;
pub fn getblockinfo(&mut self, block: usize) -> RpcRequest<BlockInfo>;
pub fn submit(&mut self, block: usize, task_sol_path: &str, pazzle_sol_path: &str) -> RpcRequest<Value>;
});

@@ -41,4 +57,37 @@ impl Client {
let client = LambdaClient::new(transport_handle);
Client { api: client }
}

pub fn solve(&self, block: usize, puzzle: &str, task: &str) {
let mut rand = thread_rng();
let puzzle = read_puzzle(puzzle);
eprintln!("{:?}", puzzle);
let task = read_task(task);
//let commands = solve_small(task);

let puzzle_answer = solve_pazzle(puzzle);
println!("{:?}", puzzle_answer);
}

pub fn execute(&mut self) {
loop {
match self.api.getmininginfo().call() {
Ok(x) => {
for b in 0..x.block {
let b = self.api.getblockinfo(b).call().unwrap();
let puzzle = read_puzzle(&b.puzzle);
let puzzle_answer = solve_pazzle(puzzle);
println!("{:?}", puzzle_answer);
}
self.solve(x.block, &x.puzzle, &x.task);
}
Err(e) => {
println!("{}", e);
}
}

let one_sec = time::Duration::from_secs(60);
thread::sleep(one_sec);
}
}
}
@@ -17,6 +17,13 @@ impl Add for Point {
}
}

impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({},{})", self.x, self.y)?;
Ok(())
}
}

impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
@@ -53,6 +60,13 @@ pub enum Direction {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Map(pub Vec<Point>);

impl fmt::Display for Map {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0.iter().map(|p| format!("{}", p)).collect::<Vec<_>>().join(","))?;
Ok(())
}
}

impl Map {
pub fn new(ps: Vec<Point>) -> Map {
Map(ps)
@@ -111,6 +125,10 @@ impl Map {
}
res
}

pub fn len(&self) -> usize {
self.0.len()
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
@@ -123,6 +141,19 @@ pub enum BoosterType {
Spawn,
}

impl fmt::Display for BoosterType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
BoosterType::NewHand => write!(f, "B"),
BoosterType::FastMove => write!(f, "F"),
BoosterType::Drill => write!(f, "L"),
BoosterType::Teleports => write!(f, "R"),
BoosterType::Cloning => write!(f, "C"),
BoosterType::Spawn => write!(f, "X"),
}
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Booster {
pub kind: BoosterType,
@@ -135,6 +166,12 @@ impl Booster {
}
}

impl fmt::Display for Booster {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}", self.kind, self.point)
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Task {
pub width: usize,
@@ -145,6 +182,17 @@ pub struct Task {
pub boosters: Vec<Booster>,
}

impl fmt::Display for Task {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}#", self.map)?;
write!(f, "{}#", self.initial)?;
write!(f, "{}#", self.obstacles.iter().map(|o| format!("{}", o)).collect::<Vec<_>>().join(";"))?;
write!(f, "{}", self.boosters.iter().map(|b| format!("{}", b)).collect::<Vec<_>>().join(";"))?;
Ok(())
}
}


#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Move {
MoveUp,
@@ -185,6 +233,7 @@ impl fmt::Display for Command {
}
}

#[derive(Debug)]
pub struct Puzzle {
pub block: usize,
pub epock: usize,
@@ -132,7 +132,7 @@ fn read_boosters(mut iter: &mut Peekable<Chars>) -> Vec<Booster> {
res
}

fn read_task(s: &str) -> Task {
pub fn read_task(s: &str) -> Task {
let mut iter = s.chars().peekable();
let map = read_map(&mut iter);
let initial = read_initial(&mut iter);
@@ -164,7 +164,7 @@ fn find_files(input_root: &str) -> Vec<String> {
.collect::<Vec<String>>()
}

fn read_puzzle(s: &str) -> Puzzle {
pub fn read_puzzle(s: &str) -> Puzzle {
let mut iter = s.chars().peekable();
let block = read_usize(&mut iter, ',');
let epock = read_usize(&mut iter, ',');
@@ -0,0 +1,185 @@
use crate::models::*;
use crate::utils::Range;
use rand::prelude::*;
use std::collections::VecDeque;

fn construct_map_from_ranges(ranges: &[Range]) -> Map {
let len = ranges.len();
let mut vertexes = Vec::new();
vertexes.push(Point::new(0, ranges[0].start as i32));
vertexes.push(Point::new(0, ranges[0].end as i32));
for y in 0..len - 1 {
if ranges[y].end != ranges[y + 1].end {
vertexes.push(Point::new((y + 1) as i32, ranges[y].end as i32));
vertexes.push(Point::new((y + 1) as i32, ranges[y + 1].end as i32));
}
}
vertexes.push(Point::new(len as i32, ranges[len - 1].end as i32));
vertexes.push(Point::new(len as i32, ranges[len - 1].start as i32));
for y in (0..len - 1).rev() {
if ranges[y].start != ranges[y + 1].start {
vertexes.push(Point::new((y + 1) as i32, ranges[y + 1].start as i32));
vertexes.push(Point::new((y + 1) as i32, ranges[y].start as i32));
}
}
Map::new(vertexes)
}

fn consume_points_for(source: &mut VecDeque<Point>, num: usize, kind: BoosterType) -> Vec<Booster> {
let mut res = Vec::new();
for _ in 0..num {
res.push(Booster::new(kind.clone(), source.pop_front().unwrap()));
}
res
}

pub fn solve_pazzle(puzzle: Puzzle) -> Option<Task> {
let len = puzzle.max_length - 1;
assert!(puzzle.includes.iter().all(|p| p.x < len as i32));
assert!(puzzle.includes.iter().all(|p| p.y < len as i32));
assert!(puzzle.excludes.iter().all(|p| p.x < len as i32));
assert!(puzzle.excludes.iter().all(|p| p.y < len as i32));

let mut include_xs = vec![vec![]; len];
let mut exclude_xs = vec![vec![]; len];
for p in &puzzle.excludes {
exclude_xs[p.y as usize].push(p.x as usize);
}
for p in &puzzle.includes {
include_xs[p.y as usize].push(p.x as usize);
}

let global_range = Range::new(0, len);
let mut x_ranges = vec![vec![]; len];
for y in 0..len {
let exs = &mut exclude_xs[y];
if exs.is_empty() {
x_ranges[y].push(global_range);
} else {
exs.sort();
x_ranges[y].push(global_range.split(exs[0]).0);
x_ranges[y].push(global_range.split(exs[exs.len() - 1]).1);
for i in 0..exs.len() - 1 {
x_ranges[y].push(global_range.split(exs[i]).1.split(exs[i + 1]).0);
}
}
}
let mut reachables = vec![vec![]; len];
for r in &x_ranges[0] {
let ixs = &include_xs[0];
if r.contains_all(ixs) {
reachables[0].push((*r, *r));
}
}
for y in 1..len {
let mut next = Vec::new();
let ixs = &include_xs[y];
for to in &x_ranges[y] {
if !to.contains_all(ixs) {
continue;
}
for (from, _) in &reachables[y - 1] {
if !to.intersect(*from) {
continue;
}
next.push((*to, *from));
break;
}
}
reachables[y].extend(next);
}

if reachables[len - 1].is_empty() {
eprintln!("unreachable");
return None;
}

let mut ranges = Vec::new();
let (mut cur_r, mut next_r) = reachables[len - 1][0];
ranges.push(cur_r);
for y in (0..len - 1).rev() {
let (new_cur_r, new_next_r) = reachables[y]
.iter()
.cloned()
.find(|(r, _)| *r == next_r)
.unwrap();
cur_r = new_cur_r;
next_r = new_next_r;
ranges.push(cur_r);
}
ranges.reverse();

let map = construct_map_from_ranges(&ranges);

if map.len() < puzzle.vertex_min {
eprintln!(
"NG: vertex {} is less than {}",
map.len(),
puzzle.vertex_min
);
return None;
}

if map.len() > puzzle.vertex_max {
eprintln!(
"NG: vertex {} is greater than {}",
map.len(),
puzzle.vertex_max
);
return None;
}

let mut points = map.enumerate_points();
if points.len() < len * len / 5 {
eprintln!("NG: area {} is less than {}", points.len(), len * len / 5);
return None;
}

let mut rand = thread_rng();
points.shuffle(&mut rand);
let mut point_source = points.into_iter().collect::<VecDeque<_>>();
let initial = point_source.pop_front().unwrap();

let mut boosters = Vec::new();
boosters.extend(consume_points_for(
&mut point_source,
puzzle.hand_count,
BoosterType::NewHand,
));
boosters.extend(consume_points_for(
&mut point_source,
puzzle.fast_count,
BoosterType::FastMove,
));
boosters.extend(consume_points_for(
&mut point_source,
puzzle.drill_count,
BoosterType::Drill,
));
boosters.extend(consume_points_for(
&mut point_source,
puzzle.tele_count,
BoosterType::Teleports,
));
boosters.extend(consume_points_for(
&mut point_source,
puzzle.clone_count,
BoosterType::Cloning,
));
boosters.extend(consume_points_for(
&mut point_source,
puzzle.spawn_count,
BoosterType::Spawn,
));

let task = Task {
width: len,
height: len,
map,
initial,
obstacles: Vec::new(),
boosters,
};

Some(task)
}

0 comments on commit 827943b

Please sign in to comment.
You can’t perform that action at this time.