<commit_before>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,      //  0
    ClubsTen,      //  1
    ClubsKing,     //  2
    ClubsQueen,    //  3
    ClubsJack,     //  4
    ClubsNine,     //  5
    ClubsEight,    //  6
    ClubsSeven,    //  7
    SpadesAce,     //  8
    SpadesTen,     //  9
    SpadesKing,    // 10
    SpadesQueen,   // 11
    SpadesJack,    // 12
    SpadesNine,    // 13
    SpadesEight,   // 14
    SpadesSeven,   // 15
    HeartsAce,     // 16
    HeartsTen,     // 17
    HeartsKing,    // 18
    HeartsQueen,   // 19
    HeartsJack,    // 20
    HeartsNine,    // 21
    HeartsEight,   // 22
    HeartsSeven,   // 23
    DiamondsAce,   // 24
    DiamondsTen,   // 25
    DiamondsKing,  // 26
    DiamondsQueen, // 27
    DiamondsJack,  // 28
    DiamondsNine,  // 29
    DiamondsEight, // 30
    DiamondsSeven, // 31
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

struct Player {
    id: u8,
    cards: Vec<u8>,
}

impl Player {
    fn print_cards(&self) {
        match self.id {
            0 => println!("player A:"),
            1 => println!("player B:"),
            2 => println!("player C:"),
            _ => panic!("Unknown player {}", self.id),
            }
        for index in 0..10 {
            print!("{}:", index);
            print_card(self.cards[index]);
        }
    }
    fn sort_cards(&mut self) {
        let mut sorted: Vec<u8> = Vec::new();
        let mut clubs: Vec<u8> = Vec::new();
        let mut spades: Vec<u8> = Vec::new();
        let mut hearts: Vec<u8> = Vec::new();
        let mut diamonds: Vec<u8> = Vec::new();
        // first find Jacks
        for n in 0..10 {
            match self.cards[n] {
                // ClubsJack
                4 => sorted.push(self.cards[n]),
                // SpadesJack
                12 => sorted.push(self.cards[n]),
                // HeartsJack
                20 => sorted.push(self.cards[n]),
                // DiamondsJack
                28 => sorted.push(self.cards[n]),
                // Clubs
                0 ... 7 => clubs.push(self.cards[n]),
                // Spades
                8 ... 15 => spades.push(self.cards[n]),
                // Hearts
                16 ... 23 => hearts.push(self.cards[n]),
                // Diamonds
                24 ... 31 => diamonds.push(self.cards[n]),
                _ => panic!("Unknown card"),
            }
        }
        clubs.sort();
        //clubs.reverse();
        spades.sort();
        //spades.reverse();
        hearts.sort();
        //hearts.reverse();
        diamonds.sort();
        //diamonds.reverse();
        // then add the suit with the highest count
        let empty: Vec<u8> = Vec::new();
        let mut highest: &Vec<u8> = ∅
        let mut max: u8 = 0u8;
        if clubs.len() > max as usize {
            max = clubs.len() as u8;
            highest = ♣
        }
        if spades.len() > max as usize {
            max = spades.len() as u8;
            highest = ♠
        }
        if hearts.len() > max as usize {
            max = hearts.len() as u8;
            highest = ♥
        }
        if diamonds.len() > max as usize {
            max = diamonds.len() as u8;
            highest = &diamonds;
        }
        // append highest
        if highest == &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest == &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest == &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest == &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        // append others
        if highest != &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest != &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest != &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest != &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        self.cards = sorted;
    }
}

struct PlayerBuilder {
    id: u8,
    cards: Vec<u8>,
}

impl PlayerBuilder {
    fn new() -> PlayerBuilder {
        PlayerBuilder { cards: Vec::new(), id: 3, }
    }

    fn add(&mut self, newCard: u8) -> &mut PlayerBuilder {
        self.cards.push(newCard);
        self
    }

    fn id(&mut self, newId: u8) -> &mut PlayerBuilder {
        self.id = newId;
        self
    }

    fn finalize(&self) -> Player {
        Player { id: self.id, cards: self.cards.to_vec(), }
    }
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealerId: u8) {
    let mut cards: Vec<u8> = Vec::new();
    // initialize cards
    for n in 0..32 {
        cards.push(n);
    }
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // create dealer with the first 10 cards
    let mut dealer = PlayerBuilder::new()
        .id(dealerId)
        .add(shuffled[0])
        .add(shuffled[1])
        .add(shuffled[2])
        .add(shuffled[3])
        .add(shuffled[4])
        .add(shuffled[5])
        .add(shuffled[6])
        .add(shuffled[7])
        .add(shuffled[8])
        .add(shuffled[9])
        .finalize();
    // let the dealer print his own cards
    dealer.sort_cards();
    println!("");
    dealer.print_cards();
    println!("");
    // create the left player (will play first card)
    let mut left = PlayerBuilder::new()
        .id((dealerId + 1) % 3)
        .add(shuffled[10])
        .add(shuffled[11])
        .add(shuffled[12])
        .add(shuffled[13])
        .add(shuffled[14])
        .add(shuffled[15])
        .add(shuffled[16])
        .add(shuffled[17])
        .add(shuffled[18])
        .add(shuffled[19])
        .finalize();
    left.sort_cards();
    println!("");
    left.print_cards();
    println!("");
    // create the right player (will play bid first)
    let mut right = PlayerBuilder::new()
        .id((dealerId + 2) % 3)
        .add(shuffled[20])
        .add(shuffled[21])
        .add(shuffled[22])
        .add(shuffled[23])
        .add(shuffled[24])
        .add(shuffled[25])
        .add(shuffled[26])
        .add(shuffled[27])
        .add(shuffled[28])
        .add(shuffled[29])
        .finalize();
    right.sort_cards();
    println!("");
    right.print_cards();
    println!("");
    // Skat
    println!("Skat:");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<commit_msg>Initialize cards via iterator and collect().<commit_after>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,      //  0
    ClubsTen,      //  1
    ClubsKing,     //  2
    ClubsQueen,    //  3
    ClubsJack,     //  4
    ClubsNine,     //  5
    ClubsEight,    //  6
    ClubsSeven,    //  7
    SpadesAce,     //  8
    SpadesTen,     //  9
    SpadesKing,    // 10
    SpadesQueen,   // 11
    SpadesJack,    // 12
    SpadesNine,    // 13
    SpadesEight,   // 14
    SpadesSeven,   // 15
    HeartsAce,     // 16
    HeartsTen,     // 17
    HeartsKing,    // 18
    HeartsQueen,   // 19
    HeartsJack,    // 20
    HeartsNine,    // 21
    HeartsEight,   // 22
    HeartsSeven,   // 23
    DiamondsAce,   // 24
    DiamondsTen,   // 25
    DiamondsKing,  // 26
    DiamondsQueen, // 27
    DiamondsJack,  // 28
    DiamondsNine,  // 29
    DiamondsEight, // 30
    DiamondsSeven, // 31
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

struct Player {
    id: u8,
    cards: Vec<u8>,
}

impl Player {
    fn print_cards(&self) {
        match self.id {
            0 => println!("player A:"),
            1 => println!("player B:"),
            2 => println!("player C:"),
            _ => panic!("Unknown player {}", self.id),
            }
        for index in 0..10 {
            print!("{}:", index);
            print_card(self.cards[index]);
        }
    }
    fn sort_cards(&mut self) {
        let mut sorted: Vec<u8> = Vec::new();
        let mut clubs: Vec<u8> = Vec::new();
        let mut spades: Vec<u8> = Vec::new();
        let mut hearts: Vec<u8> = Vec::new();
        let mut diamonds: Vec<u8> = Vec::new();
        // first find Jacks
        for n in 0..10 {
            match self.cards[n] {
                // ClubsJack
                4 => sorted.push(self.cards[n]),
                // SpadesJack
                12 => sorted.push(self.cards[n]),
                // HeartsJack
                20 => sorted.push(self.cards[n]),
                // DiamondsJack
                28 => sorted.push(self.cards[n]),
                // Clubs
                0 ... 7 => clubs.push(self.cards[n]),
                // Spades
                8 ... 15 => spades.push(self.cards[n]),
                // Hearts
                16 ... 23 => hearts.push(self.cards[n]),
                // Diamonds
                24 ... 31 => diamonds.push(self.cards[n]),
                _ => panic!("Unknown card"),
            }
        }
        clubs.sort();
        //clubs.reverse();
        spades.sort();
        //spades.reverse();
        hearts.sort();
        //hearts.reverse();
        diamonds.sort();
        //diamonds.reverse();
        // then add the suit with the highest count
        let empty: Vec<u8> = Vec::new();
        let mut highest: &Vec<u8> = ∅
        let mut max: u8 = 0u8;
        if clubs.len() > max as usize {
            max = clubs.len() as u8;
            highest = ♣
        }
        if spades.len() > max as usize {
            max = spades.len() as u8;
            highest = ♠
        }
        if hearts.len() > max as usize {
            max = hearts.len() as u8;
            highest = ♥
        }
        if diamonds.len() > max as usize {
            max = diamonds.len() as u8;
            highest = &diamonds;
        }
        // append highest
        if highest == &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest == &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest == &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest == &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        // append others
        if highest != &clubs {
            // append clubs
            for n in 0..clubs.len() {
                sorted.push(clubs[n]);
            }
        }
        if highest != &spades {
            // append spades
            for n in 0..spades.len() {
                sorted.push(spades[n]);
            }
        }
        if highest != &hearts {
            // append hearts
            for n in 0..hearts.len() {
                sorted.push(hearts[n]);
            }
        }
        if highest != &diamonds {
            // append diamonds
            for n in 0..diamonds.len() {
                sorted.push(diamonds[n]);
            }
        }
        self.cards = sorted;
    }
}

struct PlayerBuilder {
    id: u8,
    cards: Vec<u8>,
}

impl PlayerBuilder {
    fn new() -> PlayerBuilder {
        PlayerBuilder { cards: Vec::new(), id: 3, }
    }

    fn add(&mut self, newCard: u8) -> &mut PlayerBuilder {
        self.cards.push(newCard);
        self
    }

    fn id(&mut self, newId: u8) -> &mut PlayerBuilder {
        self.id = newId;
        self
    }

    fn finalize(&self) -> Player {
        Player { id: self.id, cards: self.cards.to_vec(), }
    }
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealerId: u8) {
    let mut cards: Vec<u8> = (0..32).collect();
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // create dealer with the first 10 cards
    let mut dealer = PlayerBuilder::new()
        .id(dealerId)
        .add(shuffled[0])
        .add(shuffled[1])
        .add(shuffled[2])
        .add(shuffled[3])
        .add(shuffled[4])
        .add(shuffled[5])
        .add(shuffled[6])
        .add(shuffled[7])
        .add(shuffled[8])
        .add(shuffled[9])
        .finalize();
    // let the dealer print his own cards
    dealer.sort_cards();
    println!("");
    dealer.print_cards();
    println!("");
    // create the left player (will play first card)
    let mut left = PlayerBuilder::new()
        .id((dealerId + 1) % 3)
        .add(shuffled[10])
        .add(shuffled[11])
        .add(shuffled[12])
        .add(shuffled[13])
        .add(shuffled[14])
        .add(shuffled[15])
        .add(shuffled[16])
        .add(shuffled[17])
        .add(shuffled[18])
        .add(shuffled[19])
        .finalize();
    left.sort_cards();
    println!("");
    left.print_cards();
    println!("");
    // create the right player (will play bid first)
    let mut right = PlayerBuilder::new()
        .id((dealerId + 2) % 3)
        .add(shuffled[20])
        .add(shuffled[21])
        .add(shuffled[22])
        .add(shuffled[23])
        .add(shuffled[24])
        .add(shuffled[25])
        .add(shuffled[26])
        .add(shuffled[27])
        .add(shuffled[28])
        .add(shuffled[29])
        .finalize();
    right.sort_cards();
    println!("");
    right.print_cards();
    println!("");
    // Skat
    println!("Skat:");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // Ip is not present in the table.  This should not hapen... but it does: issie #35011.
        // So rather than returning EHAction::Terminate, we do this.
        EHAction::None
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<commit_msg>Fix typos<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // Ip is not present in the table.  This should not happen... but it does: issue #35011.
        // So rather than returning EHAction::Terminate, we do this.
        EHAction::None
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<|endoftext|>


<commit_before>use core::cell::Cell;

use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::{fake, upcall};

use crate::{ButtonListener, DRIVER_ID};

use super::ButtonState;

type Buttons = super::Buttons<fake::Syscalls>;

#[test]
fn no_driver() {
    let _kernel = fake::Kernel::new();
    assert_eq!(Buttons::count(), Err(ErrorCode::NoDevice));
}

#[test]
fn num_buttons() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);
    assert_eq!(Buttons::count(), Ok(10));
}

#[test]
fn read() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    assert_eq!(driver.set_pressed(0, true), Ok(()));
    assert_eq!(Buttons::read(0), Ok(ButtonState::Pressed));

    assert_eq!(driver.set_pressed(0, false), Ok(()));
    assert_eq!(Buttons::read(0), Ok(ButtonState::Released));

    assert_eq!(Buttons::read(11), Err(ErrorCode::Invalid));
}

#[test]
fn interrupts() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    assert_eq!(Buttons::enable_interrupts(0), Ok(()));
    assert_eq!(driver.get_button_state(0).unwrap().interrupt_enabled, true);

    assert_eq!(Buttons::disable_interrupts(0), Ok(()));
    assert_eq!(driver.get_button_state(0).unwrap().interrupt_enabled, false);

    assert_eq!(Buttons::enable_interrupts(11), Err(ErrorCode::Invalid));
    assert_eq!(Buttons::disable_interrupts(11), Err(ErrorCode::Invalid));
}

#[test]
fn subscribe() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|button, state| {
        assert_eq!(button, 0);
        assert_eq!(state, ButtonState::Pressed);
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        upcall::schedule(DRIVER_ID, 0, (0, 1, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
    });
    assert_eq!(pressed_interrupt_fired.get(), true);

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|button, state| {
        assert_eq!(button, 0);
        assert_eq!(state, ButtonState::Released);
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        upcall::schedule(DRIVER_ID, 0, (0, 0, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
    });
    assert_eq!(pressed_interrupt_fired.get(), true);

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|_, _| {
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        Buttons::unregister_listener();
        upcall::schedule(DRIVER_ID, 0, (0, 1, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
    });
    assert_eq!(pressed_interrupt_fired.get(), false);
}
<commit_msg>update assert warnings<commit_after>use core::cell::Cell;

use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::{fake, upcall};

use crate::{ButtonListener, DRIVER_ID};

use super::ButtonState;

type Buttons = super::Buttons<fake::Syscalls>;

#[test]
fn no_driver() {
    let _kernel = fake::Kernel::new();
    assert_eq!(Buttons::count(), Err(ErrorCode::NoDevice));
}

#[test]
fn num_buttons() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);
    assert_eq!(Buttons::count(), Ok(10));
}

#[test]
fn read() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    assert_eq!(driver.set_pressed(0, true), Ok(()));
    assert_eq!(Buttons::read(0), Ok(ButtonState::Pressed));

    assert_eq!(driver.set_pressed(0, false), Ok(()));
    assert_eq!(Buttons::read(0), Ok(ButtonState::Released));

    assert_eq!(Buttons::read(11), Err(ErrorCode::Invalid));
}

#[test]
fn interrupts() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    assert_eq!(Buttons::enable_interrupts(0), Ok(()));
    assert!(driver.get_button_state(0).unwrap().interrupt_enabled);

    assert_eq!(Buttons::disable_interrupts(0), Ok(()));
    assert!(!driver.get_button_state(0).unwrap().interrupt_enabled);

    assert_eq!(Buttons::enable_interrupts(11), Err(ErrorCode::Invalid));
    assert_eq!(Buttons::disable_interrupts(11), Err(ErrorCode::Invalid));
}

#[test]
fn subscribe() {
    let kernel = fake::Kernel::new();
    let driver = fake::Buttons::<10>::new();
    kernel.add_driver(&driver);

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|button, state| {
        assert_eq!(button, 0);
        assert_eq!(state, ButtonState::Pressed);
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        upcall::schedule(DRIVER_ID, 0, (0, 1, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
    });
    assert!(pressed_interrupt_fired.get());

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|button, state| {
        assert_eq!(button, 0);
        assert_eq!(state, ButtonState::Released);
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        upcall::schedule(DRIVER_ID, 0, (0, 0, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
    });
    assert!(pressed_interrupt_fired.get());

    let pressed_interrupt_fired: Cell<bool> = Cell::new(false);
    let listener = ButtonListener(|_, _| {
        pressed_interrupt_fired.set(true);
    });
    share::scope(|subscribe| {
        assert_eq!(Buttons::register_listener(&listener, subscribe), Ok(()));
        Buttons::unregister_listener();
        upcall::schedule(DRIVER_ID, 0, (0, 1, 0)).unwrap();
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
    });
    assert!(!pressed_interrupt_fired.get());
}
<|endoftext|>


<commit_before>//! This module provides a microfacet model for transmission (a BTDF), see
//! [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
//! for details.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};
use bxdf::fresnel::{Dielectric, Fresnel};
use bxdf::microfacet::{MicrofacetDistribution};

/// Struct providing the microfacet BTDF, implemented as described in
/// [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
pub struct MicrofacetTransmission {
    reflectance: Colorf,
    fresnel: Dielectric,
    /// Microfacet distribution describing the structure of the microfacets of
    /// the material
    microfacet: Box<MicrofacetDistribution + Send + Sync>,
}

impl MicrofacetTransmission {
    /// Create a new transmissive microfacet BRDF
    pub fn new(c: &Colorf, fresnel: Dielectric,
               microfacet: Box<MicrofacetDistribution + Send + Sync>) -> MicrofacetTransmission {
        MicrofacetTransmission { reflectance: *c, fresnel: fresnel, microfacet: microfacet }
    }
    /// Convenience method for getting `eta_i` and `eta_t` in the right order for if
    /// we're entering or exiting this material based on the direction of the outgoing
    /// ray.
    fn eta_for_interaction(&self, w_o: &Vector) -> (f32, f32) {
        if bxdf::cos_theta(w_o) > 0.0 {
            (self.fresnel.eta_i, self.fresnel.eta_t)
        } else {
            (self.fresnel.eta_t, self.fresnel.eta_i)
        }
    }
    /// Compute the Jacobian for the change of variables (see [Walter et al 07] section 4.2),
    /// here we compute equation 17 in that section.
    fn jacobian(w_o: &Vector, w_i: &Vector, w_h: &Vector, eta: (f32, f32)) -> f32 {
        let wi_dot_h = linalg::dot(w_i, w_h);
        let wo_dot_h = linalg::dot(w_o, w_h);
        f32::powf(eta.1, 2.0) * f32::abs(wo_dot_h) / f32::powf(eta.0 * wi_dot_h + eta.1 * wo_dot_h, 2.0)
    }
    fn half_vector(w_o: &Vector, w_i: &Vector, eta: (f32, f32)) -> Option<Vector> {
        let mut w_h = -eta.0 * *w_o - eta.1 * *w_i;
        if w_h.x == 0.0 && w_h.y == 0.0 && w_h.z == 0.0 {
            None
        } else {
            Some(w_h.normalized())
        }
    }
}

impl BxDF for MicrofacetTransmission {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Transmission);
        e
    }
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf {
        if bxdf::same_hemisphere(w_o, w_i) {
            return Colorf::black();
        }
        let cos_to = bxdf::cos_theta(w_o);
        let cos_ti = bxdf::cos_theta(w_i);
        if cos_to == 0.0 || cos_ti == 0.0 {
            return Colorf::black();
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_h) = MicrofacetTransmission::half_vector(w_o, w_i, eta) {
            let d = self.microfacet.normal_distribution(&w_h);
            let f = Colorf::broadcast(1.0) - self.fresnel.fresnel(linalg::dot(w_o, &w_h));
            let g = self.microfacet.shadowing_masking(w_i, w_o, &w_h);
            let wi_dot_h = linalg::dot(w_i, &w_h);
            let jacobian = MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta);
            self.reflectance * (f32::abs(wi_dot_h) / (f32::abs(w_i.z) * f32::abs(w_o.z)))
                * (f * g * d) * jacobian
        } else {
            Colorf::black()
        }
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_h = self.microfacet.sample(w_o, samples);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_i) = linalg::refract(w_o, &w_h, eta.0, eta.1) {
            if bxdf::same_hemisphere(w_o, &w_i) {
                (Colorf::black(), Vector::broadcast(0.0), 0.0)
            } else {
                let pdf = self.microfacet.pdf(&w_h)
                    * MicrofacetTransmission::jacobian(w_o, &w_i, &w_h, eta);
                (self.eval(w_o, &w_i), w_i, pdf)
            }
        } else {
            (Colorf::black(), Vector::broadcast(0.0), 0.0)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if bxdf::same_hemisphere(w_o, w_i) {
            0.0
        } else {
            let eta = self.eta_for_interaction(w_o);
            if let Some(w_h) = MicrofacetTransmission::half_vector(w_o, w_i, eta) {
                self.microfacet.pdf(&w_h) * MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta)
            } else {
                0.0
            }
        }
    }
}

<commit_msg>Fix unneeded mut<commit_after>//! This module provides a microfacet model for transmission (a BTDF), see
//! [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
//! for details.

use std::f32;
use enum_set::EnumSet;

use linalg::{self, Vector};
use film::Colorf;
use bxdf::{self, BxDF, BxDFType};
use bxdf::fresnel::{Dielectric, Fresnel};
use bxdf::microfacet::{MicrofacetDistribution};

/// Struct providing the microfacet BTDF, implemented as described in
/// [Walter et al. 07](https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf)
pub struct MicrofacetTransmission {
    reflectance: Colorf,
    fresnel: Dielectric,
    /// Microfacet distribution describing the structure of the microfacets of
    /// the material
    microfacet: Box<MicrofacetDistribution + Send + Sync>,
}

impl MicrofacetTransmission {
    /// Create a new transmissive microfacet BRDF
    pub fn new(c: &Colorf, fresnel: Dielectric,
               microfacet: Box<MicrofacetDistribution + Send + Sync>) -> MicrofacetTransmission {
        MicrofacetTransmission { reflectance: *c, fresnel: fresnel, microfacet: microfacet }
    }
    /// Convenience method for getting `eta_i` and `eta_t` in the right order for if
    /// we're entering or exiting this material based on the direction of the outgoing
    /// ray.
    fn eta_for_interaction(&self, w_o: &Vector) -> (f32, f32) {
        if bxdf::cos_theta(w_o) > 0.0 {
            (self.fresnel.eta_i, self.fresnel.eta_t)
        } else {
            (self.fresnel.eta_t, self.fresnel.eta_i)
        }
    }
    /// Compute the Jacobian for the change of variables (see [Walter et al 07] section 4.2),
    /// here we compute equation 17 in that section.
    fn jacobian(w_o: &Vector, w_i: &Vector, w_h: &Vector, eta: (f32, f32)) -> f32 {
        let wi_dot_h = linalg::dot(w_i, w_h);
        let wo_dot_h = linalg::dot(w_o, w_h);
        f32::powf(eta.1, 2.0) * f32::abs(wo_dot_h) / f32::powf(eta.0 * wi_dot_h + eta.1 * wo_dot_h, 2.0)
    }
    fn half_vector(w_o: &Vector, w_i: &Vector, eta: (f32, f32)) -> Option<Vector> {
        let w_h = -eta.0 * *w_o - eta.1 * *w_i;
        if w_h.x == 0.0 && w_h.y == 0.0 && w_h.z == 0.0 {
            None
        } else {
            Some(w_h.normalized())
        }
    }
}

impl BxDF for MicrofacetTransmission {
    fn bxdf_type(&self) -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Transmission);
        e
    }
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf {
        if bxdf::same_hemisphere(w_o, w_i) {
            return Colorf::black();
        }
        let cos_to = bxdf::cos_theta(w_o);
        let cos_ti = bxdf::cos_theta(w_i);
        if cos_to == 0.0 || cos_ti == 0.0 {
            return Colorf::black();
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_h) = MicrofacetTransmission::half_vector(w_o, w_i, eta) {
            let d = self.microfacet.normal_distribution(&w_h);
            let f = Colorf::broadcast(1.0) - self.fresnel.fresnel(linalg::dot(w_o, &w_h));
            let g = self.microfacet.shadowing_masking(w_i, w_o, &w_h);
            let wi_dot_h = linalg::dot(w_i, &w_h);
            let jacobian = MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta);
            self.reflectance * (f32::abs(wi_dot_h) / (f32::abs(w_i.z) * f32::abs(w_o.z)))
                * (f * g * d) * jacobian
        } else {
            Colorf::black()
        }
    }
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_h = self.microfacet.sample(w_o, samples);
        if !bxdf::same_hemisphere(w_o, &w_h) {
            w_h = -w_h;
        }
        let eta = self.eta_for_interaction(w_o);
        if let Some(w_i) = linalg::refract(w_o, &w_h, eta.0, eta.1) {
            if bxdf::same_hemisphere(w_o, &w_i) {
                (Colorf::black(), Vector::broadcast(0.0), 0.0)
            } else {
                let pdf = self.microfacet.pdf(&w_h)
                    * MicrofacetTransmission::jacobian(w_o, &w_i, &w_h, eta);
                (self.eval(w_o, &w_i), w_i, pdf)
            }
        } else {
            (Colorf::black(), Vector::broadcast(0.0), 0.0)
        }
    }
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if bxdf::same_hemisphere(w_o, w_i) {
            0.0
        } else {
            let eta = self.eta_for_interaction(w_o);
            if let Some(w_h) = MicrofacetTransmission::half_vector(w_o, w_i, eta) {
                self.microfacet.pdf(&w_h) * MicrofacetTransmission::jacobian(w_o, w_i, &w_h, eta)
            } else {
                0.0
            }
        }
    }
}

<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::f64;
use std::mem;

use super::MCMove;

use types::{Matrix3, One};
use sys::{System, Configuration, EnergyCache};

/// Monte Carlo move that changes the size of the simulation cell
pub struct Resize {
    /// Delta for translation of the box length
    delta: f64,
    /// Sampling range for volume scaling
    range: Range<f64>,
    /// Configuration before applying changes to the simulation cell
    previous: Configuration,
    /// target pressure
    pressure: f64,
    /// largest cutoff diameter of potentials in `Interactions`
    maximum_cutoff: Option<f64>,
}

impl Resize {
    /// Create a new `Resize` move, with target pressure `pressure` and maximum
    /// displacement of `delta`.
    pub fn new(pressure: f64, delta: f64) -> Resize {
        assert!(delta > 0.0, "delta must be positive in Resize move");
        Resize {
            delta: delta,
            range: Range::new(-delta, delta),
            previous: Configuration::new(),
            pressure: pressure,
            maximum_cutoff: None,
        }
    }
}

impl MCMove for Resize {
    fn describe(&self) -> &str {
        "resizing of the cell"
    }

    fn setup(&mut self, system: &System) {
        // check if the cell is infinite
        if system.cell.is_infinite() {
            fatal_error!("Cannot use `Resize` move with infinite simulation cell.")
        }

        // Get the largest cutoff of all intermolecular interactions in the
        // system.
        self.maximum_cutoff = system.maximum_cutoff()
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        let delta = self.range.sample(rng);

        // Store the previous configuration
        self.previous = (**system).clone();

        let volume = system.volume();
        let scaling_factor = f64::cbrt((volume + delta) / volume);
        // Change the simulation cell
        system.cell.scale_mut(Matrix3::one() * scaling_factor);
        // Check the radius of the smallest inscribed sphere and compare to the
        // cut off distance.
        // Abort simulation when box gets smaller than twice the cutoff radius.
        if let Some(maximum_cutoff) = self.maximum_cutoff {
            if system.cell.lengths().iter().any(|&d| 0.5 * d <= maximum_cutoff) {
                fatal_error!(
                    "Tried to decrease the cell size but new size
                    conflicts with the cut off radius. \
                    Increase the number of particles to get rid of this problem."
                );
            }
        };

        for (mi, molecule) in self.previous.molecules().iter().enumerate() {
            // We don't want to change the intramolecular distances
            // so we compute the translation vector of the center-of-mass
            // (com) of a molecule and apply it to all its particles.
            // Note that to do this, the com of a molecule *always* has
            // to reside inside the simulation cell.
            let old_com = system.molecule_com(mi);
            let frac_com = system.cell.fractional(&old_com);
            let delta_com = system.cell.cartesian(&frac_com) - old_com;
            for position in &mut system.particles_mut().position[molecule.iter()] {
                *position += delta_com;
            }
        }
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let delta_energy = cache.move_all_rigid_molecules_cost(system);
        let new_volume = system.volume();
        let old_volume = self.previous.cell.volume();
        let delta_volume = new_volume - old_volume;
        // Build and return the cost function.
        beta * (delta_energy + self.pressure * delta_volume) -
        (system.molecules().len() as f64) * f64::ln(new_volume / old_volume)
    }

    fn apply(&mut self, _: &mut System) {
        // Nothing to do.
    }

    fn restore(&mut self, system: &mut System) {
        // Exchange configurations
        mem::swap(&mut **system, &mut self.previous)
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        }
    }
}
<commit_msg>Fix error in Resize MC Move<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::f64;
use std::mem;

use super::MCMove;

use types::{Matrix3, One};
use sys::{System, Configuration, EnergyCache};

/// Monte Carlo move that changes the size of the simulation cell
pub struct Resize {
    /// Delta for translation of the box length
    delta: f64,
    /// Sampling range for volume scaling
    range: Range<f64>,
    /// Configuration before applying changes to the simulation cell
    previous: Configuration,
    /// target pressure
    pressure: f64,
    /// largest cutoff diameter of potentials in `Interactions`
    maximum_cutoff: Option<f64>,
}

impl Resize {
    /// Create a new `Resize` move, with target pressure `pressure` and maximum
    /// displacement of `delta`.
    pub fn new(pressure: f64, delta: f64) -> Resize {
        assert!(delta > 0.0, "delta must be positive in Resize move");
        Resize {
            delta: delta,
            range: Range::new(-delta, delta),
            previous: Configuration::new(),
            pressure: pressure,
            maximum_cutoff: None,
        }
    }
}

impl MCMove for Resize {
    fn describe(&self) -> &str {
        "resizing of the cell"
    }

    fn setup(&mut self, system: &System) {
        // check if the cell is infinite
        if system.cell.is_infinite() {
            fatal_error!("Cannot use `Resize` move with infinite simulation cell.")
        }

        // Get the largest cutoff of all intermolecular interactions in the
        // system.
        self.maximum_cutoff = system.maximum_cutoff()
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        let delta = self.range.sample(rng);

        // Store the previous configuration
        self.previous = (**system).clone();

        let volume = system.volume();
        let scaling_factor = f64::cbrt((volume + delta) / volume);
        // Change the simulation cell
        system.cell.scale_mut(Matrix3::one() * scaling_factor);
        // Check the radius of the smallest inscribed sphere and compare to the
        // cut off distance.
        // Abort simulation when box gets smaller than twice the cutoff radius.
        if let Some(maximum_cutoff) = self.maximum_cutoff {
            if system.cell.lengths().iter().any(|&d| 0.5 * d <= maximum_cutoff) {
                fatal_error!(
                    "Tried to decrease the cell size but new size
                    conflicts with the cut off radius. \
                    Increase the number of particles to get rid of this problem."
                );
            }
        };

        for (mi, molecule) in self.previous.molecules().iter().enumerate() {
            // We don't want to change the intramolecular distances so we
            // compute the translation vector of the center-of-mass (com) of a
            // molecule and apply it to all its particles. Note that to do
            // this, the com of a molecule *always* has to reside inside the
            // simulation cell.
            let old_com = self.previous.molecule_com(mi);
            let frac_com = self.previous.cell.fractional(&old_com);
            let delta_com = system.cell.cartesian(&frac_com) - old_com;
            for position in &mut system.particles_mut().position[molecule.iter()] {
                *position += delta_com;
            }
        }
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let delta_energy = cache.move_all_rigid_molecules_cost(system);
        let new_volume = system.volume();
        let old_volume = self.previous.cell.volume();
        let delta_volume = new_volume - old_volume;
        // Build and return the cost function.
        beta * (delta_energy + self.pressure * delta_volume) -
        (system.molecules().len() as f64) * f64::ln(new_volume / old_volume)
    }

    fn apply(&mut self, _: &mut System) {
        // Nothing to do.
    }

    fn restore(&mut self, system: &mut System) {
        // Exchange configurations
        mem::swap(&mut **system, &mut self.previous)
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        }
    }
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license
use rand::distributions::{Normal, Range, Sample};
use rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::{Matrix3, Vector3D};
use sys::{System, EnergyCache};

/// Monte-Carlo move for rotating a rigid molecule
pub struct Rotate {
    /// Type of molecule to rotate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to rotate
    molid: usize,
    /// New positions of the atom in the rotated molecule
    newpos: Vec<Vector3D>,
    /// Normal distribution, for generation of the axis
    axis_rng: Normal,
    /// Maximum values for the range of the range distribution of the angle
    theta: f64,
    /// Range distribution, for generation of the angle
    range: Range<f64>,
}

impl Rotate {
    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating all the molecules in the system.
    pub fn new(theta: f64) -> Rotate {
        Rotate::create(theta, None)
    }

    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating only molecules with `moltype` type.
    pub fn with_moltype(theta: f64, moltype: u64) -> Rotate {
        Rotate::create(theta, Some(moltype))
    }

    // Factorizing the constructors
    fn create(theta: f64, moltype: Option<u64>) -> Rotate {
        assert!(theta > 0.0, "theta must be positive in Rotate move");
        Rotate {
            moltype: moltype,
            molid: usize::MAX,
            newpos: Vec::new(),
            axis_rng: Normal::new(0.0, 1.0),
            theta: theta,
            range: Range::new(-theta, theta),
        }
    }
}

impl Default for Rotate {
    fn default() -> Rotate {
        Rotate::new(0.2)
    }
}

impl MCMove for Rotate {
    fn describe(&self) -> &str {
        "molecular rotation"
    }

    fn setup(&mut self, _: &System) { }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(system, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not rotate molecule: no molecule of this type in the system.");
            return false;
        }

        // Getting values from a 3D normal distribution gives an uniform
        // distribution on the unit sphere.
        let axis = Vector3D::new(
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng)
        ).normalized();
        let theta = self.range.sample(rng);

        // get indices of particles of selected molecule
        let molecule = system.molecule(self.molid);
        // store positions of selected molecule
        self.newpos.clear();
        for pi in molecule.iter() {
            self.newpos.push(system[pi].position);
        }
        // get center-of-mass of molecule
        let com = system.molecule_com(self.molid);
        rotate_around_axis(&mut self.newpos, com, axis, theta);
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let idxes = system.molecule(self.molid).iter().collect::<Vec<_>>();
        let cost = cache.move_particles_cost(system, idxes, &self.newpos);
        return cost*beta;
    }

    fn apply(&mut self, system: &mut System) {
        for (i, pi) in system.molecule(self.molid).iter().enumerate() {
            system[pi].position = self.newpos[i];
        }
    }

    fn restore(&mut self, _: &mut System) {
        // Nothing to do
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            if (s * self.theta).abs().to_degrees() <= 180.0 {
                self.theta *= s;
                self.range = Range::new(-self.theta, self.theta);
            } else {
                // FIXME: fix the warn_once macro formatting usage
                #[allow(useless_format)] {
                    warn_once!(
                        "Tried to increase the maximum amplitude for rotations to more than 180°."
                    );
                }
            }
        }
    }
}

/// Rotate the particles at `positions` with the center-of-mass position
/// `com` around the `axis` axis by `angle`. The `positions` array is
/// overwritten with the new positions.
fn rotate_around_axis(positions: &mut [Vector3D], com: Vector3D, axis: Vector3D, angle: f64) {
    let rotation = rotation_matrix(&axis, angle);
    for position in positions {
        let oldpos = *position - com;
        *position = com + rotation * oldpos;
    }
}

fn rotation_matrix(axis: &Vector3D, angle: f64) -> Matrix3 {
    let sin = f64::sin(angle);
    let cos = f64::cos(angle);

    let x_sin = axis[0] * sin;
    let y_sin = axis[1] * sin;
    let z_sin = axis[2] * sin;
    let one_minus_cos = 1.0 - cos;
    let xy = axis[0] * axis[1] * one_minus_cos;
    let xz = axis[0] * axis[2] * one_minus_cos;
    let yz = axis[1] * axis[2] * one_minus_cos;

    // Build the rotation matrix
    let rotation = Matrix3::new(
        (axis[0] * axis[0]) * one_minus_cos + cos,
        xy + z_sin,
        xz - y_sin,
        xy - z_sin,
        (axis[1] * axis[1]) * one_minus_cos + cos,
        yz + x_sin,
        xz + y_sin,
        yz - x_sin,
        (axis[2] * axis[2]) * one_minus_cos + cos
    );

    return rotation;
}
<commit_msg>Remove obsolete disabling of a compiler warning<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license
use rand::distributions::{Normal, Range, Sample};
use rand::Rng;

use std::usize;
use std::f64;

use super::MCMove;
use super::select_molecule;

use types::{Matrix3, Vector3D};
use sys::{System, EnergyCache};

/// Monte-Carlo move for rotating a rigid molecule
pub struct Rotate {
    /// Type of molecule to rotate. `None` means all molecules.
    moltype: Option<u64>,
    /// Index of the molecule to rotate
    molid: usize,
    /// New positions of the atom in the rotated molecule
    newpos: Vec<Vector3D>,
    /// Normal distribution, for generation of the axis
    axis_rng: Normal,
    /// Maximum values for the range of the range distribution of the angle
    theta: f64,
    /// Range distribution, for generation of the angle
    range: Range<f64>,
}

impl Rotate {
    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating all the molecules in the system.
    pub fn new(theta: f64) -> Rotate {
        Rotate::create(theta, None)
    }

    /// Create a new `Rotate` move, with maximum angular displacement of `theta`,
    /// rotating only molecules with `moltype` type.
    pub fn with_moltype(theta: f64, moltype: u64) -> Rotate {
        Rotate::create(theta, Some(moltype))
    }

    // Factorizing the constructors
    fn create(theta: f64, moltype: Option<u64>) -> Rotate {
        assert!(theta > 0.0, "theta must be positive in Rotate move");
        Rotate {
            moltype: moltype,
            molid: usize::MAX,
            newpos: Vec::new(),
            axis_rng: Normal::new(0.0, 1.0),
            theta: theta,
            range: Range::new(-theta, theta),
        }
    }
}

impl Default for Rotate {
    fn default() -> Rotate {
        Rotate::new(0.2)
    }
}

impl MCMove for Rotate {
    fn describe(&self) -> &str {
        "molecular rotation"
    }

    fn setup(&mut self, _: &System) { }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        if let Some(id) = select_molecule(system, self.moltype, rng) {
            self.molid = id;
        } else {
            warn!("Can not rotate molecule: no molecule of this type in the system.");
            return false;
        }

        // Getting values from a 3D normal distribution gives an uniform
        // distribution on the unit sphere.
        let axis = Vector3D::new(
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng),
            self.axis_rng.sample(rng)
        ).normalized();
        let theta = self.range.sample(rng);

        // get indices of particles of selected molecule
        let molecule = system.molecule(self.molid);
        // store positions of selected molecule
        self.newpos.clear();
        for pi in molecule.iter() {
            self.newpos.push(system[pi].position);
        }
        // get center-of-mass of molecule
        let com = system.molecule_com(self.molid);
        rotate_around_axis(&mut self.newpos, com, axis, theta);
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        let idxes = system.molecule(self.molid).iter().collect::<Vec<_>>();
        let cost = cache.move_particles_cost(system, idxes, &self.newpos);
        return cost*beta;
    }

    fn apply(&mut self, system: &mut System) {
        for (i, pi) in system.molecule(self.molid).iter().enumerate() {
            system[pi].position = self.newpos[i];
        }
    }

    fn restore(&mut self, _: &mut System) {
        // Nothing to do
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            if (s * self.theta).abs().to_degrees() <= 180.0 {
                self.theta *= s;
                self.range = Range::new(-self.theta, self.theta);
            } else {
                warn_once!(
                    "Tried to increase the maximum amplitude for rotations to more than 180°."
                );
            }
        }
    }
}

/// Rotate the particles at `positions` with the center-of-mass position
/// `com` around the `axis` axis by `angle`. The `positions` array is
/// overwritten with the new positions.
fn rotate_around_axis(positions: &mut [Vector3D], com: Vector3D, axis: Vector3D, angle: f64) {
    let rotation = rotation_matrix(&axis, angle);
    for position in positions {
        let oldpos = *position - com;
        *position = com + rotation * oldpos;
    }
}

fn rotation_matrix(axis: &Vector3D, angle: f64) -> Matrix3 {
    let sin = f64::sin(angle);
    let cos = f64::cos(angle);

    let x_sin = axis[0] * sin;
    let y_sin = axis[1] * sin;
    let z_sin = axis[2] * sin;
    let one_minus_cos = 1.0 - cos;
    let xy = axis[0] * axis[1] * one_minus_cos;
    let xz = axis[0] * axis[2] * one_minus_cos;
    let yz = axis[1] * axis[2] * one_minus_cos;

    // Build the rotation matrix
    let rotation = Matrix3::new(
        (axis[0] * axis[0]) * one_minus_cos + cos,
        xy + z_sin,
        xz - y_sin,
        xy - z_sin,
        (axis[1] * axis[1]) * one_minus_cos + cos,
        yz + x_sin,
        xz + y_sin,
        yz - x_sin,
        (axis[2] * axis[2]) * one_minus_cos + cos
    );

    return rotation;
}
<|endoftext|>


<commit_before>use std;

/// Computes the signed distance function from a plane given as the _zero_ level set of a
/// linear function on a tetrahedron at 4 points with unit coordinates starting at (0, 0, 0) and
/// ending at (1, 1, 1), and in between exactly one coordinate changes from 0 to 1.
///
/// Inputs are `u`, the values at the vertices.
///
/// The function returns the values of the (non-signed) distance function or `None` if the zero
/// level set does not pass through the tetrahedron.
pub fn tetrahedron_dist(u: [f64; 4]) -> Option<[f64; 4]> {
    let mut u = u;
    let tiny = 1e-15;

    let mut n_pos = 0;
    for u in &mut u {
        if *u >= 0. {
            *u += tiny;
            n_pos += 1;
        }
    }
    // check if sign differs (level set goes throught the tetrahedron
    if n_pos == 0 || n_pos == 4 {
        // premature optimization: n_pos & 3 == 0 :)
        return None;
    }

    let g_norm_rcp = 1. / u.windows(2).fold(0., |sum, x| sum + (x[1] - x[0]).powi(2)).sqrt();

    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// Initializes the distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist_3d(d: &mut [f64], u: &[f64], dim: (usize, usize, usize)) {
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, u.len());
    assert_eq!(nx * ny * nz, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    // split each cube into 6 tetrahedrons
    let ids = [[(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1)],
               [(0, 0, 0), (1, 0, 0), (1, 0, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 1, 1)],
               [(0, 0, 0), (0, 1, 0), (0, 1, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 0, 1), (1, 0, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)]];

    for i in 1..nx {
        for j in 1..ny {
            for k in 1..nz {
                let s = i * ny * nz + j * nz + k;
                let mut v = [0.; 4];

                for idx in ids.iter() {
                    for m in 0..4 {
                        v[m] = u[s - idx[m].0 * ny * nz - idx[m].1 * nz - idx[m].2];
                    }

                    let r = tetrahedron_dist(v);
                    if let Some(r) = r {
                        for m in 0..4 {
                            let q = s - idx[m].0 * ny * nz - idx[m].1 * nz - idx[m].2;
                            d[q] = d[q].min(r[m]);
                        }
                    }
                }
            }
        }
    }
}
/// Computes the signed distance function from a line given as the _zero_ level set of a
/// linear function on an isosceles right triangle. It preserves level sets of linear functions.
///
/// There does not see to be much point of trying to be smart and compute the distance to the line
/// segments within the triangle. This shifts the level set even in a symmetric case when not
/// needed. This simpler approach here seems to better preserve corners in the crystalline mean
/// curvature flow.
///
/// Inputs are the values at the vertices. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(u: [f64; 3]) -> Option<[f64; 3]> {
    let mut u = u;

    let mut n_pos = 0;
    let mut n_neg = 0;
    for u in &mut u {
        if *u > 0. {
            n_pos += 1;
        } else if *u < 0. {
            n_neg += 1;
        }
    }
    // check if sign differs (level set goes throught the triangle)
    if n_neg == 3 || n_pos == 3 {
        return None;
    }

    // everything is zero
    if n_neg + n_pos == 0 {
        return Some([0., 0., 0.]);
    }

    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm_rcp = 1. / (gx * gx + gy * gy).sqrt();

    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)

}

/// Initializes the distance around the free boundary.
///
/// Based on the _linear_ level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set (a line) in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
///
/// ```text,ignore
///   0,1 *----* 1,1
///       |   /|
///       |  / |
///       | /  |
///       |/   |
///   0,0 *----* 1,0
/// ```
pub fn init_dist_2d(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    for j in 1..nx {
        for i in 1..ny {
            let s = j * ny + i;
            let vs = [[s - ny, s - ny - 1, s], [s - 1, s - ny - 1, s]];
            for v in &vs {
                let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]]);
                if let Some(e) = r {
                    for i in 0..3 {
                        d[v[i]] = e[i].min(d[v[i]]);
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn simple_triangles() {
        assert_eq!(triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(triangle_dist([1., 1., 1.]), None);
        assert_eq!(triangle_dist([-1., -1., -1.]), None);
        assert_eq!(triangle_dist([0., 1., 0.]), Some([0., 1., 0.]));
        assert_eq!(triangle_dist([0., -1., -1.]), Some([0., 1./(2f64).sqrt(), 1./(2f64).sqrt()]));
        assert_eq!(triangle_dist([0., 1., 1.]), Some([0., 1./(2f64).sqrt(), 1./(2f64).sqrt()]));
        assert_eq!(triangle_dist([1., 1., 0.]), Some([1., 1., 0.]));
        assert_eq!(triangle_dist([-1., 0., 0.]), Some([1./(2f64).sqrt(), 0., 0.]));
    }
}
<commit_msg>Allow for zeros in tetrahedra<commit_after>use std;

/// Computes the signed distance function from a plane given as the _zero_ level set of a
/// linear function on a tetrahedron at 4 points with unit coordinates starting at (0, 0, 0) and
/// ending at (1, 1, 1), and in between exactly one coordinate changes from 0 to 1.
///
/// Inputs are `u`, the values at the vertices.
///
/// The function returns the values of the (non-signed) distance function or `None` if the zero
/// level set does not pass through the tetrahedron.
pub fn tetrahedron_dist(mut u: [f64; 4]) -> Option<[f64; 4]> {
    let mut n_pos = 0;
    let mut n_neg = 0;
    for u in &mut u {
        if *u > 0. {
            n_pos += 1;
        } else if *u < 0. {
            n_neg += 1;
        }
    }
    // check if sign differs (level set goes throught the triangle)
    if n_neg == 4 || n_pos == 4 {
        return None;
    }

    // everything is zero
    if n_neg + n_pos == 0 {
        return Some([0.; 4]);
    }

    let g_norm_rcp = 1. / u.windows(2).fold(0., |sum, x| sum + (x[1] - x[0]).powi(2)).sqrt();

    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)
}

/// Initializes the distance around the free boundary.
///
/// Based on the level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist_3d(d: &mut [f64], u: &[f64], dim: (usize, usize, usize)) {
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, u.len());
    assert_eq!(nx * ny * nz, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    // split each cube into 6 tetrahedrons
    let ids = [[(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1)],
               [(0, 0, 0), (1, 0, 0), (1, 0, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 1, 1)],
               [(0, 0, 0), (0, 1, 0), (0, 1, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 0, 1), (1, 0, 1), (1, 1, 1)],
               [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)]];

    for i in 1..nx {
        for j in 1..ny {
            for k in 1..nz {
                let s = i * ny * nz + j * nz + k;
                let mut v = [0.; 4];

                for idx in ids.iter() {
                    for m in 0..4 {
                        v[m] = u[s - idx[m].0 * ny * nz - idx[m].1 * nz - idx[m].2];
                    }

                    let r = tetrahedron_dist(v);
                    if let Some(r) = r {
                        for m in 0..4 {
                            let q = s - idx[m].0 * ny * nz - idx[m].1 * nz - idx[m].2;
                            d[q] = d[q].min(r[m]);
                        }
                    }
                }
            }
        }
    }
}
/// Computes the signed distance function from a line given as the _zero_ level set of a
/// linear function on an isosceles right triangle. It preserves level sets of linear functions.
///
/// There does not see to be much point of trying to be smart and compute the distance to the line
/// segments within the triangle. This shifts the level set even in a symmetric case when not
/// needed. This simpler approach here seems to better preserve corners in the crystalline mean
/// curvature flow.
///
/// Inputs are the values at the vertices. The vertex 0 is the one with the right angle.
///
/// The function returns the values of the distance function or `None` if the zero level set
/// does not pass through the triangle.
pub fn triangle_dist(mut u: [f64; 3]) -> Option<[f64; 3]> {
    let mut n_pos = 0;
    let mut n_neg = 0;
    for u in &mut u {
        if *u > 0. {
            n_pos += 1;
        } else if *u < 0. {
            n_neg += 1;
        }
    }
    // check if sign differs (level set goes throught the triangle)
    if n_neg == 3 || n_pos == 3 {
        return None;
    }

    // everything is zero
    if n_neg + n_pos == 0 {
        return Some([0., 0., 0.]);
    }

    let gx = u[1] - u[0];
    let gy = u[2] - u[0];
    let g_norm_rcp = 1. / (gx * gx + gy * gy).sqrt();

    for u in u.iter_mut() {
        *u = u.abs() * g_norm_rcp;
    }
    Some(u)

}

/// Initializes the distance around the free boundary.
///
/// Based on the _linear_ level set function with values `u` given on a regular grid, it computes the
/// distance from the _zero_ level set (a line) in the nodes of the triangles through which the level set
/// passes.  Stores the result in the preallocated slice `d`.
///
/// Nodes away from the boundary have their value set to `std::f64::MAX`.
///
/// Splits every square into two triangles and computes the distance on each of them.
///
/// ```text,ignore
///   0,1 *----* 1,1
///       |   /|
///       |  / |
///       | /  |
///       |/   |
///   0,0 *----* 1,0
/// ```
pub fn init_dist_2d(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    let (nx, ny) = dim;
    assert_eq!(nx * ny, u.len());
    assert_eq!(nx * ny, d.len());

    for d in &mut *d {
        *d = std::f64::MAX;
    }

    for j in 1..nx {
        for i in 1..ny {
            let s = j * ny + i;
            let vs = [[s - ny, s - ny - 1, s], [s - 1, s - ny - 1, s]];
            for v in &vs {
                let r = triangle_dist([u[v[0]], u[v[1]], u[v[2]]]);
                if let Some(e) = r {
                    for i in 0..3 {
                        d[v[i]] = e[i].min(d[v[i]]);
                    }
                }
            }
        }
    }
}

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

    #[test]
    fn simple_triangles() {
        assert_eq!(triangle_dist([0., 0., 0.]), Some([0., 0., 0.]));
        assert_eq!(triangle_dist([1., 1., 1.]), None);
        assert_eq!(triangle_dist([-1., -1., -1.]), None);
        assert_eq!(triangle_dist([0., 1., 0.]), Some([0., 1., 0.]));
        assert_eq!(triangle_dist([0., -1., -1.]), Some([0., 1./(2f64).sqrt(), 1./(2f64).sqrt()]));
        assert_eq!(triangle_dist([0., 1., 1.]), Some([0., 1./(2f64).sqrt(), 1./(2f64).sqrt()]));
        assert_eq!(triangle_dist([1., 1., 0.]), Some([1., 1., 0.]));
        assert_eq!(triangle_dist([-1., 0., 0.]), Some([1./(2f64).sqrt(), 0., 0.]));
    }
}
<|endoftext|>