1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Some clarifications on how we play the game:
//
// Players: 1) Computer, 2) Opponent
// Board:   is numerated from 1-24 beginning on the start point of the Computer. Opponent facing,
//          this is switched and visible from the API's perspective. The bar will be used on
//          position 25, if necessary.

extern crate rand;
use rand::{OsRng, Rng};

// State holds the situation and the accounting information
pub struct State {
    free_positions_computer: u32,
    free_positions_opponent: u32,
    accounting: Accounting,
}

/// Accounting holds the number of stones in each position and the level of the doubling cube
pub struct Accounting {
    // negative values represent Opponent's stones, number 25 is the Computer's bar, number 26 is
    // the Opponent's bar
    board: [i8; 26],

    // this displays the n-th power of 2, negative number means it is owned by the opponent
    cube: i8,
}

pub struct Game {
    points: u32,
    history: Vec<State>,
}

pub struct Match {
    max_points: u32,
    history: Vec<Game>,
}

impl State {
    fn calculate_free_positions(&mut self) {
        // set free positions of computer to zero
        self.free_positions_computer = 0;
        self.free_positions_opponent = 0;

        // check bar first
        if self.accounting.board[24] > 0 {
            for i in 0..5 {
                if self.accounting.board[i] > -2 {
                    self.free_positions_computer |= 2u32.pow(i as u32);
                }
            }
        } else {
            for i in 0..23 {
                if self.accounting.board[i] > -2 {
                    self.free_positions_computer |= 2u32.pow(i as u32);
                }
            }


            if self.accounting.board[25] > 0 {
                // set free positions of computer to zer
                self.free_positions_opponent = 0;
                for i in 18..23 {
                    if self.accounting.board[i] > -1 {
                        self.free_positions_computer |= 2u32.pow(i as u32);
                    }
                }
            }



        }
    }
}

pub fn reset() -> State {
    let mut x = State {
        // TODO: free_position calculation
        free_positions_computer: 0,
        free_positions_opponent: 0,
        accounting: Accounting {
            board: [
                2,
                0,
                0,
                0,
                0,
                -5,
                0,
                -3,
                0,
                0,
                0,
                5,
                -5,
                0,
                0,
                0,
                3,
                0,
                5,
                0,
                0,
                0,
                0,
                -2,
                0,
                0,
            ],
            cube: 1,
        },
    };

    x.calculate_free_positions();

    return x;
}


/// roll generates two random numbers between 1 and 6, replicating a perfect dice. We use the
/// operating systems random number generator
fn roll() -> [u8; 2] {
    let mut rng = match OsRng::new() {
        Ok(g) => g,
        Err(e) => panic!("Failed to obtain OS RNG: {}", e),
    };

    return [rng.gen_range(1, 7), rng.gen_range(1, 7)];
}