Problem:
Problem E: Driving an Icosahedral Rover

After decades of fruitless efforts, one of the expedition teams of ITO (Intersolar Tourism Organization) finally found a planet that would surely provide one of the best tourist attractions
within a ten light-year radius from our solar system. The most attractive feature of the planet,
besides its comfortable gravity and calm weather, is the area called Mare Triangularis. Despite
the name, the area is not covered with water but is a great plane. Its unique feature is that it is
divided into equilateral triangular sections of the same size, called trigons. The trigons provide
a unique impressive landscape, a must for tourism. It is no wonder the board of ITO decided
to invest a vast amount on the planet.

Despite the expected secrecy of the staff, the Society of Astrogeology caught this information
in no time, as always. They immediately sent their president's letter to the Institute of Science
and Education of the Commonwealth Galactica claiming that authoritative academic inspections
were to be completed before any commercial exploitation might damage the nature.

Fortunately, astrogeologists do not plan to practice all the possible inspections on all of the
trigons; there are far too many of them. Inspections are planned only on some characteristic
trigons and, for each of them, in one of twenty different scientific aspects.

To accelerate building this new tourist resort, ITO's construction machinery team has already succeeded in putting their brand-new
invention in practical use. It is a rover vehicle of the shape of an icosahedron, a regular polyhedron with twenty faces of equilateral triangles.
The machine is customized
so that each of the twenty faces exactly fits each of the trigons.
Controlling the high-tech gyromotor installed inside its body, the rover can roll onto one of the three trigons neighboring the one its bottom is
on.

Figure E.1: The Rover on Mare Triangularis

Each of the twenty faces has its own function. The set of equipments installed on the bottom
face touching the ground can be applied to the trigon it is on. Of course, the rover was meant to accelerate construction of the luxury hotels to host rich interstellar travelers, but, changing
the installed equipment sets, it can also be used to accelerate academic inspections.

You are the driver of this rover and are asked to move the vehicle onto the trigon specified by
the leader of the scientific commission with the smallest possible steps. What makes your task
more difficult is that the designated face installed with the appropriate set of equipments has to
be the bottom. The direction of the rover does not matter.

Figure E.2:The Coordinate System

Figure E.3: Face Numbering

The trigons of Mare Triangularis are given two-dimensional coordinates as shown in Figure E.2.
Like maps used for the Earth, the x axis is from the west to the east, and the y axis is from the
south to the north. Note that all the trigons with its coordinates (x , y) has neighboring trigons
with coordinates (x - 1 , y) and (x + 1 , y). In addition to these, when x + y is even, it has a
neighbor (x , y + 1); otherwise, that is, when x + y is odd, it has a neighbor (x , y - 1).

Figure E.3 shows a development of the skin of the rover. The top face of the development
makes the exterior. That is, if the numbers on faces of the development were actually marked
on the faces of the rover, they should been readable from its outside. These numbers are used
to identify the faces.

When you start the rover, it is on the trigon (0,0) and the face 0 is touching the ground. The
rover is placed so that rolling towards north onto the trigon (0,1) makes the face numbered 5
to be at the bottom.

As your first step, you can choose one of the three adjacent trigons, namely those with coordinates (-1,0), (1,0),
and (0,1), to visit. The bottom will be the face numbered 4, 1, and 5,
respectively. If you choose to go to (1,0) in the first rolling step, the second step can bring
the rover to either of (0,0), (2,0), or (1,-1). The bottom face will be either of 0, 6, or 2,
correspondingly. The rover may visit any of the trigons twice or more, including the start and the goal trigons, when appropriate.

The theoretical design section of ITO showed that the rover can reach any goal trigon on the
specified bottom face within a finite number of steps.

Input

The input consists of a number of datasets. The number of datasets does not exceed 50.

Each of the datasets has three integers x, y, and n in one line, separated by a space. Here, (x,y)
specifies the coordinates of the trigon to which you have to move the rover, and n specifies the
face that should be at the bottom.

The end of the input is indicated by a line containing three zeros.

Output

The output for each dataset should be a line containing a single integer that gives the minimum
number of steps required to set the rover on the specified trigon with the specified face touching
the ground. No other characters should appear in the output.

You can assume that the maximum number of required steps does not exceed 100. Mare Triangularis
is broad enough so that any of its edges cannot be reached within that number of
steps.

Sample Input

0 0 1
3 5 2
-4 1 3
13 -13 2
-32 15 9
-50 50 0
0 0 0

Output for the Sample Input

6
10
9
30
47
100

Solution in Rust (judge verdict: Accepted)

use std::collections::hash_map::Entry;
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, Eq, PartialEq, Debug, Ord, PartialOrd)]
struct Coordinate {
    x: i32, y: i32
}

impl Coordinate {
    fn move_to(&self, dir: Dir) -> Option<Coordinate> {
        if (dir.to_int() as i32 + self.x + self.y) & 1 == 0 {
            match dir {
                Dir::Dir0 => Some(Coordinate{x: self.x, y: self.y + 1}),
                Dir::Dir60 | Dir::Dir120 => Some(Coordinate{x: self.x + 1, y: self.y}),
                Dir::Dir180 => Some(Coordinate{x: self.x, y: self.y - 1}),
                Dir::Dir240 | Dir::Dir300 => Some(Coordinate{x: self.x - 1, y: self.y}),
            }
        }else {
            None
        }
    }
}
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
enum Dir {
    Dir0, Dir60, Dir120, Dir180, Dir240, Dir300
}
impl Dir {
    fn from_int(value: usize) -> Dir {
        vec![Dir::Dir0, Dir::Dir60, Dir::Dir120, Dir::Dir180, Dir::Dir240, Dir::Dir300][value % 6]
    }
    fn to_int(&self) -> usize {
        match *self {
            Dir::Dir0 => 0,
            Dir::Dir60 => 1,
            Dir::Dir120 => 2,
            Dir::Dir180 => 3,
            Dir::Dir240 => 4,
            Dir::Dir300 => 5
        }
    }
    fn flip(&self) -> Dir {
        Dir::from_int(self.to_int() + 3)
    }
    fn next(&self) -> Vec<Dir> {
        match *self {
            Dir::Dir0 | Dir::Dir120 | Dir::Dir240 => vec![Dir::Dir0, Dir::Dir120, Dir::Dir240],
            Dir::Dir60 | Dir::Dir180 | Dir::Dir300 => vec![Dir::Dir60, Dir::Dir180, Dir::Dir300],
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Face {
    num: usize, dir: Dir
}
impl Face {
    fn roll(&self, dir: Dir) -> Option<Face> {
        if (self.dir.to_int() + dir.to_int()) & 1 == 0 {
            let new_num = Face::neighbor_face(self.num)[(6 + dir.to_int() - self.dir.to_int()) % 6 >> 1];
            Some(Face{num: new_num, dir: Face::detect_dir(new_num, self.num, dir.flip()).unwrap()})
        }else {
            None
        }
    }
    fn detect_dir(num: usize, other_num: usize, other_dir: Dir) -> Option<Dir> {
        if let Some(dir) = Face::neighbor_face(num).iter().position(|&c| c == other_num) {
            Some(Dir::from_int(6 - (dir << 1) + other_dir.to_int()))
        }else {
            None
        }
    }
    fn neighbor_face(num: usize) -> Vec<usize> {
        match num {
            0 => vec![5, 1, 4],
            1 => vec![6, 2, 0],
            2 => vec![7, 3, 1],
            3 => vec![8, 4, 2],
            4 => vec![9, 0, 3],
            5 => vec![0, 10, 11],
            6 => vec![1, 11, 12],
            7 => vec![2, 12, 13],
            8 => vec![3, 13, 14],
            9 => vec![4, 14, 10],
            10 => vec![15, 5, 9],
            11 => vec![16, 6, 5],
            12 => vec![17, 7, 6],
            13 => vec![18, 8, 7],
            14 => vec![19, 9, 8],
            15 => vec![10, 19, 16],
            16 => vec![11, 15, 17],
            17 => vec![12, 16, 18],
            18 => vec![13, 17, 19],
            19 => vec![14, 18, 15],
            _ => unreachable!()
        }
    }
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
struct Rover {
    position: Coordinate, bottom: Face
}

impl Rover {
    fn new() -> Rover {
        Rover{position: Coordinate{x: 0, y: 0}, bottom: Face{num: 0, dir: Face::detect_dir(0, 5, Dir::Dir0).unwrap()}}
    }
    fn next(&self) -> Vec<Rover> {
        self.bottom.dir.next().into_iter().map(|dir| Rover{position: self.position.move_to(dir).unwrap(), bottom: self.bottom.roll(dir).unwrap()}).collect::<Vec<_>>()
    }
    fn expect(position: Coordinate, face: usize) -> Vec<Rover> {
        if (position.x + position.y) & 1 == 0 {
            Dir::Dir0.next().into_iter().map(|dir| Rover{position: position, bottom: Face{num: face, dir: dir}}).collect::<Vec<_>>()
        }else {
            Dir::Dir60.next().into_iter().map(|dir| Rover{position: position, bottom: Face{num: face, dir: dir}}).collect::<Vec<_>>()
        }
    }
}

fn main() {
    let mut memo = BTreeMap::<Rover, usize>::new();
    let mut queue = VecDeque::new();
    memo.insert(Rover::new(), 0);
    queue.push_back(Rover::new());
    for count in 1 .. 101 {
        for _ in 0 .. queue.len() {
            let current = queue.pop_front().unwrap();
            //println!("current: {:?}", current);
            for next in current.next() {
                //println!("next: {:?}, count: {}", next, count);
                match memo.entry(next) {
                    std::collections::btree_map::Entry::Vacant(e) => {
                        e.insert(count);
                        queue.push_back(next);
                    },
                    _ => ()
                }
            }
        }
    }
    loop {
        read!(x: i32, y: i32, face: usize);
        if x == 0 && y == 0 && face == 0 {break;}
        println!("{}", Rover::expect(Coordinate{x: x, y: y}, face).into_iter().flat_map(|r| memo.get(&r)).min().unwrap())
    }
}