<commit_before>//! Process window events
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;
use std::sync::mpsc;
use std::time::{Instant};

use serde_json as json;
use parking_lot::MutexGuard;
use glutin::{self, ModifiersState, Event, ElementState};
use copypasta::{Clipboard, Load, Store};

use config::{self, Config};
use cli::Options;
use display::OnResize;
use index::{Line, Column, Side, Point};
use input::{self, MouseBinding, KeyBinding};
use selection::Selection;
use sync::FairMutex;
use term::{Term, SizeInfo, TermMode};
use util::limit;
use util::fmt::Red;
use window::Window;

/// Byte sequences are sent to a `Notify` in response to some events
pub trait Notify {
    /// Notify that an escape sequence should be written to the pty
    ///
    /// TODO this needs to be able to error somehow
    fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
}

pub struct ActionContext<'a, N: 'a> {
    pub notifier: &'a mut N,
    pub terminal: &'a mut Term,
    pub selection: &'a mut Option<Selection>,
    pub size_info: &'a SizeInfo,
    pub mouse: &'a mut Mouse,
    pub selection_modified: bool,
    pub received_count: &'a mut usize,
    pub suppress_chars: &'a mut bool,
    pub last_modifiers: &'a mut ModifiersState,
}

impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
    fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, val: B) {
        self.notifier.notify(val);
    }

    fn terminal_mode(&self) -> TermMode {
        *self.terminal.mode()
    }

    fn size_info(&self) -> SizeInfo {
        *self.size_info
    }

    fn copy_selection(&self, buffer: ::copypasta::Buffer) {
        if let Some(ref selection) = *self.selection {
            if let Some(ref span) = selection.to_span(self.terminal) {
                let buf = self.terminal.string_from_selection(&span);
                if !buf.is_empty() {
                    Clipboard::new()
                        .and_then(|mut clipboard| clipboard.store(buf, buffer))
                        .unwrap_or_else(|err| {
                            warn!("Error storing selection to clipboard. {}", Red(err));
                        });
                }
            }
        }
    }

    fn clear_selection(&mut self) {
        *self.selection = None;
        self.selection_modified = true;
    }

    fn update_selection(&mut self, point: Point, side: Side) {
        self.selection_modified = true;
        // Update selection if one exists
        if let Some(ref mut selection) = *self.selection {
            selection.update(point, side);
            return;
        }

        // Otherwise, start a regular selection
        self.simple_selection(point, side);
    }

    fn simple_selection(&mut self, point: Point, side: Side) {
        *self.selection = Some(Selection::simple(point, side));
        self.selection_modified = true;
    }

    fn semantic_selection(&mut self, point: Point) {
        *self.selection = Some(Selection::semantic(point, self.terminal));
        self.selection_modified = true;
    }

    fn line_selection(&mut self, point: Point) {
        *self.selection = Some(Selection::lines(point));
        self.selection_modified = true;
    }

    fn mouse_coords(&self) -> Option<Point> {
        self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize)
    }

    fn change_font_size(&mut self, delta: f32) {
        self.terminal.change_font_size(delta);
    }

    fn reset_font_size(&mut self) {
        self.terminal.reset_font_size();
    }

    #[inline]
    fn mouse_mut(&mut self) -> &mut Mouse {
        self.mouse
    }

    #[inline]
    fn received_count(&mut self) -> &mut usize {
        &mut self.received_count
    }

    #[inline]
    fn suppress_chars(&mut self) -> &mut bool {
        &mut self.suppress_chars
    }

    #[inline]
    fn last_modifiers(&mut self) -> &mut ModifiersState {
        &mut self.last_modifiers
    }
}

pub enum ClickState {
    None,
    Click,
    DoubleClick,
    TripleClick,
}

/// State of the mouse
pub struct Mouse {
    pub x: u32,
    pub y: u32,
    pub left_button_state: ElementState,
    pub middle_button_state: ElementState,
    pub right_button_state: ElementState,
    pub last_click_timestamp: Instant,
    pub click_state: ClickState,
    pub scroll_px: i32,
    pub line: Line,
    pub column: Column,
    pub cell_side: Side,
    pub lines_scrolled: f32,
}

impl Default for Mouse {
    fn default() -> Mouse {
        Mouse {
            x: 0,
            y: 0,
            last_click_timestamp: Instant::now(),
            left_button_state: ElementState::Released,
            middle_button_state: ElementState::Released,
            right_button_state: ElementState::Released,
            click_state: ClickState::None,
            scroll_px: 0,
            line: Line(0),
            column: Column(0),
            cell_side: Side::Left,
            lines_scrolled: 0.0,
        }
    }
}

/// The event processor
///
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor<N> {
    key_bindings: Vec<KeyBinding>,
    mouse_bindings: Vec<MouseBinding>,
    mouse_config: config::Mouse,
    print_events: bool,
    wait_for_event: bool,
    notifier: N,
    mouse: Mouse,
    resize_tx: mpsc::Sender<(u32, u32)>,
    ref_test: bool,
    size_info: SizeInfo,
    pub selection: Option<Selection>,
    hide_cursor_when_typing: bool,
    hide_cursor: bool,
    received_count: usize,
    suppress_chars: bool,
    last_modifiers: ModifiersState,
    pending_events: Vec<Event>,
}

/// Notify that the terminal was resized
///
/// Currently this just forwards the notice to the input processor.
impl<N> OnResize for Processor<N> {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.size_info = size.to_owned();
        self.selection = None;
    }
}

impl<N: Notify> Processor<N> {
    /// Create a new event processor
    ///
    /// Takes a writer which is expected to be hooked up to the write end of a
    /// pty.
    pub fn new(
        notifier: N,
        resize_tx: mpsc::Sender<(u32, u32)>,
        options: &Options,
        config: &Config,
        ref_test: bool,
        size_info: SizeInfo,
    ) -> Processor<N> {
        Processor {
            key_bindings: config.key_bindings().to_vec(),
            mouse_bindings: config.mouse_bindings().to_vec(),
            mouse_config: config.mouse().to_owned(),
            print_events: options.print_events,
            wait_for_event: true,
            notifier,
            resize_tx,
            ref_test,
            mouse: Default::default(),
            selection: None,
            size_info,
            hide_cursor_when_typing: config.hide_cursor_when_typing(),
            hide_cursor: false,
            received_count: 0,
            suppress_chars: false,
            last_modifiers: Default::default(),
            pending_events: Vec::with_capacity(4),
        }
    }

    /// Handle events from glutin
    ///
    /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
    fn handle_event<'a>(
        processor: &mut input::Processor<'a, ActionContext<'a, N>>,
        event: Event,
        ref_test: bool,
        resize_tx: &mpsc::Sender<(u32, u32)>,
        hide_cursor: &mut bool,
        window_is_focused: &mut bool,
    ) {
        match event {
            // Pass on device events
            Event::DeviceEvent { .. } | Event::Suspended { .. } => (),
            Event::WindowEvent { event, .. } => {
                use glutin::WindowEvent::*;
                match event {
                    CloseRequested => {
                        if ref_test {
                            // dump grid state
                            let grid = processor.ctx.terminal.grid();

                            let serialized_grid = json::to_string(&grid)
                                .expect("serialize grid");

                            let serialized_size = json::to_string(processor.ctx.terminal.size_info())
                                .expect("serialize size");

                            File::create("./grid.json")
                                .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
                                .expect("write grid.json");

                            File::create("./size.json")
                                .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
                                .expect("write size.json");
                        }

                        // FIXME should do a more graceful shutdown
                        ::std::process::exit(0);
                    },
                    Resized(w, h) => {
                        resize_tx.send((w, h)).expect("send new size");
                        processor.ctx.terminal.dirty = true;
                    },
                    KeyboardInput { input, .. } => {
                        let glutin::KeyboardInput { state, virtual_keycode, modifiers, .. } = input;
                        processor.process_key(state, virtual_keycode, &modifiers);
                        if state == ElementState::Pressed {
                            // Hide cursor while typing
                            *hide_cursor = true;
                        }
                    },
                    ReceivedCharacter(c) => {
                        processor.received_char(c);
                    },
                    MouseInput { state, button, modifiers, .. } => {
                        *hide_cursor = false;
                        processor.mouse_input(state, button, modifiers);
                        processor.ctx.terminal.dirty = true;
                    },
                    CursorMoved { position: (x, y), modifiers, .. } => {
                        let x = x as i32;
                        let y = y as i32;
                        let x = limit(x, 0, processor.ctx.size_info.width as i32);
                        let y = limit(y, 0, processor.ctx.size_info.height as i32);

                        *hide_cursor = false;
                        processor.mouse_moved(x as u32, y as u32, modifiers);

                        if !processor.ctx.selection.is_none() {
                            processor.ctx.terminal.dirty = true;
                        }
                    },
                    MouseWheel { delta, phase, modifiers, .. } => {
                        *hide_cursor = false;
                        processor.on_mouse_wheel(delta, phase, modifiers);
                    },
                    Refresh => {
                        processor.ctx.terminal.dirty = true;
                    },
                    Focused(is_focused) => {
                        *window_is_focused = is_focused;

                        if is_focused {
                            processor.ctx.terminal.dirty = true;
                            processor.ctx.terminal.next_is_urgent = Some(false);
                        } else {
                            processor.ctx.terminal.dirty = true;
                            *hide_cursor = false;
                        }

                        processor.on_focus_change(is_focused);
                    },
                    DroppedFile(path) => {
                        use input::ActionContext;
                        let path: String = path.to_string_lossy().into();
                        processor.ctx.write_to_pty(path.into_bytes());
                    }
                    _ => (),
                }
            },
            Event::Awakened => {
                processor.ctx.terminal.dirty = true;
            }
        }
    }

    /// Process events. When `wait_for_event` is set, this method is guaranteed
    /// to process at least one event.
    pub fn process_events<'a>(
        &mut self,
        term: &'a FairMutex<Term>,
        window: &mut Window
    ) -> MutexGuard<'a, Term> {
        // Terminal is lazily initialized the first time an event is returned
        // from the blocking WaitEventsIterator. Otherwise, the pty reader would
        // be blocked the entire time we wait for input!
        let mut terminal;

        self.pending_events.clear();

        {
            // Ditto on lazy initialization for context and processor.
            let context;
            let mut processor: input::Processor<ActionContext<N>>;

            let print_events = self.print_events;

            let ref_test = self.ref_test;
            let resize_tx = &self.resize_tx;

            if self.wait_for_event {
                // A Vec is used here since wait_events can potentially yield
                // multiple events before the interrupt is handled. For example,
                // Resize and Moved events.
                let pending_events = &mut self.pending_events;
                window.wait_events(|e| {
                    pending_events.push(e);
                    glutin::ControlFlow::Break
                });
            }

            terminal = term.lock();

            context = ActionContext {
                terminal: &mut terminal,
                notifier: &mut self.notifier,
                selection: &mut self.selection,
                mouse: &mut self.mouse,
                size_info: &self.size_info,
                selection_modified: false,
                received_count: &mut self.received_count,
                suppress_chars: &mut self.suppress_chars,
                last_modifiers: &mut self.last_modifiers,
            };

            processor = input::Processor {
                ctx: context,
                mouse_config: &self.mouse_config,
                key_bindings: &self.key_bindings[..],
                mouse_bindings: &self.mouse_bindings[..],
            };

            let mut window_is_focused = window.is_focused;

            // Scope needed to that hide_cursor isn't borrowed after the scope
            // ends.
            {
                let hide_cursor = &mut self.hide_cursor;
                let mut process = |event| {
                    if print_events {
                        println!("glutin event: {:?}", event);
                    }
                    Processor::handle_event(
                        &mut processor,
                        event,
                        ref_test,
                        resize_tx,
                        hide_cursor,
                        &mut window_is_focused,
                    );
                };

                for event in self.pending_events.drain(..) {
                    process(event);
                }

                window.poll_events(process);
            }

            if self.hide_cursor_when_typing {
                window.set_cursor_visible(!self.hide_cursor);
            }

            window.is_focused = window_is_focused;

            if processor.ctx.selection_modified {
                processor.ctx.terminal.dirty = true;
            }
        }

        self.wait_for_event = !terminal.dirty;

        terminal
    }

    pub fn update_config(&mut self, config: &Config) {
        self.key_bindings = config.key_bindings().to_vec();
        self.mouse_bindings = config.mouse_bindings().to_vec();
        self.mouse_config = config.mouse().to_owned();
    }
}
<commit_msg>Ignore mouse input if window is unfocused<commit_after>//! Process window events
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;
use std::sync::mpsc;
use std::time::{Instant};

use serde_json as json;
use parking_lot::MutexGuard;
use glutin::{self, ModifiersState, Event, ElementState};
use copypasta::{Clipboard, Load, Store};

use config::{self, Config};
use cli::Options;
use display::OnResize;
use index::{Line, Column, Side, Point};
use input::{self, MouseBinding, KeyBinding};
use selection::Selection;
use sync::FairMutex;
use term::{Term, SizeInfo, TermMode};
use util::limit;
use util::fmt::Red;
use window::Window;

/// Byte sequences are sent to a `Notify` in response to some events
pub trait Notify {
    /// Notify that an escape sequence should be written to the pty
    ///
    /// TODO this needs to be able to error somehow
    fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
}

pub struct ActionContext<'a, N: 'a> {
    pub notifier: &'a mut N,
    pub terminal: &'a mut Term,
    pub selection: &'a mut Option<Selection>,
    pub size_info: &'a SizeInfo,
    pub mouse: &'a mut Mouse,
    pub selection_modified: bool,
    pub received_count: &'a mut usize,
    pub suppress_chars: &'a mut bool,
    pub last_modifiers: &'a mut ModifiersState,
}

impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
    fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, val: B) {
        self.notifier.notify(val);
    }

    fn terminal_mode(&self) -> TermMode {
        *self.terminal.mode()
    }

    fn size_info(&self) -> SizeInfo {
        *self.size_info
    }

    fn copy_selection(&self, buffer: ::copypasta::Buffer) {
        if let Some(ref selection) = *self.selection {
            if let Some(ref span) = selection.to_span(self.terminal) {
                let buf = self.terminal.string_from_selection(&span);
                if !buf.is_empty() {
                    Clipboard::new()
                        .and_then(|mut clipboard| clipboard.store(buf, buffer))
                        .unwrap_or_else(|err| {
                            warn!("Error storing selection to clipboard. {}", Red(err));
                        });
                }
            }
        }
    }

    fn clear_selection(&mut self) {
        *self.selection = None;
        self.selection_modified = true;
    }

    fn update_selection(&mut self, point: Point, side: Side) {
        self.selection_modified = true;
        // Update selection if one exists
        if let Some(ref mut selection) = *self.selection {
            selection.update(point, side);
            return;
        }

        // Otherwise, start a regular selection
        self.simple_selection(point, side);
    }

    fn simple_selection(&mut self, point: Point, side: Side) {
        *self.selection = Some(Selection::simple(point, side));
        self.selection_modified = true;
    }

    fn semantic_selection(&mut self, point: Point) {
        *self.selection = Some(Selection::semantic(point, self.terminal));
        self.selection_modified = true;
    }

    fn line_selection(&mut self, point: Point) {
        *self.selection = Some(Selection::lines(point));
        self.selection_modified = true;
    }

    fn mouse_coords(&self) -> Option<Point> {
        self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize)
    }

    fn change_font_size(&mut self, delta: f32) {
        self.terminal.change_font_size(delta);
    }

    fn reset_font_size(&mut self) {
        self.terminal.reset_font_size();
    }

    #[inline]
    fn mouse_mut(&mut self) -> &mut Mouse {
        self.mouse
    }

    #[inline]
    fn received_count(&mut self) -> &mut usize {
        &mut self.received_count
    }

    #[inline]
    fn suppress_chars(&mut self) -> &mut bool {
        &mut self.suppress_chars
    }

    #[inline]
    fn last_modifiers(&mut self) -> &mut ModifiersState {
        &mut self.last_modifiers
    }
}

pub enum ClickState {
    None,
    Click,
    DoubleClick,
    TripleClick,
}

/// State of the mouse
pub struct Mouse {
    pub x: u32,
    pub y: u32,
    pub left_button_state: ElementState,
    pub middle_button_state: ElementState,
    pub right_button_state: ElementState,
    pub last_click_timestamp: Instant,
    pub click_state: ClickState,
    pub scroll_px: i32,
    pub line: Line,
    pub column: Column,
    pub cell_side: Side,
    pub lines_scrolled: f32,
}

impl Default for Mouse {
    fn default() -> Mouse {
        Mouse {
            x: 0,
            y: 0,
            last_click_timestamp: Instant::now(),
            left_button_state: ElementState::Released,
            middle_button_state: ElementState::Released,
            right_button_state: ElementState::Released,
            click_state: ClickState::None,
            scroll_px: 0,
            line: Line(0),
            column: Column(0),
            cell_side: Side::Left,
            lines_scrolled: 0.0,
        }
    }
}

/// The event processor
///
/// Stores some state from received events and dispatches actions when they are
/// triggered.
pub struct Processor<N> {
    key_bindings: Vec<KeyBinding>,
    mouse_bindings: Vec<MouseBinding>,
    mouse_config: config::Mouse,
    print_events: bool,
    wait_for_event: bool,
    notifier: N,
    mouse: Mouse,
    resize_tx: mpsc::Sender<(u32, u32)>,
    ref_test: bool,
    size_info: SizeInfo,
    pub selection: Option<Selection>,
    hide_cursor_when_typing: bool,
    hide_cursor: bool,
    received_count: usize,
    suppress_chars: bool,
    last_modifiers: ModifiersState,
    pending_events: Vec<Event>,
}

/// Notify that the terminal was resized
///
/// Currently this just forwards the notice to the input processor.
impl<N> OnResize for Processor<N> {
    fn on_resize(&mut self, size: &SizeInfo) {
        self.size_info = size.to_owned();
        self.selection = None;
    }
}

impl<N: Notify> Processor<N> {
    /// Create a new event processor
    ///
    /// Takes a writer which is expected to be hooked up to the write end of a
    /// pty.
    pub fn new(
        notifier: N,
        resize_tx: mpsc::Sender<(u32, u32)>,
        options: &Options,
        config: &Config,
        ref_test: bool,
        size_info: SizeInfo,
    ) -> Processor<N> {
        Processor {
            key_bindings: config.key_bindings().to_vec(),
            mouse_bindings: config.mouse_bindings().to_vec(),
            mouse_config: config.mouse().to_owned(),
            print_events: options.print_events,
            wait_for_event: true,
            notifier,
            resize_tx,
            ref_test,
            mouse: Default::default(),
            selection: None,
            size_info,
            hide_cursor_when_typing: config.hide_cursor_when_typing(),
            hide_cursor: false,
            received_count: 0,
            suppress_chars: false,
            last_modifiers: Default::default(),
            pending_events: Vec::with_capacity(4),
        }
    }

    /// Handle events from glutin
    ///
    /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
    fn handle_event<'a>(
        processor: &mut input::Processor<'a, ActionContext<'a, N>>,
        event: Event,
        ref_test: bool,
        resize_tx: &mpsc::Sender<(u32, u32)>,
        hide_cursor: &mut bool,
        window_is_focused: &mut bool,
    ) {
        match event {
            // Pass on device events
            Event::DeviceEvent { .. } | Event::Suspended { .. } => (),
            Event::WindowEvent { event, .. } => {
                use glutin::WindowEvent::*;
                match event {
                    CloseRequested => {
                        if ref_test {
                            // dump grid state
                            let grid = processor.ctx.terminal.grid();

                            let serialized_grid = json::to_string(&grid)
                                .expect("serialize grid");

                            let serialized_size = json::to_string(processor.ctx.terminal.size_info())
                                .expect("serialize size");

                            File::create("./grid.json")
                                .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
                                .expect("write grid.json");

                            File::create("./size.json")
                                .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
                                .expect("write size.json");
                        }

                        // FIXME should do a more graceful shutdown
                        ::std::process::exit(0);
                    },
                    Resized(w, h) => {
                        resize_tx.send((w, h)).expect("send new size");
                        processor.ctx.terminal.dirty = true;
                    },
                    KeyboardInput { input, .. } => {
                        let glutin::KeyboardInput { state, virtual_keycode, modifiers, .. } = input;
                        processor.process_key(state, virtual_keycode, &modifiers);
                        if state == ElementState::Pressed {
                            // Hide cursor while typing
                            *hide_cursor = true;
                        }
                    },
                    ReceivedCharacter(c) => {
                        processor.received_char(c);
                    },
                    MouseInput { state, button, modifiers, .. } => {
                        if *window_is_focused {
                            *hide_cursor = false;
                            processor.mouse_input(state, button, modifiers);
                            processor.ctx.terminal.dirty = true;
                        }
                    },
                    CursorMoved { position: (x, y), modifiers, .. } => {
                        let x = x as i32;
                        let y = y as i32;
                        let x = limit(x, 0, processor.ctx.size_info.width as i32);
                        let y = limit(y, 0, processor.ctx.size_info.height as i32);

                        *hide_cursor = false;
                        processor.mouse_moved(x as u32, y as u32, modifiers);

                        if !processor.ctx.selection.is_none() {
                            processor.ctx.terminal.dirty = true;
                        }
                    },
                    MouseWheel { delta, phase, modifiers, .. } => {
                        *hide_cursor = false;
                        processor.on_mouse_wheel(delta, phase, modifiers);
                    },
                    Refresh => {
                        processor.ctx.terminal.dirty = true;
                    },
                    Focused(is_focused) => {
                        *window_is_focused = is_focused;

                        if is_focused {
                            processor.ctx.terminal.dirty = true;
                            processor.ctx.terminal.next_is_urgent = Some(false);
                        } else {
                            processor.ctx.terminal.dirty = true;
                            *hide_cursor = false;
                        }

                        processor.on_focus_change(is_focused);
                    },
                    DroppedFile(path) => {
                        use input::ActionContext;
                        let path: String = path.to_string_lossy().into();
                        processor.ctx.write_to_pty(path.into_bytes());
                    }
                    _ => (),
                }
            },
            Event::Awakened => {
                processor.ctx.terminal.dirty = true;
            }
        }
    }

    /// Process events. When `wait_for_event` is set, this method is guaranteed
    /// to process at least one event.
    pub fn process_events<'a>(
        &mut self,
        term: &'a FairMutex<Term>,
        window: &mut Window
    ) -> MutexGuard<'a, Term> {
        // Terminal is lazily initialized the first time an event is returned
        // from the blocking WaitEventsIterator. Otherwise, the pty reader would
        // be blocked the entire time we wait for input!
        let mut terminal;

        self.pending_events.clear();

        {
            // Ditto on lazy initialization for context and processor.
            let context;
            let mut processor: input::Processor<ActionContext<N>>;

            let print_events = self.print_events;

            let ref_test = self.ref_test;
            let resize_tx = &self.resize_tx;

            if self.wait_for_event {
                // A Vec is used here since wait_events can potentially yield
                // multiple events before the interrupt is handled. For example,
                // Resize and Moved events.
                let pending_events = &mut self.pending_events;
                window.wait_events(|e| {
                    pending_events.push(e);
                    glutin::ControlFlow::Break
                });
            }

            terminal = term.lock();

            context = ActionContext {
                terminal: &mut terminal,
                notifier: &mut self.notifier,
                selection: &mut self.selection,
                mouse: &mut self.mouse,
                size_info: &self.size_info,
                selection_modified: false,
                received_count: &mut self.received_count,
                suppress_chars: &mut self.suppress_chars,
                last_modifiers: &mut self.last_modifiers,
            };

            processor = input::Processor {
                ctx: context,
                mouse_config: &self.mouse_config,
                key_bindings: &self.key_bindings[..],
                mouse_bindings: &self.mouse_bindings[..],
            };

            let mut window_is_focused = window.is_focused;

            // Scope needed to that hide_cursor isn't borrowed after the scope
            // ends.
            {
                let hide_cursor = &mut self.hide_cursor;
                let mut process = |event| {
                    if print_events {
                        println!("glutin event: {:?}", event);
                    }
                    Processor::handle_event(
                        &mut processor,
                        event,
                        ref_test,
                        resize_tx,
                        hide_cursor,
                        &mut window_is_focused,
                    );
                };

                for event in self.pending_events.drain(..) {
                    process(event);
                }

                window.poll_events(process);
            }

            if self.hide_cursor_when_typing {
                window.set_cursor_visible(!self.hide_cursor);
            }

            window.is_focused = window_is_focused;

            if processor.ctx.selection_modified {
                processor.ctx.terminal.dirty = true;
            }
        }

        self.wait_for_event = !terminal.dirty;

        terminal
    }

    pub fn update_config(&mut self, config: &Config) {
        self.key_bindings = config.key_bindings().to_vec();
        self.mouse_bindings = config.mouse_bindings().to_vec();
        self.mouse_config = config.mouse().to_owned();
    }
}
<|endoftext|>


<commit_before>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to use `ggez`'s built in event loop, you can
//! write your own mainloop and check for events on your own.  This is
//! not particularly hard, there's nothing special about the
//! `EventHandler` trait.  It just tries to simplify the process a
//! little.  For examples of how to write your own main loop, see the
//! source code for this module, or the [`eventloop`
//! example](https://github.com/ggez/ggez/blob/master/examples/eventloop.rs).

use gilrs;
use winit::{self, dpi};

// TODO LATER: I kinda hate all these re-exports.  I kinda hate
// a lot of the details of the `EventHandler` and input now though,
// and look forward to ripping it all out and replacing it with newer winit.

/// A mouse button.
pub use winit::event::MouseButton;

/// An analog axis of some device (gamepad thumbstick, joystick...).
pub use gilrs::Axis;
/// A button of some device (gamepad, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::event::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}
pub use crate::input::gamepad::GamepadId;
pub use crate::input::keyboard::{KeyCode, KeyMods};

use self::winit_event::*;
/// `winit` event loop.
pub use winit::event_loop::{ControlFlow, EventLoop};

use crate::context::Context;
use crate::error::GameResult;

/// A trait defining event callbacks.  This is your primary interface with
/// `ggez`'s event loop.  Implement this trait for a type and
/// override at least the [`update()`](#tymethod.update) and
/// [`draw()`](#tymethod.draw) methods, then pass it to
/// [`event::run()`](fn.run.html) to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// [`key_down_event()`](#tymethod.key_down_event), which will by
/// default exit the game if the escape key is pressed.  Just
/// override the methods you want to use.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// [`graphics::clear()`](../graphics/fn.clear.html) and end it
    /// with [`graphics::present()`](../graphics/fn.present.html) and
    /// maybe [`timer::yield_now()`](../timer/fn.yield_now.html).
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// mouse entered or left window area
    fn mouse_enter_or_leave(&mut self, _ctx: &mut Context, _entered: bool) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    ///
    /// The default implementation of this will call `ggez::event::quit()`
    /// when the escape key is pressed.  If you override this with
    /// your own event handler you have to re-implment that
    /// functionality yourself.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A gamepad button was pressed; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad button was released; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad axis moved; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: GamepadId) {
    }

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit (the quit event is cancelled).
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via [`graphics::set_mode()`](../graphics/fn.set_mode.html).
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the [`timer`](../timer/index.html) module for more info.
pub fn run<S: 'static>(mut ctx: Context, event_loop: EventLoop<()>, mut state: S) -> !
where
    S: EventHandler,
{
    use crate::input::{keyboard, mouse};

    event_loop.run(move |event, _, control_flow| {
        if !ctx.continuing {
            *control_flow = ControlFlow::Exit;
            return;
        }

        *control_flow = ControlFlow::Poll;

        let ctx = &mut ctx;
        let state = &mut state;

        ctx.process_event(&event);
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Resized(logical_size) => {
                    // let actual_size = logical_size;
                    state.resize_event(ctx, logical_size.width as f32, logical_size.height as f32);
                }
                WindowEvent::CloseRequested => {
                    if !state.quit_event(ctx) {
                        quit(ctx);
                    }
                }
                WindowEvent::Focused(gained) => {
                    state.focus_event(ctx, gained);
                }
                WindowEvent::ReceivedCharacter(ch) => {
                    state.text_input_event(ctx, ch);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Pressed,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    let repeat = keyboard::is_key_repeated(ctx);
                    state.key_down_event(ctx, keycode, modifiers.into(), repeat);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Released,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    state.key_up_event(ctx, keycode, modifiers.into());
                }
                WindowEvent::MouseWheel { delta, .. } => {
                    let (x, y) = match delta {
                        MouseScrollDelta::LineDelta(x, y) => (x, y),
                        MouseScrollDelta::PixelDelta(pos) => {
                            let scale_factor = ctx.gfx_context.window.window().scale_factor();
                            let dpi::LogicalPosition { x, y } = pos.to_logical::<f32>(scale_factor);
                            (x, y)
                        }
                    };
                    state.mouse_wheel_event(ctx, x, y);
                }
                WindowEvent::MouseInput {
                    state: element_state,
                    button,
                    ..
                } => {
                    let position = mouse::position(ctx);
                    match element_state {
                        ElementState::Pressed => {
                            state.mouse_button_down_event(ctx, button, position.x, position.y)
                        }
                        ElementState::Released => {
                            state.mouse_button_up_event(ctx, button, position.x, position.y)
                        }
                    }
                }
                WindowEvent::CursorMoved { .. } => {
                    let position = mouse::position(ctx);
                    let delta = mouse::delta(ctx);
                    state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                }
                _x => {
                    // trace!("ignoring window event {:?}", x);
                }
            },
            Event::DeviceEvent { event, .. } => match event {
                _ => (),
            },
            Event::Resumed => (),
            Event::Suspended => (),
            Event::NewEvents(_) => (),
            Event::UserEvent(_) => (),
            Event::MainEventsCleared => {
                // If you are writing your own event loop, make sure
                // you include `timer_context.tick()` and
                // `ctx.process_event()` calls.  These update ggez's
                // internal state however necessary.
                ctx.timer_context.tick();

                if let Err(e) = state.update(ctx) {
                    error!("Error on EventHandler::update(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }

                if let Err(e) = state.draw(ctx) {
                    error!("Error on EventHandler::draw(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }
            Event::RedrawRequested(_) => (),
            Event::RedrawEventsCleared => (),
            Event::LoopDestroyed => (),
        }

        // Handle gamepad events if necessary.
        if ctx.conf.modules.gamepad {
            while let Some(gilrs::Event { id, event, .. }) = ctx.gamepad_context.next_event() {
                match event {
                    gilrs::EventType::ButtonPressed(button, _) => {
                        state.gamepad_button_down_event(ctx, button, GamepadId(id));
                    }
                    gilrs::EventType::ButtonReleased(button, _) => {
                        state.gamepad_button_up_event(ctx, button, GamepadId(id));
                    }
                    gilrs::EventType::AxisChanged(axis, value, _) => {
                        state.gamepad_axis_event(ctx, axis, value, GamepadId(id));
                    }
                    _ => {}
                }
            }
        }
    });
}
<commit_msg>Removes redundant imports on event.rs<commit_after>//! The `event` module contains traits and structs to actually run your game mainloop
//! and handle top-level state, as well as handle input events such as keyboard
//! and mouse.
//!
//! If you don't want to use `ggez`'s built in event loop, you can
//! write your own mainloop and check for events on your own.  This is
//! not particularly hard, there's nothing special about the
//! `EventHandler` trait.  It just tries to simplify the process a
//! little.  For examples of how to write your own main loop, see the
//! source code for this module, or the [`eventloop`
//! example](https://github.com/ggez/ggez/blob/master/examples/eventloop.rs).

use winit::{self, dpi};

// TODO LATER: I kinda hate all these re-exports.  I kinda hate
// a lot of the details of the `EventHandler` and input now though,
// and look forward to ripping it all out and replacing it with newer winit.

/// A mouse button.
pub use winit::event::MouseButton;

/// An analog axis of some device (gamepad thumbstick, joystick...).
pub use gilrs::Axis;
/// A button of some device (gamepad, joystick...).
pub use gilrs::Button;

/// `winit` events; nested in a module for re-export neatness.
pub mod winit_event {
    pub use super::winit::event::{
        DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, MouseScrollDelta,
        TouchPhase, WindowEvent,
    };
}
pub use crate::input::gamepad::GamepadId;
pub use crate::input::keyboard::{KeyCode, KeyMods};

use self::winit_event::*;
/// `winit` event loop.
pub use winit::event_loop::{ControlFlow, EventLoop};

use crate::context::Context;
use crate::error::GameResult;

/// A trait defining event callbacks.  This is your primary interface with
/// `ggez`'s event loop.  Implement this trait for a type and
/// override at least the [`update()`](#tymethod.update) and
/// [`draw()`](#tymethod.draw) methods, then pass it to
/// [`event::run()`](fn.run.html) to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// [`key_down_event()`](#tymethod.key_down_event), which will by
/// default exit the game if the escape key is pressed.  Just
/// override the methods you want to use.
pub trait EventHandler {
    /// Called upon each logic update to the game.
    /// This should be where the game's logic takes place.
    fn update(&mut self, _ctx: &mut Context) -> GameResult;

    /// Called to do the drawing of your game.
    /// You probably want to start this with
    /// [`graphics::clear()`](../graphics/fn.clear.html) and end it
    /// with [`graphics::present()`](../graphics/fn.present.html) and
    /// maybe [`timer::yield_now()`](../timer/fn.yield_now.html).
    fn draw(&mut self, _ctx: &mut Context) -> GameResult;

    /// A mouse button was pressed
    fn mouse_button_down_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// A mouse button was released
    fn mouse_button_up_event(
        &mut self,
        _ctx: &mut Context,
        _button: MouseButton,
        _x: f32,
        _y: f32,
    ) {
    }

    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
    /// and relative x and y coordinates compared to its last position.
    fn mouse_motion_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32, _dx: f32, _dy: f32) {}

    /// mouse entered or left window area
    fn mouse_enter_or_leave(&mut self, _ctx: &mut Context, _entered: bool) {}

    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
    /// or horizontally (x, positive to the right and negative to the left).
    fn mouse_wheel_event(&mut self, _ctx: &mut Context, _x: f32, _y: f32) {}

    /// A keyboard button was pressed.
    ///
    /// The default implementation of this will call `ggez::event::quit()`
    /// when the escape key is pressed.  If you override this with
    /// your own event handler you have to re-implment that
    /// functionality yourself.
    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        _keymods: KeyMods,
        _repeat: bool,
    ) {
        if keycode == KeyCode::Escape {
            quit(ctx);
        }
    }

    /// A keyboard button was released.
    fn key_up_event(&mut self, _ctx: &mut Context, _keycode: KeyCode, _keymods: KeyMods) {}

    /// A unicode character was received, usually from keyboard input.
    /// This is the intended way of facilitating text input.
    fn text_input_event(&mut self, _ctx: &mut Context, _character: char) {}

    /// A gamepad button was pressed; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_down_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad button was released; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_button_up_event(&mut self, _ctx: &mut Context, _btn: Button, _id: GamepadId) {}

    /// A gamepad axis moved; `id` identifies which gamepad.
    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
    /// the gamepad.
    fn gamepad_axis_event(&mut self, _ctx: &mut Context, _axis: Axis, _value: f32, _id: GamepadId) {
    }

    /// Called when the window is shown or hidden.
    fn focus_event(&mut self, _ctx: &mut Context, _gained: bool) {}

    /// Called upon a quit event.  If it returns true,
    /// the game does not exit (the quit event is cancelled).
    fn quit_event(&mut self, _ctx: &mut Context) -> bool {
        debug!("quit_event() callback called, quitting...");
        false
    }

    /// Called when the user resizes the window, or when it is resized
    /// via [`graphics::set_mode()`](../graphics/fn.set_mode.html).
    fn resize_event(&mut self, _ctx: &mut Context, _width: f32, _height: f32) {}
}

/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
pub fn quit(ctx: &mut Context) {
    ctx.continuing = false;
}

/// Runs the game's main loop, calling event callbacks on the given state
/// object as events occur.
///
/// It does not try to do any type of framerate limiting.  See the
/// documentation for the [`timer`](../timer/index.html) module for more info.
pub fn run<S: 'static>(mut ctx: Context, event_loop: EventLoop<()>, mut state: S) -> !
where
    S: EventHandler,
{
    use crate::input::{keyboard, mouse};

    event_loop.run(move |event, _, control_flow| {
        if !ctx.continuing {
            *control_flow = ControlFlow::Exit;
            return;
        }

        *control_flow = ControlFlow::Poll;

        let ctx = &mut ctx;
        let state = &mut state;

        ctx.process_event(&event);
        match event {
            Event::WindowEvent { event, .. } => match event {
                WindowEvent::Resized(logical_size) => {
                    // let actual_size = logical_size;
                    state.resize_event(ctx, logical_size.width as f32, logical_size.height as f32);
                }
                WindowEvent::CloseRequested => {
                    if !state.quit_event(ctx) {
                        quit(ctx);
                    }
                }
                WindowEvent::Focused(gained) => {
                    state.focus_event(ctx, gained);
                }
                WindowEvent::ReceivedCharacter(ch) => {
                    state.text_input_event(ctx, ch);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Pressed,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    let repeat = keyboard::is_key_repeated(ctx);
                    state.key_down_event(ctx, keycode, modifiers.into(), repeat);
                }
                WindowEvent::KeyboardInput {
                    input:
                        KeyboardInput {
                            state: ElementState::Released,
                            virtual_keycode: Some(keycode),
                            modifiers,
                            ..
                        },
                    ..
                } => {
                    state.key_up_event(ctx, keycode, modifiers.into());
                }
                WindowEvent::MouseWheel { delta, .. } => {
                    let (x, y) = match delta {
                        MouseScrollDelta::LineDelta(x, y) => (x, y),
                        MouseScrollDelta::PixelDelta(pos) => {
                            let scale_factor = ctx.gfx_context.window.window().scale_factor();
                            let dpi::LogicalPosition { x, y } = pos.to_logical::<f32>(scale_factor);
                            (x, y)
                        }
                    };
                    state.mouse_wheel_event(ctx, x, y);
                }
                WindowEvent::MouseInput {
                    state: element_state,
                    button,
                    ..
                } => {
                    let position = mouse::position(ctx);
                    match element_state {
                        ElementState::Pressed => {
                            state.mouse_button_down_event(ctx, button, position.x, position.y)
                        }
                        ElementState::Released => {
                            state.mouse_button_up_event(ctx, button, position.x, position.y)
                        }
                    }
                }
                WindowEvent::CursorMoved { .. } => {
                    let position = mouse::position(ctx);
                    let delta = mouse::delta(ctx);
                    state.mouse_motion_event(ctx, position.x, position.y, delta.x, delta.y);
                }
                _x => {
                    // trace!("ignoring window event {:?}", x);
                }
            },
            Event::DeviceEvent { event, .. } => match event {
                _ => (),
            },
            Event::Resumed => (),
            Event::Suspended => (),
            Event::NewEvents(_) => (),
            Event::UserEvent(_) => (),
            Event::MainEventsCleared => {
                // If you are writing your own event loop, make sure
                // you include `timer_context.tick()` and
                // `ctx.process_event()` calls.  These update ggez's
                // internal state however necessary.
                ctx.timer_context.tick();

                if let Err(e) = state.update(ctx) {
                    error!("Error on EventHandler::update(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }

                if let Err(e) = state.draw(ctx) {
                    error!("Error on EventHandler::draw(): {:?}", e);
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }
            Event::RedrawRequested(_) => (),
            Event::RedrawEventsCleared => (),
            Event::LoopDestroyed => (),
        }

        // Handle gamepad events if necessary.
        if ctx.conf.modules.gamepad {
            while let Some(gilrs::Event { id, event, .. }) = ctx.gamepad_context.next_event() {
                match event {
                    gilrs::EventType::ButtonPressed(button, _) => {
                        state.gamepad_button_down_event(ctx, button, GamepadId(id));
                    }
                    gilrs::EventType::ButtonReleased(button, _) => {
                        state.gamepad_button_up_event(ctx, button, GamepadId(id));
                    }
                    gilrs::EventType::AxisChanged(axis, value, _) => {
                        state.gamepad_axis_event(ctx, axis, value, GamepadId(id));
                    }
                    _ => {}
                }
            }
        }
    });
}
<|endoftext|>


<commit_before>/// Compute the real-valued digamma function.
///
/// The formula is as follows:
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// ## Examples
///
/// ```
/// use special::digamma;
///
/// const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
/// assert!((digamma(1.0) + EULER_MASCHERONI).abs() < 1e-15);
/// ```
///
/// ## References
///
/// 1. M. J. Beal, Variational algorithms for approximate Bayesian inference.
///    University of London, 2003, pp. 265–266.
pub fn digamma(x: f64)-> f64 {
    macro_rules! evaluate_polynomial(
        ($x:expr, $coefficients:expr) => (
            $coefficients.iter().rev().fold(0.0, |sum, &c| $x * sum + c)
        );
    );

    if x <= 8.0 {
        return digamma(x + 1.0) - x.recip();
    }

    let inv_x = x.recip();
    let inv_x_2 = inv_x * inv_x;
    x.ln() - 0.5 * inv_x - inv_x_2 * evaluate_polynomial!(inv_x_2, [
        1.0 / 12.0, -1.0 / 120.0, 1.0 / 252.0, -1.0 / 240.0,
        5.0 / 660.0, -691.0 / 32760.0, 1.0 / 12.0, -3617.0 / 8160.0,
    ])
}

/// Compute the regularized lower incomplete gamma function.
///
/// The formula is as follows:
///
/// ```math
///                          ∞
///           γ(x, p)    1   /
/// P(x, p) = ------- = ---- | t^(p-1) e^(-t) dt
///            Γ(p)     Γ(p) /
///                          0
/// ```
///
/// where γ is the incomplete lower gamma function, and Γ is the complete gamma
/// function.
///
/// The code is based on a [C implementation][1] by John Burkardt. The original
/// algorithm was published in Applied Statistics and is known as
/// [Algorithm AS 239][2].
///
/// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa239/asa239.html
/// [2]: http://www.jstor.org/stable/2347328
pub fn inc_gamma(x: f64, p: f64) -> f64 {
    debug_assert!(x >= 0.0 && p > 0.0);

    const ELIMIT: f64 = -88.0;
    const OFLO: f64 = 1.0e+37;
    const TOL: f64 = 1.0e-14;
    const XBIG: f64 = 1.0e+08;

    if x == 0.0 {
        return 0.0;
    }

    // For `p ≥ 1000`, the original algorithm uses an approximation shown below.
    // However, it introduces a substantial accuracy loss.
    //
    // ```
    // use m::erf;
    // use std::f64::consts::FRAC_1_SQRT_2;
    //
    // const PLIMIT: f64 = 1000.0;
    //
    // if PLIMIT < p {
    //     let pn1 = 3.0 * p.sqrt() * ((x / p).powf(1.0 / 3.0) + 1.0 / (9.0 * p) - 1.0);
    //     return 0.5 * (1.0 + unsafe { erf(FRAC_1_SQRT_2 * pn1) });
    // }
    // ```

    if XBIG < x {
        return 1.0;
    }

    if x <= 1.0 || x < p {
        let mut arg = p * x.ln() - x - ln_gamma(p + 1.0).0;
        let mut c = 1.0;
        let mut value = 1.0;
        let mut a = p;

        loop {
            a += 1.0;
            c *= x / a;
            value += c;

            if c <= TOL {
                break;
            }
        }

        arg += value.ln();

        if ELIMIT <= arg {
            return arg.exp();
        } else {
            return 0.0;
        };
    } else {
        let mut arg = p * x.ln() - x - ln_gamma(p).0;
        let mut a = 1.0 - p;
        let mut b = a + x + 1.0;
        let mut c = 0.0;
        let mut pn1 = 1.0;
        let mut pn2 = x;
        let mut pn3 = x + 1.0;
        let mut pn4 = x * b;
        let mut value = pn3 / pn4;

        loop {
            a += 1.0;
            b += 2.0;
            c += 1.0;
            let an = a * c;
            let pn5 = b * pn3 - an * pn1;
            let pn6 = b * pn4 - an * pn2;

            if pn6 != 0.0 {
                let rn = pn5 / pn6;
                if (value - rn).abs() <= TOL.min(TOL * rn) {
                    break;
                }
                value = rn;
            }

            pn1 = pn3;
            pn2 = pn4;
            pn3 = pn5;
            pn4 = pn6;

            if OFLO <= pn5.abs() {
                pn1 /= OFLO;
                pn2 /= OFLO;
                pn3 /= OFLO;
                pn4 /= OFLO;
            }
        }

        arg += value.ln();

        if ELIMIT <= arg {
            return 1.0 - arg.exp();
        } else {
            return 1.0;
        }
    }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    use m::lgamma_r;
    let mut sign: i32 = 0;
    let value = unsafe { lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    use assert;

    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - EULER_MASCHERONI, super::digamma(0.25));
    }

    #[test]
    fn inc_gamma_small_p() {
        let p = 4.2;
        let x = vec![
            0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
            5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5,
        ];
        let y = vec![
            0.000000000000000e+00, 1.118818097571853e-03, 1.386936454406691e-02,
            5.173931341260211e-02, 1.186345016135447e-01, 2.092219100370761e-01,
            3.137074857845146e-01, 4.219736975484903e-01, 5.258832878449179e-01,
            6.200417684429613e-01, 7.016346974530381e-01, 7.698559854309833e-01,
            8.252531208548146e-01, 8.691540627528154e-01, 9.032348314835232e-01,
            9.292289044193606e-01, 9.487539837941871e-01, 9.632249236076943e-01,
            9.738240752336722e-01, 9.815062931491536e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(x, p)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-14);
    }

    #[test]
    fn inc_gamma_large_p() {
        let p = 1500.0;
        let x = vec![
            1400.0, 1410.0, 1420.0, 1430.0, 1440.0, 1450.0, 1460.0, 1470.0, 1480.0, 1490.0,
            1500.0, 1510.0, 1520.0, 1530.0, 1540.0, 1550.0, 1560.0, 1570.0, 1580.0, 1590.0,
        ];
        let y = vec![
            4.231080348517120e-03, 9.056183893278287e-03, 1.809200095269094e-02,
            3.380047876608895e-02, 5.917825204288418e-02, 9.731671903009434e-02,
            1.506860564044825e-01, 2.202940362119810e-01, 3.049926190158564e-01,
            4.012305141433336e-01, 5.034335611603484e-01, 6.049687028759408e-01,
            6.994146092246781e-01, 7.817404371226420e-01, 8.490443067241588e-01,
            9.006922020203059e-01, 9.379249194843459e-01, 9.631597573132408e-01,
            9.792520392189441e-01, 9.889149370075309e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(x, p)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-12);
    }
}
<commit_msg>Fix the description of inc_gamma<commit_after>/// Compute the real-valued digamma function.
///
/// The formula is as follows:
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// ## Examples
///
/// ```
/// use special::digamma;
///
/// const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
/// assert!((digamma(1.0) + EULER_MASCHERONI).abs() < 1e-15);
/// ```
///
/// ## References
///
/// 1. M. J. Beal, Variational algorithms for approximate Bayesian inference.
///    University of London, 2003, pp. 265–266.
pub fn digamma(x: f64)-> f64 {
    macro_rules! evaluate_polynomial(
        ($x:expr, $coefficients:expr) => (
            $coefficients.iter().rev().fold(0.0, |sum, &c| $x * sum + c)
        );
    );

    if x <= 8.0 {
        return digamma(x + 1.0) - x.recip();
    }

    let inv_x = x.recip();
    let inv_x_2 = inv_x * inv_x;
    x.ln() - 0.5 * inv_x - inv_x_2 * evaluate_polynomial!(inv_x_2, [
        1.0 / 12.0, -1.0 / 120.0, 1.0 / 252.0, -1.0 / 240.0,
        5.0 / 660.0, -691.0 / 32760.0, 1.0 / 12.0, -3617.0 / 8160.0,
    ])
}

/// Compute the regularized lower incomplete gamma function.
///
/// The formula is as follows:
///
/// ```math
///           γ(x, p)    1   x
/// P(x, p) = ------- = ---- ∫ t^(p-1) e^(-t) dt
///            Γ(p)     Γ(p) 0
/// ```
///
/// where γ is the incomplete lower gamma function, and Γ is the complete gamma
/// function.
///
/// The code is based on a [C implementation][1] by John Burkardt. The original
/// algorithm was published in Applied Statistics and is known as
/// [Algorithm AS 239][2].
///
/// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa239/asa239.html
/// [2]: http://www.jstor.org/stable/2347328
pub fn inc_gamma(x: f64, p: f64) -> f64 {
    debug_assert!(x >= 0.0 && p > 0.0);

    const ELIMIT: f64 = -88.0;
    const OFLO: f64 = 1.0e+37;
    const TOL: f64 = 1.0e-14;
    const XBIG: f64 = 1.0e+08;

    if x == 0.0 {
        return 0.0;
    }

    // For `p ≥ 1000`, the original algorithm uses an approximation shown below.
    // However, it introduces a substantial accuracy loss.
    //
    // ```
    // use m::erf;
    // use std::f64::consts::FRAC_1_SQRT_2;
    //
    // const PLIMIT: f64 = 1000.0;
    //
    // if PLIMIT < p {
    //     let pn1 = 3.0 * p.sqrt() * ((x / p).powf(1.0 / 3.0) + 1.0 / (9.0 * p) - 1.0);
    //     return 0.5 * (1.0 + unsafe { erf(FRAC_1_SQRT_2 * pn1) });
    // }
    // ```

    if XBIG < x {
        return 1.0;
    }

    if x <= 1.0 || x < p {
        let mut arg = p * x.ln() - x - ln_gamma(p + 1.0).0;
        let mut c = 1.0;
        let mut value = 1.0;
        let mut a = p;

        loop {
            a += 1.0;
            c *= x / a;
            value += c;

            if c <= TOL {
                break;
            }
        }

        arg += value.ln();

        if ELIMIT <= arg {
            return arg.exp();
        } else {
            return 0.0;
        };
    } else {
        let mut arg = p * x.ln() - x - ln_gamma(p).0;
        let mut a = 1.0 - p;
        let mut b = a + x + 1.0;
        let mut c = 0.0;
        let mut pn1 = 1.0;
        let mut pn2 = x;
        let mut pn3 = x + 1.0;
        let mut pn4 = x * b;
        let mut value = pn3 / pn4;

        loop {
            a += 1.0;
            b += 2.0;
            c += 1.0;
            let an = a * c;
            let pn5 = b * pn3 - an * pn1;
            let pn6 = b * pn4 - an * pn2;

            if pn6 != 0.0 {
                let rn = pn5 / pn6;
                if (value - rn).abs() <= TOL.min(TOL * rn) {
                    break;
                }
                value = rn;
            }

            pn1 = pn3;
            pn2 = pn4;
            pn3 = pn5;
            pn4 = pn6;

            if OFLO <= pn5.abs() {
                pn1 /= OFLO;
                pn2 /= OFLO;
                pn3 /= OFLO;
                pn4 /= OFLO;
            }
        }

        arg += value.ln();

        if ELIMIT <= arg {
            return 1.0 - arg.exp();
        } else {
            return 1.0;
        }
    }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    use m::lgamma_r;
    let mut sign: i32 = 0;
    let value = unsafe { lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    use assert;

    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - EULER_MASCHERONI, super::digamma(0.25));
    }

    #[test]
    fn inc_gamma_small_p() {
        let p = 4.2;
        let x = vec![
            0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
            5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5,
        ];
        let y = vec![
            0.000000000000000e+00, 1.118818097571853e-03, 1.386936454406691e-02,
            5.173931341260211e-02, 1.186345016135447e-01, 2.092219100370761e-01,
            3.137074857845146e-01, 4.219736975484903e-01, 5.258832878449179e-01,
            6.200417684429613e-01, 7.016346974530381e-01, 7.698559854309833e-01,
            8.252531208548146e-01, 8.691540627528154e-01, 9.032348314835232e-01,
            9.292289044193606e-01, 9.487539837941871e-01, 9.632249236076943e-01,
            9.738240752336722e-01, 9.815062931491536e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(x, p)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-14);
    }

    #[test]
    fn inc_gamma_large_p() {
        let p = 1500.0;
        let x = vec![
            1400.0, 1410.0, 1420.0, 1430.0, 1440.0, 1450.0, 1460.0, 1470.0, 1480.0, 1490.0,
            1500.0, 1510.0, 1520.0, 1530.0, 1540.0, 1550.0, 1560.0, 1570.0, 1580.0, 1590.0,
        ];
        let y = vec![
            4.231080348517120e-03, 9.056183893278287e-03, 1.809200095269094e-02,
            3.380047876608895e-02, 5.917825204288418e-02, 9.731671903009434e-02,
            1.506860564044825e-01, 2.202940362119810e-01, 3.049926190158564e-01,
            4.012305141433336e-01, 5.034335611603484e-01, 6.049687028759408e-01,
            6.994146092246781e-01, 7.817404371226420e-01, 8.490443067241588e-01,
            9.006922020203059e-01, 9.379249194843459e-01, 9.631597573132408e-01,
            9.792520392189441e-01, 9.889149370075309e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(x, p)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-12);
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash;

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Debug, Clone)]
pub struct ConnectedComponent {
    id: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
    }
}

#[derive(Debug)]
pub struct Graph {
    pub components: HashMap<usize, ConnectedComponent>,
    pub neighbours: HashMap<usize, HashSet<usize>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue;
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            id: counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    return components;
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> =
            components_and_neighbours
                .iter()
                .flat_map(|(component, _)| {
                    component
                        .cells
                        .iter()
                        .map(|cell| (cell.clone(), component.clone()))
                        .collect::<Vec<(Position, ConnectedComponent)>>()
                })
                .collect();

        let mut neighbours: HashMap<usize, HashSet<usize>> = HashMap::new();

        for (component, neighbour_cells) in &components_and_neighbours {
            let mut neighbour_components = HashSet::new();

            for cell in neighbour_cells {
                let position = Position {
                    column: cell % grid.number_of_columns,
                    row: cell / grid.number_of_columns,
                };
                neighbour_components.insert(map_cell_to_component[&position].id);
            }
            neighbours.insert(component.id, neighbour_components);
        }

        let mut components = HashMap::with_capacity(components_and_neighbours.len());

        for (c, _) in components_and_neighbours.into_iter() {
            components.insert(c.id, c);
        }

        Self {
            components,
            neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &self.components[component].cells {
                cells[position.column + position.row * columns] = self.components[component].colour;
            }
        }

        Grid {
            number_of_rows: rows,
            number_of_columns: columns,
            cells,
        }
    }

    pub fn find_component(&self, position: &Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if self.components[component].cells.contains(&position) {
                return &self.components[component];
            }
        }

        unreachable!()
    }

    pub fn change_colour_of_component_at(&mut self, position: &Position, colour: Colour) {
        let component_id = self.find_component(position).id;

        // Remove the component which is to change colour
        let mut component = self.components.remove(&component_id).unwrap();
        let mut neighbours = self.neighbours.remove(&component_id).unwrap();

        // Gather new cells for that component by combinging the cells of all
        // its neighbours which already have the new colour.
        let mut new_cells = HashSet::new();
        // Gather the set of its new neighbours which is just the union of the
        // sets of neighbours its neighbours with the new colour have.
        let mut new_neighbours = HashSet::new();
        let mut removed_neighbours = HashSet::new();

        for id in &neighbours {
            if *id != component_id && self.components[id].colour == colour {
                let neighbour_component = self.components.remove(id).unwrap();
                new_cells.extend(neighbour_component.cells.into_iter());
                let set_of_neighbour_ids = self.neighbours.remove(&neighbour_component.id).unwrap();
                new_neighbours.extend(set_of_neighbour_ids.into_iter());
                removed_neighbours.insert(*id);
            }
        }

        // Add new neighbours
        neighbours.extend(new_neighbours.clone().into_iter());
        // Remove the ID of the component itself
        neighbours.remove(&component_id);
        // and the IDs of the neighbours that were merged into the component
        neighbours = neighbours.difference(&removed_neighbours).map(|&x| x).collect();

        // Add the cells from the neighbours which now have the new colour
        component.cells.extend(new_cells.into_iter());
        // and update the colour.  With this, the component itself is done.
        component.colour = colour;

        // Fix the neighbour sets for all the remaining components
        // All we have to do here is replace any of the indices in new_neighbours with component_id.
        for (_, n) in self.neighbours.iter_mut() {
            for incorporated_neighbour_id in &removed_neighbours {
                n.remove(incorporated_neighbour_id);
            }
            n.insert(component_id);
        }

        // Put the component and neighbours back into the Graph
        self.components.entry(component_id).or_insert(component);
        self.neighbours.entry(component_id).or_insert(neighbours);
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red; 4],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }

    #[test]
    fn should_have_same_keys_for_components_and_neighbours_maps() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let components_keys: HashSet<_> = graph.components.keys().collect();
        let neighbours_keys: HashSet<_> = graph.neighbours.keys().collect();
        assert_eq!(components_keys, neighbours_keys);
    }

    #[test]
    fn should_contain_exactly_the_component_ids_as_keys() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_keys: HashSet<_> = graph.components.keys().collect();
        let component_ids: HashSet<_> = graph.components.values().map(|x| &x.id).collect();
        assert_eq!(component_keys, component_ids);

        for (id, component) in graph.components {
            assert_eq!(id, component.id);
        }
    }

    #[test]
    fn should_contain_only_component_ids_as_values_in_neighbours_map() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_ids: HashSet<_> = graph.components.keys().map(|&x| x).collect();

        for (_, neighbours) in graph.neighbours {
            assert_eq!(neighbours.difference(&component_ids).collect::<HashSet<_>>().len(), 0);
        }
    }
}
<commit_msg>Remove redundant return statement<commit_after>use std::collections::{HashMap, HashSet, VecDeque};
use std::hash::Hash;

use crate::colour::Colour;
use crate::grid::Grid;

// Represent the state of the game as a graph.  One node for each cell.  There is an edge between
// two cells if and only if they are the same colour and have a distance of 1 according to the
// Manhattan metric.
//
// The game has only one real operation (i.e. not counting level generation): Switching the colour
// of the connected component containing the top left cell to whichever colour the clicked cell
// has.  This results in said component growing by every component it neighbours which has its new
// colour.  In essence, the aim of the gaim is to join connected components until only one is
// left.  Fewer clicks is better.
//
// So, we represent the game state as a collection of connected components, each of which has a
// colour, a list of coordinates of the constituent cells, and a list of it s neighbours.  As we
// do all our operations on connected components, we actually work not with the graph of
// neighbouring cells but with a graph of connected components.  The graph of connected components
// is made up of one node representing each connected component and an edge between any two
// connected components that have cells which share an edge, i.e. two cells which would have been
// connected by an edge in the original graph if they had had the same colour (which they did
// not).

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Position {
    pub row: usize,
    pub column: usize,
}

#[derive(Debug, Clone)]
pub struct ConnectedComponent {
    id: usize,
    pub colour: Colour,
    pub cells: HashSet<Position>,
}

impl PartialEq for ConnectedComponent {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for ConnectedComponent {}

impl Hash for ConnectedComponent {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state);
    }
}

#[derive(Debug)]
pub struct Graph {
    pub components: HashMap<usize, ConnectedComponent>,
    pub neighbours: HashMap<usize, HashSet<usize>>,
}

fn find_connected_components(grid: &Grid) -> Vec<(ConnectedComponent, HashSet<usize>)> {
    let rows = grid.number_of_rows;
    let columns = grid.number_of_columns;

    let mut remaining_cells: HashSet<usize> = (0..grid.cells.len()).into_iter().collect();

    let mut components = vec![];
    let mut counter = 0;

    // Take any element to land in any component.
    while let Some(&start_cell_index) = remaining_cells.iter().next() {
        let mut visited = HashSet::new();
        let mut neighbours = HashSet::new();
        let mut queue = VecDeque::new();

        queue.push_back(start_cell_index);

        // Gather all cells in the connected component of start_cell_index.
        while let Some(i) = queue.pop_front() {
            visited.insert(i);
            remaining_cells.remove(&i);

            let mut neighbouring_cells = vec![];
            if i % columns > 0 {
                neighbouring_cells.push(i - 1);
            }
            if i % columns < columns - 1 {
                neighbouring_cells.push(i + 1);
            }
            if i >= columns {
                neighbouring_cells.push(i - columns)
            }
            if i < (rows - 1) * columns {
                neighbouring_cells.push(i + columns)
            }

            for neighbour in neighbouring_cells {
                if visited.contains(&neighbour) {
                    continue;
                }

                if grid.cells[i] == grid.cells[neighbour] {
                    queue.push_back(neighbour);
                } else {
                    neighbours.insert(neighbour);
                }
            }
        }

        let cells = visited
            .iter()
            .map(|&i| Position {
                column: i % columns,
                row: i / columns,
            })
            .collect();

        let component = ConnectedComponent {
            id: counter,
            colour: grid.cells[*visited.iter().next().unwrap()],
            cells,
        };
        counter += 1;

        components.push((component, neighbours));
    }

    components
}

impl Graph {
    pub fn create(grid: &Grid) -> Self {
        let components_and_neighbours = find_connected_components(&grid);

        let map_cell_to_component: HashMap<Position, ConnectedComponent> =
            components_and_neighbours
                .iter()
                .flat_map(|(component, _)| {
                    component
                        .cells
                        .iter()
                        .map(|cell| (cell.clone(), component.clone()))
                        .collect::<Vec<(Position, ConnectedComponent)>>()
                })
                .collect();

        let mut neighbours: HashMap<usize, HashSet<usize>> = HashMap::new();

        for (component, neighbour_cells) in &components_and_neighbours {
            let mut neighbour_components = HashSet::new();

            for cell in neighbour_cells {
                let position = Position {
                    column: cell % grid.number_of_columns,
                    row: cell / grid.number_of_columns,
                };
                neighbour_components.insert(map_cell_to_component[&position].id);
            }
            neighbours.insert(component.id, neighbour_components);
        }

        let mut components = HashMap::with_capacity(components_and_neighbours.len());

        for (c, _) in components_and_neighbours.into_iter() {
            components.insert(c.id, c);
        }

        Self {
            components,
            neighbours
        }
    }

    fn to_grid(&self, rows: usize, columns: usize) -> Grid {
        let mut cells = vec![Colour::Red; rows * columns];

        for component in self.neighbours.keys() {
            for position in &self.components[component].cells {
                cells[position.column + position.row * columns] = self.components[component].colour;
            }
        }

        Grid {
            number_of_rows: rows,
            number_of_columns: columns,
            cells,
        }
    }

    pub fn find_component(&self, position: &Position) -> &ConnectedComponent {
        for component in self.neighbours.keys() {
            if self.components[component].cells.contains(&position) {
                return &self.components[component];
            }
        }

        unreachable!()
    }

    pub fn change_colour_of_component_at(&mut self, position: &Position, colour: Colour) {
        let component_id = self.find_component(position).id;

        // Remove the component which is to change colour
        let mut component = self.components.remove(&component_id).unwrap();
        let mut neighbours = self.neighbours.remove(&component_id).unwrap();

        // Gather new cells for that component by combinging the cells of all
        // its neighbours which already have the new colour.
        let mut new_cells = HashSet::new();
        // Gather the set of its new neighbours which is just the union of the
        // sets of neighbours its neighbours with the new colour have.
        let mut new_neighbours = HashSet::new();
        let mut removed_neighbours = HashSet::new();

        for id in &neighbours {
            if *id != component_id && self.components[id].colour == colour {
                let neighbour_component = self.components.remove(id).unwrap();
                new_cells.extend(neighbour_component.cells.into_iter());
                let set_of_neighbour_ids = self.neighbours.remove(&neighbour_component.id).unwrap();
                new_neighbours.extend(set_of_neighbour_ids.into_iter());
                removed_neighbours.insert(*id);
            }
        }

        // Add new neighbours
        neighbours.extend(new_neighbours.clone().into_iter());
        // Remove the ID of the component itself
        neighbours.remove(&component_id);
        // and the IDs of the neighbours that were merged into the component
        neighbours = neighbours.difference(&removed_neighbours).map(|&x| x).collect();

        // Add the cells from the neighbours which now have the new colour
        component.cells.extend(new_cells.into_iter());
        // and update the colour.  With this, the component itself is done.
        component.colour = colour;

        // Fix the neighbour sets for all the remaining components
        // All we have to do here is replace any of the indices in new_neighbours with component_id.
        for (_, n) in self.neighbours.iter_mut() {
            for incorporated_neighbour_id in &removed_neighbours {
                n.remove(incorporated_neighbour_id);
            }
            n.insert(component_id);
        }

        // Put the component and neighbours back into the Graph
        self.components.entry(component_id).or_insert(component);
        self.neighbours.entry(component_id).or_insert(neighbours);
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn should_return_same_grid_as_input() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);
        let reconstituted_grid = graph.to_grid(size, size);

        assert_eq!(reconstituted_grid, grid);
    }

    #[test]
    fn should_have_one_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red; 4],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 1);
    }

    #[test]
    fn should_have_four_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Yellow, Colour::Yellow, Colour::Red],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 4);
    }

    #[test]
    fn should_have_two_component() {
        let grid = Grid {
            number_of_columns: 2,
            number_of_rows: 2,
            cells: vec![Colour::Red, Colour::Red, Colour::Yellow, Colour::Yellow],
        };

        let graph = Graph::create(&grid);

        assert_eq!(graph.neighbours.len(), 2);
    }

    #[test]
    fn should_have_same_keys_for_components_and_neighbours_maps() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let components_keys: HashSet<_> = graph.components.keys().collect();
        let neighbours_keys: HashSet<_> = graph.neighbours.keys().collect();
        assert_eq!(components_keys, neighbours_keys);
    }

    #[test]
    fn should_contain_exactly_the_component_ids_as_keys() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_keys: HashSet<_> = graph.components.keys().collect();
        let component_ids: HashSet<_> = graph.components.values().map(|x| &x.id).collect();
        assert_eq!(component_keys, component_ids);

        for (id, component) in graph.components {
            assert_eq!(id, component.id);
        }
    }

    #[test]
    fn should_contain_only_component_ids_as_values_in_neighbours_map() {
        let size = 4;
        let grid = Grid::generate(size);

        let graph = Graph::create(&grid);

        let component_ids: HashSet<_> = graph.components.keys().map(|&x| x).collect();

        for (_, neighbours) in graph.neighbours {
            assert_eq!(neighbours.difference(&component_ids).collect::<HashSet<_>>().len(), 0);
        }
    }
}
<|endoftext|>