extern crate algs4;
use std::io::prelude::*;
use std::io;
use std::fmt;
use std::cmp::Ordering;
use algs4::sorting::quick_sort;
use algs4::sorting::comparator::Comparator;
use algs4::sorting::comparator::insertion_sort;
#[derive(Copy, Clone)]
pub struct Point {
x: i32,
y: i32,
}
pub struct SlopeOrder<'a> {
pt: &'a Point
}
impl<'a> Comparator<Point> for SlopeOrder<'a> {
fn compare(&self, q1: &Point, q2: &Point) -> Ordering {
self.pt.slope_to(q1).partial_cmp(&self.pt.slope_to(q2)).unwrap()
}
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x: x, y: y }
}
pub fn draw(&self) {
unimplemented!()
}
pub fn draw_to(&self, _other: &Point) {
unimplemented!()
}
pub fn slope_to(&self, other: &Point) -> f64 {
((other.y - self.y) as f64) / ((other.x - self.x) as f64)
}
#[allow(non_snake_case)]
pub fn SLOPE_ORDER<'a>(&'a self) -> SlopeOrder<'a> {
SlopeOrder { pt: self }
}
}
impl PartialEq<Point> for Point {
fn eq(&self, other: &Point) -> bool {
self.x == other.x && self.y == other.y
}
}
impl PartialOrd<Point> for Point {
fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
if self.y < other.y || (self.y == other.y && self.x < other.x) {
Some(Ordering::Less)
} else if self.x == other.x && self.y == other.y {
Some(Ordering::Equal)
} else {
Some(Ordering::Greater)
}
}
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "({}, {})", self.x, self.y));
Ok(())
}
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "({}, {})", self.x, self.y));
Ok(())
}
}
fn brute_force(points: &[Point]) {
for p in points.iter() {
for q in points.iter() {
if p == q { break }
for r in points.iter() {
if r == p || r == q { break }
for s in points.iter() {
if s == p || s == q || s == r { break }
let slope = p.slope_to(q);
if slope == p.slope_to(r) && slope == p.slope_to(s) {
println!("{} -> {} -> {} -> {}", p, q, r, s);
}
}
}
}
}
}
fn sorting_based(points: &[Point]) {
let n = points.len();
let mut points = points.to_vec();
assert!(n > 4);
let mut result: Vec<Vec<Point>> = Vec::new();
for i in 1 .. n {
points.swap(0, i);
let mut points = points.clone();
let p = points[0].clone();
quick_sort(&mut points[1..]);
insertion_sort(&mut points[1..], p.SLOPE_ORDER());
let mut n = 0usize;
let mut coll_points_idx = vec![0];
let mut prev_slope = 99999.9;
for (idx, slope) in points.iter().map(|q| p.slope_to(q)).enumerate() {
if idx == 0 {
continue;
}
if slope == prev_slope {
n += 1;
coll_points_idx.push(idx);
} else {
if n >= 4 {
let mut line: Vec<Point> = coll_points_idx.iter().map(|&i| points[i].clone()).collect();
quick_sort(&mut line);
if !result.contains(&line) {
result.push(line)
}
}
n = 2;
coll_points_idx = vec![0, idx];
}
prev_slope = slope;
}
if n >= 4 {
let mut line: Vec<Point> = coll_points_idx.iter().map(|&i| points[i].clone()).collect();
quick_sort(&mut line);
if !result.contains(&line) {
result.push(line)
}
}
}
for line in result.iter() {
let desc = line.iter().map(|i| format!("{}", i)).collect::<Vec<String>>().join(" -> ");
println!("{}", desc);
}
}
fn main() {
let mut lines = io::BufReader::new(io::stdin()).lines();
let n = lines.next().unwrap().unwrap().parse().unwrap();
let mut points: Vec<Point> = Vec::new();
for _ in 0 .. n {
let segs: Vec<i32> = lines.next().unwrap().unwrap().split(' ').
filter(|s| !s.is_empty()).map(|n| n.parse().unwrap()).collect();
let x = segs[0];
let y = segs[1];
points.push(Point::new(x, y));
}
println!("# Brute force");
brute_force(&points);
println!("# A faster, sorting-based solution");
sorting_based(&mut points);
}