Problem:
Problem C: Hexerpents of Hexwamp

Hexwamp is a strange swamp, paved with regular hexagonal dimples.
Hexerpents crawling in this area are serpents adapted to the
environment, consisting of a chain of regular hexagonal sections. Each
section fits in one dimple.

Hexerpents crawl moving some of their sections from the dimples they
are in to adjacent ones. To avoid breaking their bodies, sections
that are adjacent to each other before the move should also be
adjacent after the move. When one section moves, sections adjacent to
it support the move, and thus they cannot move at that time. Any
number of sections, as far as no two of them are adjacent to each
other, can move at the same time.

You can easily find that a hexerpent can move its sections at its
either end to only up to two dimples, and can move intermediate
sections to only one dimple, if any.

For example, without any obstacles, a hexerpent can crawl forward
twisting its body as shown in Figure C-1, left to right. In this
figure, the serpent moves four of its eight sections at a time, and
moves its body forward by one dimple unit after four steps of moves.
Actually, they are much better in crawling sideways, like sidewinders.

Figure C-1: Crawling forward

Their skin is so sticky that if two sections of a serpent that are not
originally adjacent come to adjacent dimples (Figure C-2), they will
stick together and the serpent cannot but die. Two sections cannot
fit in one dimple, of course. This restricts serpents' moves
further. Sometimes, they have to make some efforts to get a food
piece even when it is in the dimple next to their head.

Figure C-2: Fatal case

Hexwamp has rocks here and there. Each rock fits in a dimple.
Hexerpents' skin does not stick to rocks, but they cannot crawl over
the rocks. Although avoiding dimples with rocks restricts their
moves, they know the geography so well that they can plan the fastest
paths.

You are appointed to take the responsibility of the head of the
scientist team to carry out academic research on this swamp and the
serpents. You are expected to accomplish the research, but never at
the sacrifice of any casualty. Your task now is to estimate how soon
a man-eating hexerpent may move its head (the first section) to the
position of a scientist in the swamp. Their body sections except for
the head are quite harmless and the scientist wearing high-tech
anti-sticking suit can stay in the same dimple with a body section of
the hexerpent.

Input

The input is a sequence of several datasets, and the end of the input
is indicated by a line containing a single zero. The number of
datasets never exceeds 10.

Each dataset looks like the following.

the number of sections the serpent has (=n)

x1 y1

x2 y2

...

xn yn

the number of rocks the swamp has (=k)

u1 v1

u2 v2

...

uk vk

X Y

The first line of the dataset has an integer n that indicates
the number of sections the hexerpent has, which is 2 or greater and
never exceeds 8. Each of the n following lines contains two
integers x and y that indicate the coordinates of a
serpent's section. The lines show the initial positions of the
sections from the serpent's head to its tail, in this order.

The next line of the dataset indicates the number of rocks k
the swamp has, which is a non-negative integer not exceeding 100.
Each of the k following lines contains two integers u
and v that indicate the position of a rock.

Finally comes a line containing two integers X and Y,
indicating the goal position of the hexerpent, where the scientist is.
The serpent's head is not initially here.

All of the coordinates x, y, u, v, X, and Y are between
−999999 and 999999, inclusive. Two integers in a line are
separated by a single space. No characters other than decimal digits,
minus signs, and spaces to separate two integers appear in the input.
The coordinate system used to indicate a position is as shown in
Figure C-3.

Figure C-3: The coordinate system

Output

For each dataset, output a line that contains a decimal integer that
indicates the minimum number of steps the serpent requires for moving
its head to the goal position. Output lines should not contain any
other characters.

You can assume that the hexerpent can reach the goal within 20 steps.

Sample Input

3
2 -2
2 -1
1 0
1
0 2
0 0
4
2 -2
2 -1
2 0
3 0
2
1 -1
0 2
0 0
8
-6 0
-5 0
-4 0
-3 0
-2 0
-1 0
0 0
1 0
1
-1 1
0 0
6
2 -3
3 -3
3 -2
3 -1
3 0
2 1
3
1 -1
1 0
1 1
0 0
3
-8000 4996
-8000 4997
-8000 4998
2
-7999 4999
-8001 5000
-8000 5000
8
10 -8
9 -7
9 -6
9 -5
9 -4
9 -3
9 -2
9 -1
0
0 0
0

Output for the Sample Input

3
9
18
18
19
20

Solution in Rust (judge verdict: Accepted)

use std::hash::Hash;
use std::collections::hash_set::Iter;
use std::rc::Rc;
use std::ops::DivAssign;
use std::ops::MulAssign;
use std::ops::SubAssign;
use std::collections::BinaryHeap;
use std::str::FromStr;
use std::collections::HashSet;
use std::collections::BTreeMap;
use std::fmt::Display;
use std::ops::Neg;
use std::ops::Div;
use std::ops::Mul;
use std::ops::Add;
use std::ops::{AddAssign, Sub};
use std::cmp::max;
use std::collections::VecDeque;
use std::cmp::min;
use std::collections::{HashMap, BTreeSet};
use std::cmp::Ordering;
use std::fmt::Debug;

fn read_line() -> String {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).expect("No Line");
    buffer.trim().to_owned()
}
fn read_lines<T: std::str::FromStr>(count: usize) -> Vec<T> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(buffer.trim().parse().ok().expect("Can't Parse"));
        buffer.clear();
    }
    vec
}
fn read_tabulate<R, T: Fn(&str)->R> (count: usize, transformer: T) -> Vec<R> {
    let mut buffer = String::new();
    let mut vec = Vec::with_capacity(count);
    for _ in 0 .. count {
        std::io::stdin().read_line(&mut buffer).expect("No Line");
        vec.push(transformer(buffer.trim()));
        buffer.clear();
    }
    vec
}
fn read_value<T: std::str::FromStr>() -> T {
    read_line().trim().parse().ok().unwrap()
}
fn read_values<T: std::str::FromStr>() -> Vec<T> {
    read_line().trim().split_whitespace().map(|x| x.parse().ok().expect("Can't Parse")).collect::<Vec<T>>()
}
macro_rules! freeze {
    ($($id:ident), *) => {
        $(let $id = $id;)*
    };
}
macro_rules! read_map {
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
}
macro_rules! read {
    (mut $ident: ident: String) => {
        let mut $ident = read_value::<String>();
    };
    ($ident: ident: String) => {
        let $ident = read_value::<String>();
    };
    (mut $ident: ident: [$ty:ty]) => {
        let mut $ident = read_values::<$ty>();
    };
    ($ident: ident: [$ty:ty]) => {
        let $ident = read_values::<$ty>();
    };
    (mut $ident: ident: [[$ty:ty]; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    ($ident: ident: [[$ty:ty]; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| read_values::<$ty>()).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$ty:ty; $size:expr]) => {
        let mut $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$ty:ty; $size:expr]) => {
        let $ident = read_lines::<$ty>($size);
    };
    ($ident: ident: [$block: block; $size: expr]) => {
        let $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    (mut $ident: ident: [$block: block; $size: expr]) => {
        let mut $ident = (0 .. $size).into_iter().map(|_| $block).collect::<Vec<_>>();
    };
    ($($token: tt)*) => {
        let mut iter = read_values::<String>().into_iter();
        read_from_iter!(iter; $($token)*);
    };
}
macro_rules! read_from_iter {
    ($iter:expr; mut $ident:ident:$ty:ty, $($rest:tt)*) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; $ident:ident:$ty:ty, $($rest:tt)*) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
        read_from_iter!($iter; $($rest)*);
    };
    ($iter:expr; mut $ident:ident:$ty:ty) => {
        let mut $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter:expr; $ident:ident:$ty:ty) => {
        let $ident = $iter.next().unwrap().parse::<$ty>().expect("Can't Parse");
    };
    ($iter: expr; ) => {};
}
struct KeyValue<K, V> {
    key: K,
    value: V
}
impl <K: PartialOrd, V> PartialEq for KeyValue<K, V> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
impl <K: PartialOrd, V> Eq for KeyValue<K, V> {}
impl <K: PartialOrd, V> PartialOrd for KeyValue<K, V> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.key.partial_cmp(&other.key)
    }
}
impl <K: PartialOrd, V> Ord for KeyValue<K, V> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.key.partial_cmp(&other.key).ok_or("Can't Compare").unwrap()
    }
}
#[derive(Eq, PartialEq)]
struct Rev<T: Ord>(T);
impl <T: std::cmp::Ord> PartialOrd for Rev<T> {
    fn partial_cmp(&self, rhs: &Rev<T>) -> std::option::Option<std::cmp::Ordering> { 
        rhs.0.partial_cmp(&self.0)
    }
}
impl <T: Ord> Ord for Rev<T> {
    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering { 
        rhs.0.cmp(&self.0)
    }
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct Coordinate {
    x: i32, y: i32
}
impl Hash for Coordinate {
    fn hash<H>(&self, hasher: &mut H) where H: std::hash::Hasher {
        self.x.hash(hasher);
        self.y.hash(hasher);
    }
}
impl Coordinate {
    fn is_neighbor(&self, other: Coordinate) -> bool {
        let Coordinate{x: dx, y: dy} = *self - other;
        -1 <= dx && dx <= 1 && -1 <= dy && dy <= 1 && dx != dy
    }
    fn neighbor(&self) -> Vec<Coordinate> {
        vec![
            Coordinate{x: self.x, y: self.y + 1},
            Coordinate{x: self.x + 1, y: self.y},
            Coordinate{x: self.x + 1, y: self.y - 1},
            Coordinate{x: self.x, y: self.y - 1},
            Coordinate{x: self.x - 1, y: self.y},
            Coordinate{x: self.x - 1, y: self.y + 1}
        ]
    }
    fn neighbors() -> Vec<Coordinate> {
        Coordinate{x: 0, y: 0}.neighbor()
    }
}
impl Add for Coordinate {
    type Output = Coordinate;
    fn add(self, rhs: Coordinate) -> <Self as std::ops::Add<Coordinate>>::Output { 
        Coordinate{x: self.x + rhs.x, y: self.y + rhs.y}
    }
}
impl Sub for Coordinate {
    type Output = Coordinate;
    fn sub(self, rhs: Coordinate) -> <Self as std::ops::Sub<Coordinate>>::Output { 
        Coordinate{x: self.x - rhs.x, y: self.y - rhs.y}
    }
}
fn enumerate_all_next<F: FnMut(&Vec<Coordinate>) -> ()>(current: &Vec<Coordinate>, suspect: &mut Vec<Coordinate>, consumer: &mut F) {
    if current.len() == suspect.len() {
        return consumer(suspect);
    }
    if suspect.is_empty() || current[suspect.len() - 1] == suspect[suspect.len() - 1] {
        let len = suspect.len();
        suspect.push(current[len]);
        if is_valid_next_state(&current[0..suspect.len()], suspect) {
            enumerate_all_next(current, suspect, consumer);
        }
        suspect.pop();
        for next in current[suspect.len()].neighbor() {
            suspect.push(next);
            if is_valid_next_state(&current[0..suspect.len()], suspect) {
                enumerate_all_next(current, suspect, consumer);
            }
            suspect.pop();
        }
    }else {
        let len = suspect.len();
        suspect.push(current[len]);
        if is_valid_next_state(&current[0..suspect.len()], suspect) {
            enumerate_all_next(current, suspect, consumer);
        }
        suspect.pop();
    }
}
fn enumerate_all_initial<F: FnMut(&Vec<Coordinate>) -> ()>(suspect: &mut Vec<Coordinate>, consumer: &mut F) {
    if suspect.len() == 8 {
        return;
    }
    if let Some(&last) = suspect.last() {
        for next in last.neighbor() {
            suspect.push(next);
            if is_valid(suspect) {
                consumer(suspect);
                enumerate_all_initial(suspect, consumer);
            }
            suspect.pop();
        }
    }else {
        suspect.push(Coordinate{x: 0, y: 0});
        if is_valid(suspect) {
            consumer(suspect);
            enumerate_all_initial(suspect, consumer);
        }
        suspect.pop();
    }
}
fn to_dir(from: Coordinate, to: Coordinate) -> usize {
    match to - from {
        Coordinate{x: 0, y: 1} => 0,
        Coordinate{x: 1, y: 0} => 1,
        Coordinate{x: 1, y: -1} => 2,
        Coordinate{x: 0, y: -1} => 3,
        Coordinate{x: -1, y: 0} => 4,
        Coordinate{x: -1, y: 1} => 5,
        _ => panic!()
    }
}
fn to_index(trace: &Vec<Coordinate>) -> usize {
    let mut result = if trace[0].x == 0 && trace[0].y == 0 { 6 } else { to_dir(Coordinate{x: 0, y: 0}, trace[0]) };
    for i in 1 .. trace.len() {
        result = (result * 6) + to_dir(trace[i - 1], trace[i]);
    }
    result
}
fn is_valid(body: &[Coordinate]) -> bool {
    for i in 0 .. body.len() {
        for j in i + 2 .. body.len() {
            if body[i] == body[j] || body[i].is_neighbor(body[j]) {
                return false;
            }
        }
    }
    for i in 1 .. body.len() {
        if !body[i - 1].is_neighbor(body[i]) {
            return false;
        }
    }
    true
}
fn is_valid_next_state(prev: &[Coordinate], next: &[Coordinate]) -> bool {
    if !is_valid(next) {return false;}
    for i in 1 .. prev.len() {
        if prev[i - 1] != next[i - 1] && prev[i] != next[i] {
            return false;
        }
    }
    for i in 0 .. prev.len() {
        if prev[i] != next[i] && !prev[i].is_neighbor(next[i]) {
            return false;
        }
    }
    true
}
fn all_pair() -> HashMap<usize, (HashMap<usize, Vec<usize>>, HashMap<usize, Vec<Coordinate>>)>  {
    let mut suspect = vec![];
    let mut result = HashMap::new();
    enumerate_all_initial( &mut suspect, &mut |trace| {
        let ref mut t = result.entry(trace.len()).or_insert((HashMap::new(), HashMap::new()));
        let next_state = &mut t.0;
        let index_to_state = &mut t.1;
        index_to_state.insert(to_index(trace), trace.clone());
        let mut nexts = HashSet::new();
        let mut temp = vec![];
        enumerate_all_next(trace, &mut temp, &mut |next| {
            nexts.insert(to_index(next));
           if next[0] != trace[0] { index_to_state.entry(to_index(next)).or_insert(next.clone()); };
        });
        next_state.insert(to_index(trace), nexts.into_iter().collect::<Vec<_>>());
    });
    result
}
fn main() {
    let heuristic_length = |coordinate: Coordinate| { max(max(coordinate.x, coordinate.y), (coordinate.x + coordinate.y).abs()) };
    let caches = all_pair();
    loop {
        read!(n: usize);
        if n == 0 { break; }
        read_map!(snake: [{
            read!(x: i32, y: i32);
            Coordinate{x: x, y: y}
        }; n]);
        let ref t = caches.get(&n).unwrap();
        let ref next_states = t.0;
        let ref indices_to_state = t.1;
        read!(k: usize);
        read_map!(blocks: [{
            read!(x: i32, y: i32);
            Coordinate{x: x, y: y}
        }; k]);
        read!(X: i32, Y: i32);
        let goal = Coordinate{x: X, y: Y};
        let mut queue = BinaryHeap::new();
        let mut memo = HashMap::<(Coordinate, usize), i32>::new();
        memo.insert((snake[0], to_index(&snake.iter().map(|&c| c - snake[0]).collect::<Vec<_>>())), 0);
        queue.push(Rev(KeyValue{key: 0, value: (snake[0], to_index(&snake.iter().map(|&c| c - snake[0]).collect::<Vec<_>>()))}));
        let mut result = None;
        while let Some(Rev(KeyValue{key: all_step, value: (head, posture)})) = queue.pop() {
            //println!("all_step: {}, head: {:?}, position: {:?}", all_step, head, indices_to_state[&posture]);
            if head == goal {
                result = Some(all_step);
                break;
            }
            let step = *memo.get(&(head, posture)).unwrap();
            for next in &next_states[&posture] {
                if let Some(pos) = indices_to_state.get(next) {
                    let next_pos = pos.iter().map(|&c| c + head).collect::<Vec<_>>();
                    if next_pos.iter().any(|c| blocks.contains(c)) {continue;};
                    //println!("next_pos: {:?}, step: {}", next_pos, step);
                    let next = to_index(&next_pos.iter().map(|&c| c - next_pos[0]).collect::<Vec<_>>());
                    let m = memo.entry((next_pos[0], next)).or_insert(std::i32::MAX);
                    if *m > step + 1 {
                        *m = step + 1;
                        queue.push(Rev(KeyValue{key: step + 1 + heuristic_length(next_pos[0] - goal), value: (next_pos[0], next)}));
                    }
                }else {
                    panic!();
                }
            }
        }
        println!("{}", result.unwrap());
    }
}