<commit_before>use crate::board::{Board, BoardStatus};
use crate::chess_move::ChessMove;
use crate::color::Color;
use crate::movegen::MoveGen;
use crate::piece::Piece;

/// Contains all actions supported within the game
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Eq)]
pub enum Action {
    MakeMove(ChessMove),
    OfferDraw(Color),
    AcceptDraw,
    DeclareDraw,
    Resign(Color),
}

/// What was the result of this game?
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum GameResult {
    WhiteCheckmates,
    WhiteResigns,
    BlackCheckmates,
    BlackResigns,
    Stalemate,
    DrawAccepted,
    DrawDeclared,
}

/// For UI/UCI Servers, store a game object which allows you to determine
/// draw by 3 fold repitition, draw offers, resignations, and moves.
///
/// This structure is slow compared to using `Board` directly, so it is
/// not recommended for engines.
///
/// Note: This does not yet support draw by 50-move rule.
#[derive(Clone, Debug)]
pub struct Game {
    start_pos: Board,
    moves: Vec<Action>,
}

impl Game {
    /// Create a new `Game` with the initial position.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.current_position(), Board::default());
    /// ```
    pub fn new() -> Game {
        Game {
            start_pos: Board::default(),
            moves: vec!(),
        }
    }

    /// Get all actions made in this game (moves, draw offers, resignations, etc.)
    ///
    /// ```
    /// use chess::{Game, MoveGen, Color};
    ///
    /// let mut game = Game::new();
    /// let mut movegen = MoveGen::new_legal(&game.current_position());
    ///
    /// game.make_move(movegen.next().expect("At least one valid move"));
    /// game.resign(Color::Black);
    /// assert_eq!(game.actions().len(), 2);
    /// ```
    pub fn actions(&self) -> &Vec<Action> {
        &self.moves
    }

    /// What is the status of this game?
    ///
    /// ```
    /// use chess::Game;
    ///
    /// let game = Game::new();
    /// assert!(game.result().is_none());
    /// ```
    pub fn result(&self) -> Option<GameResult> {
        match self.current_position().status() {
            BoardStatus::Checkmate => {
                if self.side_to_move() == Color::White {
                    Some(GameResult::BlackCheckmates)
                } else {
                    Some(GameResult::WhiteCheckmates)
                }
            },
            BoardStatus::Stalemate => {
                Some(GameResult::Stalemate)
            },
            BoardStatus::Ongoing => {
                if self.moves.len() == 0 {
                    None
                } else if self.moves[self.moves.len() - 1] == Action::AcceptDraw {
                    Some(GameResult::DrawAccepted)
                } else if self.moves[self.moves.len() - 1] == Action::DeclareDraw {
                    Some(GameResult::DrawDeclared)
                } else if self.moves[self.moves.len() - 1] == Action::Resign(Color::White) {
                    Some(GameResult::WhiteResigns)
                } else if self.moves[self.moves.len() - 1] == Action::Resign(Color::Black) {
                    Some(GameResult::BlackResigns)
                } else {
                    None
                }
            },
        }
    }

    /// Create a new `Game` object from an FEN string.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new_from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").expect("Valid FEN");
    /// let game2 = Game::new_from_fen("Invalid FEN");
    /// assert!(game2.is_none());
    /// ```
    pub fn new_from_fen(fen: &str) -> Option<Game> {
        let board = Board::from_fen(fen.to_string());
        match board {
            None => None,
            Some(b) => Some(Game {
                start_pos: b,
                moves: vec!(),
            })
        }
    }

    /// Get the current position on the board from the `Game` object.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.current_position(), Board::default());
    /// ```
    pub fn current_position(&self) -> Board {
        let mut copy = self.start_pos;

        for x in self.moves.iter() {
            match *x {
                Action::MakeMove(m) => { copy = copy.make_move_new(m); }
                _ => {}
            }
        }

        copy
    }

    /// Determine if a player can legally declare a draw by 3-fold repetition or 50-move rule.
    ///
    /// ```
    /// use chess::{Game, Square, Rank, File, ChessMove};
    ///
    /// let b1 = Square::make_square(Rank::First, File::B);
    /// let c3 = Square::make_square(Rank::Third, File::C);
    ///
    /// let b8 = Square::make_square(Rank::Eighth, File::B);
    /// let c6 = Square::make_square(Rank::Sixth, File::C);
    ///
    /// let b1c3 = ChessMove::new(b1, c3, None);
    /// let c3b1 = ChessMove::new(c3, b1, None);
    ///
    /// let b8c6 = ChessMove::new(b8, c6, None);
    /// let c6b8 = ChessMove::new(c6, b8, None);
    ///
    /// let mut game = Game::new();
    /// assert_eq!(game.can_declare_draw(), false);
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    ///
    /// assert_eq!(game.can_declare_draw(), false); // position has shown up twice
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    /// assert_eq!(game.can_declare_draw(), true); // position has shown up three times
    /// ```
    pub fn can_declare_draw(&self) -> bool {
        if self.result().is_some() {
            return false;
        }

        let mut legal_moves_per_move: Vec<Vec<ChessMove>> = vec!();

        let mut board = self.start_pos;
        let mut reversible_moves = 0;
        legal_moves_per_move.push(MoveGen::new_legal(&board).collect());
        for x in self.moves.iter() {
            match *x {
                Action::MakeMove(m) => {
                    let white_castle_rights = board.castle_rights(Color::White);
                    let black_castle_rights = board.castle_rights(Color::Black);
                    if board.piece_on(m.get_source()) == Some(Piece::Pawn) {
                        reversible_moves = 0;
                    } else if board.piece_on(m.get_dest()).is_some() {
                        reversible_moves = 0;
                    } else {
                        reversible_moves += 1;
                    }
                    board = board.make_move_new(m);

                    if board.castle_rights(Color::White) != white_castle_rights ||
                       board.castle_rights(Color::Black) != black_castle_rights {
                        reversible_moves = 0;
                    }
                    legal_moves_per_move.push(MoveGen::new_legal(&board).collect());
                },
                _ => {}
            }
        }

        if reversible_moves >= 100 {
            return true;
        }

        let last_moves = legal_moves_per_move[legal_moves_per_move.len() - 1].clone();

        for i in 1..(legal_moves_per_move.len() - 1) {
            for j in 0..i {
                if legal_moves_per_move[i] == last_moves && legal_moves_per_move[j] == last_moves {
                    return true;
                }
            }
        }

        return false;
    }

    /// Declare a draw by 3-fold repitition or 50-move rule.
    ///
    /// ```
    /// use chess::{Game, Square, Rank, File, ChessMove};
    ///
    /// let b1 = Square::make_square(Rank::First, File::B);
    /// let c3 = Square::make_square(Rank::Third, File::C);
    ///
    /// let b8 = Square::make_square(Rank::Eighth, File::B);
    /// let c6 = Square::make_square(Rank::Sixth, File::C);
    ///
    /// let b1c3 = ChessMove::new(b1, c3, None);
    /// let c3b1 = ChessMove::new(c3, b1, None);
    ///
    /// let b8c6 = ChessMove::new(b8, c6, None);
    /// let c6b8 = ChessMove::new(c6, b8, None);
    ///
    /// let mut game = Game::new();
    /// assert_eq!(game.can_declare_draw(), false);
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    ///
    /// assert_eq!(game.can_declare_draw(), false); // position has shown up twice
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    /// assert_eq!(game.can_declare_draw(), true); // position has shown up three times
    /// game.declare_draw();
    /// ```
    pub fn declare_draw(&mut self) -> bool {
        if self.can_declare_draw() {
            self.moves.push(Action::DeclareDraw);
            true
        } else {
            false
        }
    }

    /// Make a chess move on the board
    ///
    /// ```
    /// use chess::{Game, MoveGen};
    ///
    /// let mut game = Game::new();
    ///
    /// let mut movegen = MoveGen::new_legal(&game.current_position());
    ///
    /// game.make_move(movegen.next().expect("At least one legal move"));
    /// ```
    pub fn make_move(&mut self, chess_move: ChessMove) -> bool {
        if self.result().is_some() {
            return false;
        }
        if self.current_position().legal(chess_move) {
            self.moves.push(Action::MakeMove(chess_move));
            true
        } else {
            false
        }
    }

    /// Who's turn is it to move?
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.side_to_move(), Color::White);
    /// ```
    pub fn side_to_move(&self) -> Color {
        let move_count = self.moves.iter().filter(
            |m| match *m {
                Action::MakeMove(_) => true,
                _ => false
            })
            .count() + if self.start_pos.side_to_move() == Color::White { 0 } else { 1 };

        if move_count % 2 == 0 {
            Color::White
        } else {
            Color::Black
        }
    }

    /// Offer a draw to my opponent.  `color` is the player who offered the draw.  The draw must be
    /// accepted before my opponent moves.
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let mut game = Game::new();
    /// game.offer_draw(Color::White);
    /// ```
    pub fn offer_draw(&mut self, color: Color) -> bool {
        if self.result().is_some() {
            return false;
        }
        self.moves.push(Action::OfferDraw(color));
        return true;
    }

    /// Accept a draw offer from my opponent.
    ///
    /// ```
    /// use chess::{Game, MoveGen, Color};
    ///
    /// let mut game = Game::new();
    /// game.offer_draw(Color::Black);
    /// assert_eq!(game.accept_draw(), true);
    ///
    /// let mut game2 = Game::new();
    /// let mut movegen = MoveGen::new_legal(&game2.current_position());
    /// game2.offer_draw(Color::Black);
    /// game2.make_move(movegen.next().expect("At least one legal move"));
    /// assert_eq!(game2.accept_draw(), false);
    /// ```
    pub fn accept_draw(&mut self) -> bool {
        if self.result().is_some() {
            return false;
        }
        if self.moves.len() > 0 {
            if self.moves[self.moves.len() - 1] == Action::OfferDraw(Color::White) ||
               self.moves[self.moves.len() - 1] == Action::OfferDraw(Color::Black) {
                self.moves.push(Action::AcceptDraw);
                return true;
            }
        }

        if self.moves.len() > 1 {
            if self.moves[self.moves.len() - 2] == Action::OfferDraw(!self.side_to_move()) {
                self.moves.push(Action::AcceptDraw);
                return true;
            }
        }

        false
    }

    /// `color` resigns the game
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let mut game = Game::new();
    /// game.resign(Color::White);
    /// ```
    pub fn resign(&mut self, color: Color) -> bool {
        if self.result().is_some() {
            return false;
        }
        self.moves.push(Action::Resign(color));
        return true;
    }
}

<commit_msg>Fixed documentation.<commit_after>use crate::board::{Board, BoardStatus};
use crate::chess_move::ChessMove;
use crate::color::Color;
use crate::movegen::MoveGen;
use crate::piece::Piece;

/// Contains all actions supported within the game
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Eq)]
pub enum Action {
    MakeMove(ChessMove),
    OfferDraw(Color),
    AcceptDraw,
    DeclareDraw,
    Resign(Color),
}

/// What was the result of this game?
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum GameResult {
    WhiteCheckmates,
    WhiteResigns,
    BlackCheckmates,
    BlackResigns,
    Stalemate,
    DrawAccepted,
    DrawDeclared,
}

/// For UI/UCI Servers, store a game object which allows you to determine
/// draw by 3 fold repitition, draw offers, resignations, and moves.
///
/// This structure is slow compared to using `Board` directly, so it is
/// not recommended for engines.
#[derive(Clone, Debug)]
pub struct Game {
    start_pos: Board,
    moves: Vec<Action>,
}

impl Game {
    /// Create a new `Game` with the initial position.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.current_position(), Board::default());
    /// ```
    pub fn new() -> Game {
        Game {
            start_pos: Board::default(),
            moves: vec!(),
        }
    }

    /// Get all actions made in this game (moves, draw offers, resignations, etc.)
    ///
    /// ```
    /// use chess::{Game, MoveGen, Color};
    ///
    /// let mut game = Game::new();
    /// let mut movegen = MoveGen::new_legal(&game.current_position());
    ///
    /// game.make_move(movegen.next().expect("At least one valid move"));
    /// game.resign(Color::Black);
    /// assert_eq!(game.actions().len(), 2);
    /// ```
    pub fn actions(&self) -> &Vec<Action> {
        &self.moves
    }

    /// What is the status of this game?
    ///
    /// ```
    /// use chess::Game;
    ///
    /// let game = Game::new();
    /// assert!(game.result().is_none());
    /// ```
    pub fn result(&self) -> Option<GameResult> {
        match self.current_position().status() {
            BoardStatus::Checkmate => {
                if self.side_to_move() == Color::White {
                    Some(GameResult::BlackCheckmates)
                } else {
                    Some(GameResult::WhiteCheckmates)
                }
            },
            BoardStatus::Stalemate => {
                Some(GameResult::Stalemate)
            },
            BoardStatus::Ongoing => {
                if self.moves.len() == 0 {
                    None
                } else if self.moves[self.moves.len() - 1] == Action::AcceptDraw {
                    Some(GameResult::DrawAccepted)
                } else if self.moves[self.moves.len() - 1] == Action::DeclareDraw {
                    Some(GameResult::DrawDeclared)
                } else if self.moves[self.moves.len() - 1] == Action::Resign(Color::White) {
                    Some(GameResult::WhiteResigns)
                } else if self.moves[self.moves.len() - 1] == Action::Resign(Color::Black) {
                    Some(GameResult::BlackResigns)
                } else {
                    None
                }
            },
        }
    }

    /// Create a new `Game` object from an FEN string.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new_from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").expect("Valid FEN");
    /// let game2 = Game::new_from_fen("Invalid FEN");
    /// assert!(game2.is_none());
    /// ```
    pub fn new_from_fen(fen: &str) -> Option<Game> {
        let board = Board::from_fen(fen.to_string());
        match board {
            None => None,
            Some(b) => Some(Game {
                start_pos: b,
                moves: vec!(),
            })
        }
    }

    /// Get the current position on the board from the `Game` object.
    ///
    /// ```
    /// use chess::{Game, Board};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.current_position(), Board::default());
    /// ```
    pub fn current_position(&self) -> Board {
        let mut copy = self.start_pos;

        for x in self.moves.iter() {
            match *x {
                Action::MakeMove(m) => { copy = copy.make_move_new(m); }
                _ => {}
            }
        }

        copy
    }

    /// Determine if a player can legally declare a draw by 3-fold repetition or 50-move rule.
    ///
    /// ```
    /// use chess::{Game, Square, Rank, File, ChessMove};
    ///
    /// let b1 = Square::make_square(Rank::First, File::B);
    /// let c3 = Square::make_square(Rank::Third, File::C);
    ///
    /// let b8 = Square::make_square(Rank::Eighth, File::B);
    /// let c6 = Square::make_square(Rank::Sixth, File::C);
    ///
    /// let b1c3 = ChessMove::new(b1, c3, None);
    /// let c3b1 = ChessMove::new(c3, b1, None);
    ///
    /// let b8c6 = ChessMove::new(b8, c6, None);
    /// let c6b8 = ChessMove::new(c6, b8, None);
    ///
    /// let mut game = Game::new();
    /// assert_eq!(game.can_declare_draw(), false);
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    ///
    /// assert_eq!(game.can_declare_draw(), false); // position has shown up twice
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    /// assert_eq!(game.can_declare_draw(), true); // position has shown up three times
    /// ```
    pub fn can_declare_draw(&self) -> bool {
        if self.result().is_some() {
            return false;
        }

        let mut legal_moves_per_move: Vec<Vec<ChessMove>> = vec!();

        let mut board = self.start_pos;
        let mut reversible_moves = 0;
        legal_moves_per_move.push(MoveGen::new_legal(&board).collect());
        for x in self.moves.iter() {
            match *x {
                Action::MakeMove(m) => {
                    let white_castle_rights = board.castle_rights(Color::White);
                    let black_castle_rights = board.castle_rights(Color::Black);
                    if board.piece_on(m.get_source()) == Some(Piece::Pawn) {
                        reversible_moves = 0;
                    } else if board.piece_on(m.get_dest()).is_some() {
                        reversible_moves = 0;
                    } else {
                        reversible_moves += 1;
                    }
                    board = board.make_move_new(m);

                    if board.castle_rights(Color::White) != white_castle_rights ||
                       board.castle_rights(Color::Black) != black_castle_rights {
                        reversible_moves = 0;
                    }
                    legal_moves_per_move.push(MoveGen::new_legal(&board).collect());
                },
                _ => {}
            }
        }

        if reversible_moves >= 100 {
            return true;
        }

        let last_moves = legal_moves_per_move[legal_moves_per_move.len() - 1].clone();

        for i in 1..(legal_moves_per_move.len() - 1) {
            for j in 0..i {
                if legal_moves_per_move[i] == last_moves && legal_moves_per_move[j] == last_moves {
                    return true;
                }
            }
        }

        return false;
    }

    /// Declare a draw by 3-fold repitition or 50-move rule.
    ///
    /// ```
    /// use chess::{Game, Square, Rank, File, ChessMove};
    ///
    /// let b1 = Square::make_square(Rank::First, File::B);
    /// let c3 = Square::make_square(Rank::Third, File::C);
    ///
    /// let b8 = Square::make_square(Rank::Eighth, File::B);
    /// let c6 = Square::make_square(Rank::Sixth, File::C);
    ///
    /// let b1c3 = ChessMove::new(b1, c3, None);
    /// let c3b1 = ChessMove::new(c3, b1, None);
    ///
    /// let b8c6 = ChessMove::new(b8, c6, None);
    /// let c6b8 = ChessMove::new(c6, b8, None);
    ///
    /// let mut game = Game::new();
    /// assert_eq!(game.can_declare_draw(), false);
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    ///
    /// assert_eq!(game.can_declare_draw(), false); // position has shown up twice
    ///
    /// game.make_move(b1c3);
    /// game.make_move(b8c6);
    /// game.make_move(c3b1);
    /// game.make_move(c6b8);
    /// assert_eq!(game.can_declare_draw(), true); // position has shown up three times
    /// game.declare_draw();
    /// ```
    pub fn declare_draw(&mut self) -> bool {
        if self.can_declare_draw() {
            self.moves.push(Action::DeclareDraw);
            true
        } else {
            false
        }
    }

    /// Make a chess move on the board
    ///
    /// ```
    /// use chess::{Game, MoveGen};
    ///
    /// let mut game = Game::new();
    ///
    /// let mut movegen = MoveGen::new_legal(&game.current_position());
    ///
    /// game.make_move(movegen.next().expect("At least one legal move"));
    /// ```
    pub fn make_move(&mut self, chess_move: ChessMove) -> bool {
        if self.result().is_some() {
            return false;
        }
        if self.current_position().legal(chess_move) {
            self.moves.push(Action::MakeMove(chess_move));
            true
        } else {
            false
        }
    }

    /// Who's turn is it to move?
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let game = Game::new();
    /// assert_eq!(game.side_to_move(), Color::White);
    /// ```
    pub fn side_to_move(&self) -> Color {
        let move_count = self.moves.iter().filter(
            |m| match *m {
                Action::MakeMove(_) => true,
                _ => false
            })
            .count() + if self.start_pos.side_to_move() == Color::White { 0 } else { 1 };

        if move_count % 2 == 0 {
            Color::White
        } else {
            Color::Black
        }
    }

    /// Offer a draw to my opponent.  `color` is the player who offered the draw.  The draw must be
    /// accepted before my opponent moves.
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let mut game = Game::new();
    /// game.offer_draw(Color::White);
    /// ```
    pub fn offer_draw(&mut self, color: Color) -> bool {
        if self.result().is_some() {
            return false;
        }
        self.moves.push(Action::OfferDraw(color));
        return true;
    }

    /// Accept a draw offer from my opponent.
    ///
    /// ```
    /// use chess::{Game, MoveGen, Color};
    ///
    /// let mut game = Game::new();
    /// game.offer_draw(Color::Black);
    /// assert_eq!(game.accept_draw(), true);
    ///
    /// let mut game2 = Game::new();
    /// let mut movegen = MoveGen::new_legal(&game2.current_position());
    /// game2.offer_draw(Color::Black);
    /// game2.make_move(movegen.next().expect("At least one legal move"));
    /// assert_eq!(game2.accept_draw(), false);
    /// ```
    pub fn accept_draw(&mut self) -> bool {
        if self.result().is_some() {
            return false;
        }
        if self.moves.len() > 0 {
            if self.moves[self.moves.len() - 1] == Action::OfferDraw(Color::White) ||
               self.moves[self.moves.len() - 1] == Action::OfferDraw(Color::Black) {
                self.moves.push(Action::AcceptDraw);
                return true;
            }
        }

        if self.moves.len() > 1 {
            if self.moves[self.moves.len() - 2] == Action::OfferDraw(!self.side_to_move()) {
                self.moves.push(Action::AcceptDraw);
                return true;
            }
        }

        false
    }

    /// `color` resigns the game
    ///
    /// ```
    /// use chess::{Game, Color};
    ///
    /// let mut game = Game::new();
    /// game.resign(Color::White);
    /// ```
    pub fn resign(&mut self, color: Color) -> bool {
        if self.result().is_some() {
            return false;
        }
        self.moves.push(Action::Resign(color));
        return true;
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt::{Display, Error, Formatter};

use map::Map;

#[derive(Clone, Debug)]
pub enum PatriciaTrie<T> {
    Tip,
    Node { key: String, value: Option<T>, children: HashMap<char, PatriciaTrie<T>> }
}

use trie::PatriciaTrie::{Tip, Node};

fn longest_common_prefix(s1: &str, s2: &str) -> usize {
    s1.chars().zip(s2.chars()).take_while(|t| t.0 == t.1).count()
}

// taken from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key, $val); )*
         map
    }}
}

impl<T: Clone> Map<String, T> for PatriciaTrie<T> {
    fn empty() -> PatriciaTrie<T> {
        Tip
    }

    fn bind(&self, k: String, v: T) -> PatriciaTrie<T> {
        fn add_children<T: Clone>(t: &PatriciaTrie<T>, k: String, v: T) -> PatriciaTrie<T> {
            match *t {
                Tip => panic!("undefined"),
                Node { ref key, ref value, ref children } =>
                    match children.get(&k.char_at(0)) {
                        Some(n) => n.bind(k, v),
                        None => Node { key: k, value: Some(v), children: hashmap![] }
                    }
            }
        }

        match *self {
            Tip => Node { key: k, value: Some(v), children: hashmap![] },
            Node { ref key, ref value, ref children } => {
                let i = longest_common_prefix(&k, &key);

                // update an already existing key
                if i == k.len() && i == key.len() {
                    Node { key: k, value: Some(v), children: children.clone() }
                }
                // the existing key is contained in the new key
                else if i == key.len() {
                    let k1 = &k[i..];

                    let mut children = children.clone();
                    children.insert(k1.char_at(0), add_children(self, k1.to_string(), v));

                    Node { key: key.clone(), value: value.clone(), children: children }
                }
                // the new key is contained in the existing key
                else if i == k.len() {
                    let k1 = &key[i..];
                    let children = hashmap![
                        k1.char_at(0) => Node { key: k1.to_string(), value: value.clone(), children: children.clone() }];
                    Node { key: k, value: Some(v), children: children }
                }
                // split at longest common prefix
                else {
                    let common = &k[..i];

                    let k1 = &key[i..];
                    let k2 = &k[i..];

                    let children = hashmap![
                        k1.char_at(0) => Node { key: k1.to_string(), value: value.clone(), children: children.clone() },
                        k2.char_at(0) => Node { key: k2.to_string(), value: Some(v), children: hashmap![] }];

                    Node { key: common.to_string(), value: None, children: children }
                }
            }
        }
    }

    fn lookup(&self, k: String) -> T {
        match *self {
            Tip => panic!("lookup on empty tree."),
            Node { ref key, ref value, ref children } => {
                if k == *key {
                    match *value {
                        Some(ref v) => v.clone(),
                        None => panic!("element does not exist"),
                    }
                } else if k.starts_with(key) {
                    match children.get(&k.char_at(key.len())) {
                        Some(t) => t.lookup(k[key.len()..].to_string()),
                        None => panic!("element does not exist"),
                    }
                } else {
                    panic!("element does not exist")
                }
            }
        }
    }
}

impl<T: Display> Display for PatriciaTrie<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        fn aux<T: Display>(t: &PatriciaTrie<T>, mut indent: String, last: bool, f: &mut Formatter) -> Result<(), Error> {
            match *t {
                Tip => writeln!(f, "()"),
                Node { ref key, ref value, ref children } => {
                    try!(write!(f, "{}", indent));

                    if last {
                        try!(write!(f, "\\-"));
                        indent = indent + "  ";
                    } else {
                        try!(write!(f, "|-"));
                        indent = indent + "| ";
                    }

                    try!(write!(f, "{}", key));

                    match *value {
                        Some(ref v) => try!(write!(f, " => ({})", v)),
                        _ => ()
                    }

                    try!(writeln!(f, ""));

                    for (i, (_, c)) in children.iter().enumerate() {
                        try!(aux(c, indent.clone(), i == children.len() - 1, f));
                    }

                    Result::Ok(())
                }
            }
        }

        aux(self, "".to_string(), true, f)
    }
}

#[test]
fn patricia_trie() {
    let t: PatriciaTrie<usize> = Map::empty();
    let t2 = t.bind("test".to_string(), 0)
        .bind("slow".to_string(), 1)
        .bind("water".to_string(), 2)
        .bind("slower".to_string(), 3)
        .bind("tester".to_string(), 4)
        .bind("te".to_string(), 5)
        .bind("toast".to_string(), 6)
        .bind("toad".to_string(), 7);

    assert_eq!(t2.lookup("test".to_string()), 0);
    assert_eq!(t2.lookup("slow".to_string()), 1);
    assert_eq!(t2.lookup("water".to_string()), 2);
    assert_eq!(t2.lookup("slower".to_string()), 3);
    assert_eq!(t2.lookup("tester".to_string()), 4);
    assert_eq!(t2.lookup("te".to_string()), 5);
    assert_eq!(t2.lookup("toast".to_string()), 6);
    assert_eq!(t2.lookup("toad".to_string()), 7);
}
<commit_msg>patricia trie: use Rc for subtree sharing<commit_after>use std::collections::HashMap;
use std::fmt::{Display, Error, Formatter};
use std::rc::Rc;

use map::Map;

#[derive(Clone, Debug)]
pub enum PatriciaTrie<T> {
    Tip,
    Node { key: String, value: Option<T>, children: HashMap<char, Rc<PatriciaTrie<T>>> }
}

use trie::PatriciaTrie::{Tip, Node};

fn longest_common_prefix(s1: &str, s2: &str) -> usize {
    s1.chars().zip(s2.chars()).take_while(|t| t.0 == t.1).count()
}

// taken from: http://stackoverflow.com/questions/28392008/more-concise-hashmap-initialization
macro_rules! hashmap {
    ($( $key: expr => $val: expr ),*) => {{
         let mut map = ::std::collections::HashMap::new();
         $( map.insert($key, $val); )*
         map
    }}
}

impl<T: Clone> Map<String, T> for PatriciaTrie<T> {
    fn empty() -> PatriciaTrie<T> {
        Tip
    }

    fn bind(&self, k: String, v: T) -> PatriciaTrie<T> {
        fn add_children<T: Clone>(t: &PatriciaTrie<T>, k: String, v: T) -> PatriciaTrie<T> {
            match *t {
                Tip => panic!("undefined"),
                Node { ref key, ref value, ref children } =>
                    match children.get(&k.char_at(0)) {
                        Some(n) => n.bind(k, v),
                        None => Node { key: k, value: Some(v), children: hashmap![] }
                    }
            }
        }

        match *self {
            Tip => Node { key: k, value: Some(v), children: hashmap![] },
            Node { ref key, ref value, ref children } => {
                let i = longest_common_prefix(&k, &key);

                // update an already existing key
                if i == k.len() && i == key.len() {
                    Node { key: k, value: Some(v), children: children.clone() }
                }
                // the existing key is contained in the new key
                else if i == key.len() {
                    let k1 = &k[i..];

                    let mut children = children.clone();
                    children.insert(k1.char_at(0), Rc::new(add_children(self, k1.to_string(), v)));

                    Node { key: key.clone(), value: value.clone(), children: children }
                }
                // the new key is contained in the existing key
                else if i == k.len() {
                    let k1 = &key[i..];
                    let children = hashmap![
                        k1.char_at(0) => Rc::new(Node { key: k1.to_string(), value: value.clone(), children: children.clone() })];
                    Node { key: k, value: Some(v), children: children }
                }
                // split at longest common prefix
                else {
                    let common = &k[..i];

                    let k1 = &key[i..];
                    let k2 = &k[i..];

                    let children = hashmap![
                        k1.char_at(0) => Rc::new(Node { key: k1.to_string(), value: value.clone(), children: children.clone() }),
                        k2.char_at(0) => Rc::new(Node { key: k2.to_string(), value: Some(v), children: hashmap![] })];

                    Node { key: common.to_string(), value: None, children: children }
                }
            }
        }
    }

    fn lookup(&self, k: String) -> T {
        match *self {
            Tip => panic!("lookup on empty tree."),
            Node { ref key, ref value, ref children } => {
                if k == *key {
                    match *value {
                        Some(ref v) => v.clone(),
                        None => panic!("element does not exist"),
                    }
                } else if k.starts_with(key) {
                    match children.get(&k.char_at(key.len())) {
                        Some(t) => t.lookup(k[key.len()..].to_string()),
                        None => panic!("element does not exist"),
                    }
                } else {
                    panic!("element does not exist")
                }
            }
        }
    }
}

impl<T: Display> Display for PatriciaTrie<T> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        fn aux<T: Display>(t: &PatriciaTrie<T>, mut indent: String, last: bool, f: &mut Formatter) -> Result<(), Error> {
            match *t {
                Tip => writeln!(f, "()"),
                Node { ref key, ref value, ref children } => {
                    try!(write!(f, "{}", indent));

                    if last {
                        try!(write!(f, "\\-"));
                        indent = indent + "  ";
                    } else {
                        try!(write!(f, "|-"));
                        indent = indent + "| ";
                    }

                    try!(write!(f, "{}", key));

                    match *value {
                        Some(ref v) => try!(write!(f, " => ({})", v)),
                        _ => ()
                    }

                    try!(writeln!(f, ""));

                    for (i, (_, c)) in children.iter().enumerate() {
                        try!(aux(c, indent.clone(), i == children.len() - 1, f));
                    }

                    Result::Ok(())
                }
            }
        }

        aux(self, "".to_string(), true, f)
    }
}

#[test]
fn patricia_trie() {
    let t: PatriciaTrie<usize> = Map::empty();
    let t2 = t.bind("test".to_string(), 0)
        .bind("slow".to_string(), 1)
        .bind("water".to_string(), 2)
        .bind("slower".to_string(), 3)
        .bind("tester".to_string(), 4)
        .bind("te".to_string(), 5)
        .bind("toast".to_string(), 6)
        .bind("toad".to_string(), 7);

    assert_eq!(t2.lookup("test".to_string()), 0);
    assert_eq!(t2.lookup("slow".to_string()), 1);
    assert_eq!(t2.lookup("water".to_string()), 2);
    assert_eq!(t2.lookup("slower".to_string()), 3);
    assert_eq!(t2.lookup("tester".to_string()), 4);
    assert_eq!(t2.lookup("te".to_string()), 5);
    assert_eq!(t2.lookup("toast".to_string()), 6);
    assert_eq!(t2.lookup("toad".to_string()), 7);
}
<|endoftext|>


<commit_before>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.005;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 50;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            Some(Decision { choice: Choice::Suicide, .. }) => {
                                if let Some(ref mut c) = this.cell {
                                    c.inhale = 0;
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<commit_msg>balance things out<commit_after>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.003;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000;
const MOVEMENT_COST: usize = 55;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            Some(Decision { choice: Choice::Suicide, .. }) => {
                                if let Some(ref mut c) = this.cell {
                                    c.inhale = 0;
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<|endoftext|>


<commit_before>use memory::Fetch;
use executor::execute;
use decoder::decode_16;
use decoder::decode_32;
use decoder::is_thumb32;
use register::Reg;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub struct Core<'a, T: Fetch + 'a> {
    pub msp: u32,
    pub psp: u32,
    pub r: [u32; 16],

    pub apsr: u32,
    pub ipsr: u32,
    pub epsr: u32,

    pub primask: u32,
    pub control: u32,

    pub mode: ProcessorMode,
    pub memory: &'a mut T,
}

impl<'a, T: Fetch> Core<'a, T> {
    pub fn new(memory: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            msp: 0,
            psp: 0,
            apsr: 0,
            ipsr: 0,
            epsr: 0,
            primask: 0,
            control: 0,
            r: [0; 16],
            memory: memory,
        }
    }

    pub fn reset(&mut self) {
        let reset_vector = self.memory.fetch32(4);
        println!("\nRESET");

        self.r[Reg::PC.value()] = reset_vector & 0xfffffffe;
        self.epsr = (reset_vector & 1) << 24;
        self.msp = self.memory.fetch32(0);
    }

    //
    // fetch, decode and execute single instruction
    //
    pub fn run(&mut self) {
        let hw = self.memory.fetch16(self.r[Reg::PC.value()]);

        let op = match is_thumb32(hw) {
            true => {
                let hw2 = self.memory.fetch16(self.r[Reg::PC.value()] + 2);
                //println!("pc 0x{:X} = 0x{:X}, 0x{:X}",
                //         self.r[Reg::PC.value()],
                //         hw,
                //         hw2);
                decode_32(hw, hw2)
            }
            false => {
                //println!("pc 0x{:X} = 0x{:X}", self.r[Reg::PC.value()], hw);
                decode_16(hw)
            }
        };

        execute(self, op);
        //TODO: print only changed registers
        //TODO: print APSR
        //TODO: print memory accesses
        println!("PC:{:08X} LR:{:08X} R0:{:08X} R1:{:08X} R2:{:08X} R3:{:08X} R4:{:08X} R5:{:08X} \
                  R6:{:08X} R7:{:08X} R8:{:08X}",
                 self.r[Reg::PC.value()],
                 self.r[Reg::LR.value()],
                 self.r[Reg::R0.value()],
                 self.r[Reg::R1.value()],
                 self.r[Reg::R2.value()],
                 self.r[Reg::R3.value()],
                 self.r[Reg::R4.value()],
                 self.r[Reg::R5.value()],
                 self.r[Reg::R6.value()],
                 self.r[Reg::R7.value()],
                 self.r[Reg::R8.value()]);
    }
}
<commit_msg>print full reg dump - aspr<commit_after>use memory::Fetch;
use executor::execute;
use decoder::decode_16;
use decoder::decode_32;
use decoder::is_thumb32;
use register::Reg;

pub enum ProcessorMode {
    ThreadMode,
    HandlerMode,
}

pub struct Core<'a, T: Fetch + 'a> {
    pub msp: u32,
    pub psp: u32,
    pub r: [u32; 16],

    pub apsr: u32,
    pub ipsr: u32,
    pub epsr: u32,

    pub primask: u32,
    pub control: u32,

    pub mode: ProcessorMode,
    pub memory: &'a mut T,
}

impl<'a, T: Fetch> Core<'a, T> {
    pub fn new(memory: &'a mut T) -> Core<'a, T> {
        Core {
            mode: ProcessorMode::ThreadMode,
            msp: 0,
            psp: 0,
            apsr: 0,
            ipsr: 0,
            epsr: 0,
            primask: 0,
            control: 0,
            r: [0; 16],
            memory: memory,
        }
    }

    pub fn reset(&mut self) {
        let reset_vector = self.memory.fetch32(4);
        println!("\nRESET");

        self.r[Reg::PC.value()] = reset_vector & 0xfffffffe;
        self.epsr = (reset_vector & 1) << 24;
        self.msp = self.memory.fetch32(0);
    }

    //
    // fetch, decode and execute single instruction
    //
    pub fn run(&mut self) {
        //TODO: print only changed registers
        //TODO: print APSR
        //TODO: print memory accesses
        println!("PC:{:08X} APSR:{:08X} LR:{:08X} R0:{:08X} R1:{:08X} R2:{:08X} R3:{:08X} R4:{:08X} R5:{:08X} \
                  R6:{:08X} R7:{:08X} R8:{:08X} R9:{:08X} R10:{:08X} R11:{:08X} R12:{:08X} SP:{:08X}",
                 self.r[Reg::PC.value()],
                 self.apsr,
                 self.r[Reg::LR.value()],
                 self.r[Reg::R0.value()],
                 self.r[Reg::R1.value()],
                 self.r[Reg::R2.value()],
                 self.r[Reg::R3.value()],
                 self.r[Reg::R4.value()],
                 self.r[Reg::R5.value()],
                 self.r[Reg::R6.value()],
                 self.r[Reg::R7.value()],
                 self.r[Reg::R8.value()],
                 self.r[Reg::R9.value()],
                 self.r[Reg::R10.value()],
                 self.r[Reg::R11.value()],
                 self.r[Reg::R12.value()],
                 self.r[Reg::SP.value()],
                 );

        let hw = self.memory.fetch16(self.r[Reg::PC.value()]);

        let op = match is_thumb32(hw) {
            true => {
                let hw2 = self.memory.fetch16(self.r[Reg::PC.value()] + 2);
                //println!("pc 0x{:X} = 0x{:X}, 0x{:X}",
                //         self.r[Reg::PC.value()],
                //         hw,
                //         hw2);
                decode_32(hw, hw2)
            }
            false => {
                //println!("pc 0x{:X} = 0x{:X}", self.r[Reg::PC.value()], hw);
                decode_16(hw)
            }
        };

        execute(self, op);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Date and Time Functions — calendrical calculations and miscellaneous time stuff

use libc::{c_int, c_uint, c_char};
use ffi;
use std;

/// Simply a replacement for time_t. It has been deprecated since it is not equivalent to time_t on 64-bit platforms with a 64-bit time_t.
/// Unrelated to GTimer.
///
/// Note that GTime is defined to always be a 32-bit integer, unlike time_t which may be 64-bit on some systems. Therefore, GTime will
/// overflow in the year 2038, and you cannot use the address of a GTime variable as argument to the UNIX time() function.
pub type Time = i32;

/// Integer representing a year; G_DATE_BAD_YEAR is the invalid value. The year must be 1 or higher; negative (BC) years are not allowed.
/// The year is represented with four digits.
pub type Year = u16;
/// Integer representing a day of the month; between 1 and 31. G_DATE_BAD_DAY represents an invalid day of the month.
pub type Day = u8;

/// Enumeration representing a month; values are G_DATE_JANUARY, G_DATE_FEBRUARY, etc. G_DATE_BAD_MONTH is the invalid value.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Month {
    /// invalid value
    BadMonth,
    /// january
    January,
    /// february
    February,
    /// march
    March,
    /// april
    April,
    /// may
    May,
    /// june
    June,
    /// july
    July,
    /// august
    August,
    /// september
    September,
    /// october
    October,
    /// november
    November,
    /// december
    December
}

/// Enumeration representing a day of the week; G_DATE_MONDAY, G_DATE_TUESDAY, etc. G_DATE_BAD_WEEKDAY is an invalid weekday.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Weekday {
    /// invalid value
    BadWeekday,
    /// monday
    Monday,
    /// tuesday
    Tuesday,
    /// wednesday
    Wednesday,
    /// thrusday
    Thursday,
    /// friday
    Friday,
    /// saturday
    Saturday,
    /// sunday
    Sunday
}

pub struct Date {
    pointer: *mut ffi::GDate
}

impl Date {
    pub fn new() -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new() };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_dmy(day: Day, month: Month, year: Year) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_dmy(day as c_int, month as c_int, year) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_julian(julian_day: u32) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_julian(julian_day) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        unsafe { ffi::g_date_clear(self.pointer, 1) }
    }

    pub fn set_day(&mut self, day: Day) {
        unsafe { ffi::g_date_set_day(self.pointer, day as c_int) }
    }

    pub fn set_month(&mut self, month: Month) {
        unsafe { ffi::g_date_set_month(self.pointer, month as c_int) }
    }

    pub fn set_year(&mut self, year: Year) {
        unsafe { ffi::g_date_set_year(self.pointer, year) }
    }

    pub fn set_dmy(&mut self, day: Day, month: Month, year: Year) {
        unsafe { ffi::g_date_set_dmy(self.pointer, day as c_int, month as c_int, year) }
    }

    pub fn set_julian(&mut self, julian: u32) {
        unsafe { ffi::g_date_set_julian(self.pointer, julian) }
    }

    pub fn set_time_t(&mut self, timet: i64) {
        unsafe { ffi::g_date_set_time_t(self.pointer, timet) }
    }

    pub fn set_time_val(&mut self, timeval: &mut TimeVal) {
        unsafe { ffi::g_date_set_time_val(self.pointer, std::mem::transmute(timeval)) }
    }

    pub fn set_parse(&mut self, str_: &str) {
        unsafe { ffi::g_date_set_parse(self.pointer, str_.as_ptr() as *const c_char) }
    }

    pub fn add_days(&mut self, days: usize) {
        unsafe { ffi::g_date_add_days(self.pointer, days as c_uint) }
    }

    pub fn subtract_days(&mut self, days: usize) {
        unsafe { ffi::g_date_subtract_days(self.pointer, days as c_uint) }
    }

    pub fn add_months(&mut self, months: usize) {
        unsafe { ffi::g_date_add_months(self.pointer, months as c_uint) }
    }

    pub fn subtract_months(&mut self, months: usize) {
        unsafe { ffi::g_date_subtract_months(self.pointer, months as c_uint) }
    }

    pub fn add_years(&mut self, years: usize) {
        unsafe { ffi::g_date_add_years(self.pointer, years as c_uint) }
    }

    pub fn subtract_years(&mut self, years: usize) {
        unsafe { ffi::g_date_subtract_years(self.pointer, years as c_uint) }
    }

    pub fn between(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_between(self.pointer, other.pointer) as isize }
    }

    pub fn compare(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_compare(self.pointer, other.pointer) as isize   }
    }

    pub fn clamp(&mut self, min_date: &Date, max_date: &Date) {
        unsafe { ffi::g_date_clamp(self.pointer, min_date.pointer, max_date.pointer) }
    }

    pub fn order(&mut self, other: &mut Date) {
        unsafe { ffi::g_date_order(self.pointer, other.pointer) }
    }

    pub fn get_day(&self) -> Day {
        unsafe { ffi::g_date_get_day(self.pointer) }
    }

    pub fn get_month(&self) -> Month {
        unsafe { std::mem::transmute(ffi::g_date_get_month(self.pointer)) }
    }

    pub fn get_year(&self) -> Year {
        unsafe { ffi::g_date_get_year(self.pointer) }
    }

    pub fn get_julian(&self) -> u32 {
        unsafe { ffi::g_date_get_julian(self.pointer) }
    }

    pub fn get_weekday(&self) -> Weekday {
        unsafe { std::mem::transmute(ffi::g_date_get_weekday(self.pointer)) }
    }

    pub fn get_day_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_day_of_year(self.pointer) }
    }

    pub fn is_first_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_first_of_month(self.pointer)) }
    }

    pub fn is_last_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_last_of_month(self.pointer)) }
    }

    pub fn get_monday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_monday_week_of_year(self.pointer) }
    }

    pub fn get_sunday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_sunday_week_of_year(self.pointer) }
    }

    pub fn get_iso8601_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_iso8601_week_of_year(self.pointer) }
    }

    /*pub fn strftime(&self, s: &mut String, format: &str) -> u32 {
        unsafe { ffi::g_date_strftime(self.pointer) }
    }*/

    pub fn is_valid(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_valid(self.pointer)) }
    }
}

impl Drop for Date {
    fn drop(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::g_date_free(self.pointer); }
            self.pointer = std::ptr::null_mut();
        }
    }
}

/// Represents a precise time, with seconds and microseconds. Similar to the struct timeval returned by the gettimeofday() UNIX
/// system call.
///
/// GLib is attempting to unify around the use of 64bit integers to represent microsecond-precision time. As such, this type
/// will be removed from a future version of GLib.
#[repr(C)]
pub struct TimeVal {
    /// seconds
    pub tv_sec: i32,
    /// microseconds
    pub tv_usec: i32
}

impl TimeVal {
    pub fn add(&mut self, microseconds: u64) {
        unsafe { ffi::g_time_val_add(std::mem::transmute(self), microseconds) }
    }

    pub fn from_iso8601(&mut self, iso_date: &str) {
        unsafe { ffi::g_time_val_from_iso8601(iso_date.as_ptr() as *const c_char, std::mem::transmute(self)) }
    }

    pub fn to_iso8601(&mut self) -> Option<String> {
        unsafe { super::translate::FromGlibPtr::borrow(ffi::g_time_val_to_iso8601(std::mem::transmute(self))) }
    }
}

pub fn get_current_time() -> TimeVal {
    let mut t = TimeVal {
        tv_sec: 0,
        tv_usec: 0
    };

    unsafe { ffi::g_get_current_time(std::mem::transmute(&mut t)) };
    t
}

pub fn usleep(microseconds: u64) {
    unsafe { ffi::g_usleep(microseconds) }
}

pub fn get_monotonic_time() -> i64 {
    unsafe { ffi::g_get_monotonic_time() }
}

pub fn get_real_time() -> i64 {
    unsafe { ffi::g_get_real_time() }
}

pub fn get_days_in_month(month: Month, year: Year) -> u8 {
    unsafe { ffi::g_date_get_days_in_month(month as c_int, year) }
}

pub fn is_leap_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_is_leap_year(year)) }
}

pub fn get_monday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_monday_weeks_in_year(year) }
}

pub fn get_sunday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_sunday_weeks_in_year(year) }
}

pub fn is_valid_day(day: Day) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_day(day as c_int)) }
}

pub fn is_valid_month(month: Month) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_month(month as c_int)) }
}

pub fn is_valid_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_year(year)) }
}

pub fn is_valid_dmy(day: Day, month: Month, year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_dmy(day as c_int, month as c_int, year)) }
}

pub fn is_valid_julian(julian: u32) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_julian(julian)) }
}

pub fn is_valid_weekday(day: Weekday) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_weekday(day as c_int)) }
}
<commit_msg>Remove bad type conversions<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Date and Time Functions — calendrical calculations and miscellaneous time stuff

use libc::{c_int, c_uint};
use ffi;
use std;
use super::translate::ToGlibPtr;

/// Simply a replacement for time_t. It has been deprecated since it is not equivalent to time_t on 64-bit platforms with a 64-bit time_t.
/// Unrelated to GTimer.
///
/// Note that GTime is defined to always be a 32-bit integer, unlike time_t which may be 64-bit on some systems. Therefore, GTime will
/// overflow in the year 2038, and you cannot use the address of a GTime variable as argument to the UNIX time() function.
pub type Time = i32;

/// Integer representing a year; G_DATE_BAD_YEAR is the invalid value. The year must be 1 or higher; negative (BC) years are not allowed.
/// The year is represented with four digits.
pub type Year = u16;
/// Integer representing a day of the month; between 1 and 31. G_DATE_BAD_DAY represents an invalid day of the month.
pub type Day = u8;

/// Enumeration representing a month; values are G_DATE_JANUARY, G_DATE_FEBRUARY, etc. G_DATE_BAD_MONTH is the invalid value.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Month {
    /// invalid value
    BadMonth,
    /// january
    January,
    /// february
    February,
    /// march
    March,
    /// april
    April,
    /// may
    May,
    /// june
    June,
    /// july
    July,
    /// august
    August,
    /// september
    September,
    /// october
    October,
    /// november
    November,
    /// december
    December
}

/// Enumeration representing a day of the week; G_DATE_MONDAY, G_DATE_TUESDAY, etc. G_DATE_BAD_WEEKDAY is an invalid weekday.
#[derive(Clone, Copy)]
#[repr(C)]
pub enum Weekday {
    /// invalid value
    BadWeekday,
    /// monday
    Monday,
    /// tuesday
    Tuesday,
    /// wednesday
    Wednesday,
    /// thrusday
    Thursday,
    /// friday
    Friday,
    /// saturday
    Saturday,
    /// sunday
    Sunday
}

pub struct Date {
    pointer: *mut ffi::GDate
}

impl Date {
    pub fn new() -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new() };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_dmy(day: Day, month: Month, year: Year) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_dmy(day as c_int, month as c_int, year) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn new_julian(julian_day: u32) -> Option<Date> {
        let tmp = unsafe { ffi::g_date_new_julian(julian_day) };

        if tmp.is_null() {
            Some(Date {
                pointer: tmp
            })
        } else {
            None
        }
    }

    pub fn clear(&mut self) {
        unsafe { ffi::g_date_clear(self.pointer, 1) }
    }

    pub fn set_day(&mut self, day: Day) {
        unsafe { ffi::g_date_set_day(self.pointer, day as c_int) }
    }

    pub fn set_month(&mut self, month: Month) {
        unsafe { ffi::g_date_set_month(self.pointer, month as c_int) }
    }

    pub fn set_year(&mut self, year: Year) {
        unsafe { ffi::g_date_set_year(self.pointer, year) }
    }

    pub fn set_dmy(&mut self, day: Day, month: Month, year: Year) {
        unsafe { ffi::g_date_set_dmy(self.pointer, day as c_int, month as c_int, year) }
    }

    pub fn set_julian(&mut self, julian: u32) {
        unsafe { ffi::g_date_set_julian(self.pointer, julian) }
    }

    pub fn set_time_t(&mut self, timet: i64) {
        unsafe { ffi::g_date_set_time_t(self.pointer, timet) }
    }

    pub fn set_time_val(&mut self, timeval: &mut TimeVal) {
        unsafe { ffi::g_date_set_time_val(self.pointer, std::mem::transmute(timeval)) }
    }

    pub fn set_parse(&mut self, str_: &str) {
        unsafe { ffi::g_date_set_parse(self.pointer, str_.borrow_to_glib().0) }
    }

    pub fn add_days(&mut self, days: usize) {
        unsafe { ffi::g_date_add_days(self.pointer, days as c_uint) }
    }

    pub fn subtract_days(&mut self, days: usize) {
        unsafe { ffi::g_date_subtract_days(self.pointer, days as c_uint) }
    }

    pub fn add_months(&mut self, months: usize) {
        unsafe { ffi::g_date_add_months(self.pointer, months as c_uint) }
    }

    pub fn subtract_months(&mut self, months: usize) {
        unsafe { ffi::g_date_subtract_months(self.pointer, months as c_uint) }
    }

    pub fn add_years(&mut self, years: usize) {
        unsafe { ffi::g_date_add_years(self.pointer, years as c_uint) }
    }

    pub fn subtract_years(&mut self, years: usize) {
        unsafe { ffi::g_date_subtract_years(self.pointer, years as c_uint) }
    }

    pub fn between(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_between(self.pointer, other.pointer) as isize }
    }

    pub fn compare(&self, other: &Date) -> isize {
        unsafe { ffi::g_date_compare(self.pointer, other.pointer) as isize   }
    }

    pub fn clamp(&mut self, min_date: &Date, max_date: &Date) {
        unsafe { ffi::g_date_clamp(self.pointer, min_date.pointer, max_date.pointer) }
    }

    pub fn order(&mut self, other: &mut Date) {
        unsafe { ffi::g_date_order(self.pointer, other.pointer) }
    }

    pub fn get_day(&self) -> Day {
        unsafe { ffi::g_date_get_day(self.pointer) }
    }

    pub fn get_month(&self) -> Month {
        unsafe { std::mem::transmute(ffi::g_date_get_month(self.pointer)) }
    }

    pub fn get_year(&self) -> Year {
        unsafe { ffi::g_date_get_year(self.pointer) }
    }

    pub fn get_julian(&self) -> u32 {
        unsafe { ffi::g_date_get_julian(self.pointer) }
    }

    pub fn get_weekday(&self) -> Weekday {
        unsafe { std::mem::transmute(ffi::g_date_get_weekday(self.pointer)) }
    }

    pub fn get_day_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_day_of_year(self.pointer) }
    }

    pub fn is_first_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_first_of_month(self.pointer)) }
    }

    pub fn is_last_of_month(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_is_last_of_month(self.pointer)) }
    }

    pub fn get_monday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_monday_week_of_year(self.pointer) }
    }

    pub fn get_sunday_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_sunday_week_of_year(self.pointer) }
    }

    pub fn get_iso8601_week_of_year(&self) -> u32 {
        unsafe { ffi::g_date_get_iso8601_week_of_year(self.pointer) }
    }

    /*pub fn strftime(&self, s: &mut String, format: &str) -> u32 {
        unsafe { ffi::g_date_strftime(self.pointer) }
    }*/

    pub fn is_valid(&self) -> bool {
        unsafe { super::to_bool(ffi::g_date_valid(self.pointer)) }
    }
}

impl Drop for Date {
    fn drop(&mut self) {
        if !self.pointer.is_null() {
            unsafe { ffi::g_date_free(self.pointer); }
            self.pointer = std::ptr::null_mut();
        }
    }
}

/// Represents a precise time, with seconds and microseconds. Similar to the struct timeval returned by the gettimeofday() UNIX
/// system call.
///
/// GLib is attempting to unify around the use of 64bit integers to represent microsecond-precision time. As such, this type
/// will be removed from a future version of GLib.
#[repr(C)]
pub struct TimeVal {
    /// seconds
    pub tv_sec: i32,
    /// microseconds
    pub tv_usec: i32
}

impl TimeVal {
    pub fn add(&mut self, microseconds: u64) {
        unsafe { ffi::g_time_val_add(std::mem::transmute(self), microseconds) }
    }

    pub fn from_iso8601(&mut self, iso_date: &str) {
        unsafe { ffi::g_time_val_from_iso8601(iso_date.borrow_to_glib().0, std::mem::transmute(self)) }
    }

    pub fn to_iso8601(&mut self) -> Option<String> {
        unsafe { super::translate::FromGlibPtr::borrow(ffi::g_time_val_to_iso8601(std::mem::transmute(self))) }
    }
}

pub fn get_current_time() -> TimeVal {
    let mut t = TimeVal {
        tv_sec: 0,
        tv_usec: 0
    };

    unsafe { ffi::g_get_current_time(std::mem::transmute(&mut t)) };
    t
}

pub fn usleep(microseconds: u64) {
    unsafe { ffi::g_usleep(microseconds) }
}

pub fn get_monotonic_time() -> i64 {
    unsafe { ffi::g_get_monotonic_time() }
}

pub fn get_real_time() -> i64 {
    unsafe { ffi::g_get_real_time() }
}

pub fn get_days_in_month(month: Month, year: Year) -> u8 {
    unsafe { ffi::g_date_get_days_in_month(month as c_int, year) }
}

pub fn is_leap_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_is_leap_year(year)) }
}

pub fn get_monday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_monday_weeks_in_year(year) }
}

pub fn get_sunday_weeks_in_year(year: Year) -> u8 {
    unsafe { ffi::g_date_get_sunday_weeks_in_year(year) }
}

pub fn is_valid_day(day: Day) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_day(day as c_int)) }
}

pub fn is_valid_month(month: Month) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_month(month as c_int)) }
}

pub fn is_valid_year(year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_year(year)) }
}

pub fn is_valid_dmy(day: Day, month: Month, year: Year) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_dmy(day as c_int, month as c_int, year)) }
}

pub fn is_valid_julian(julian: u32) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_julian(julian)) }
}

pub fn is_valid_weekday(day: Weekday) -> bool {
    unsafe { super::to_bool(ffi::g_date_valid_weekday(day as c_int)) }
}
<|endoftext|>