Created
May 17, 2014 00:45
-
-
Save nulldatamap/c8bf55e8189c1b7ce1b3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // game.rs | |
| extern crate rand; | |
| use self::rand::Rng; | |
| use std::io; | |
| // Used for easily modifiable rules | |
| pub struct GameRules { | |
| // Deck rules | |
| maxDeckSize : int, | |
| minDeckSize : int, | |
| maxCardDuplicates: int, | |
| maxMinionCount : int, | |
| maxBaseCount : int, | |
| minMinionCount : int, | |
| minBaseCount : int, | |
| maxEventCount : int, | |
| minEventCount : int, | |
| maxActionCount : int, | |
| minActionCount : int, | |
| maxStructureCount: int, | |
| minStructureCount: int, | |
| // Game rules | |
| startingBases : int, | |
| startingDraw : int, | |
| mulliganCount : int, | |
| startingResouces : int, | |
| resourceGain : int, | |
| cardGain : int, | |
| maxHandSize : int, | |
| playfieldSize : int, | |
| baseSlotCount : int, | |
| maxMinionHealth : int, | |
| maxMinionAttack : int, | |
| } | |
| pub static defaultRules : GameRules = GameRules { | |
| maxDeckSize : 30, | |
| minDeckSize : 30, | |
| maxCardDuplicates: 2, | |
| maxMinionCount : 30, | |
| minMinionCount : 0, | |
| maxBaseCount : 5, | |
| minBaseCount : 0, | |
| maxEventCount : 30, | |
| minEventCount : 0, | |
| maxActionCount : 30, | |
| minActionCount : 0, | |
| maxStructureCount: 30, | |
| minStructureCount: 0, | |
| // Game rules | |
| startingBases : 1, | |
| startingDraw : 3, | |
| mulliganCount : 1, | |
| startingResouces : 1, | |
| resourceGain : 1, | |
| cardGain : 2, | |
| maxHandSize : 10, | |
| playfieldSize : 9, | |
| baseSlotCount : 3, | |
| maxMinionHealth : 100, | |
| maxMinionAttack : 100, | |
| }; | |
| pub struct Game<'a> { | |
| rules : GameRules, | |
| friendly : Player, | |
| opponent : Player, | |
| state : State, | |
| board : Board<'a> | |
| } | |
| impl<'a> Game<'a> { | |
| pub fn new<'a>( r : GameRules, fd : Vec<Card>, od : Vec<Card> ) -> Option<Game<'a>> { | |
| if validateDeck( &od, r ) && validateDeck( &fd, r ) { | |
| return Some( Game{ rules: r | |
| , friendly: Player::new( fd ) | |
| , opponent: Player::new( od ) | |
| , state : State::initalState() | |
| , board : Board::empty() } ); | |
| }else { | |
| return None; | |
| } | |
| } | |
| /* | |
| Game order: | |
| = Game join | |
| ! Both join with a valid deck. | |
| ! A random base is drawn and played for each player. | |
| ! Each player draw 3 cards | |
| Each is allowed to mulligan each of the drawn cards once. | |
| = Player turn | |
| Draw a card. | |
| % Turn start | |
| Trigger turn start event | |
| % Turn Action { | |
| Let player play any card they can afford, and sacrifice once. | |
| Trigger turn action events | |
| % Turn Action } | |
| % End turn | |
| Trigger turn end event | |
| Opponents turn. | |
| */ | |
| pub fn startGame<'a>( &mut self ) { | |
| self.friendly.shuffleDeck(); | |
| self.opponent.shuffleDeck(); | |
| self.friendly.drawAnyCards( self.rules.startingDraw ); | |
| self.opponent.drawAnyCards( self.rules.startingDraw ); | |
| let fhand = self.getMulliganInput(); | |
| self.friendly.mulligan( fhand ); | |
| let ohand = self.getMulliganInput(); | |
| self.opponent.mulligan( ohand ); | |
| } | |
| pub fn getMulliganInput( &self ) -> Vec<bool> { | |
| let mut lne; | |
| println!( "Cards to mulligan: " ); | |
| loop { | |
| match io::stdin().read_line() { | |
| Ok( _inp ) => lne = _inp, | |
| Err( err ) => fail!( "Fail to get mulligan: {}", err.desc ) | |
| } | |
| } | |
| } | |
| } | |
| pub enum Turn { | |
| FriendlyTurn, | |
| OpponentTurn | |
| } | |
| pub enum Phase { | |
| StartingPhase, | |
| MidPhase, | |
| EndingPhase | |
| } | |
| pub struct State { | |
| turn : Turn, | |
| phase : Phase | |
| } | |
| impl State { | |
| pub fn initalState() -> State { | |
| State{ turn: FriendlyTurn, phase: StartingPhase } | |
| } | |
| } | |
| pub struct Player { | |
| deck : Vec<Card>, | |
| hand : Vec<Card>, | |
| graviyard : Vec<Card>, | |
| resources : int | |
| } | |
| impl Player { | |
| pub fn new( deck : Vec<Card> ) -> Player { | |
| return Player{ deck: deck | |
| , hand: Vec::new() | |
| , graviyard: Vec::new() | |
| , resources: 0 }; | |
| } | |
| pub fn shuffleDeck( &mut self ) { | |
| let size = self.deck.len(); | |
| let mut ndeck = Vec::with_capacity( size ); | |
| let mut rng = rand::task_rng(); | |
| loop { | |
| let ds = self.deck.len(); | |
| match self.deck.swap_remove( rng.gen::<uint>() % ds ) { | |
| Some( card ) => ndeck.push( card ), | |
| None => break | |
| } | |
| } | |
| self.deck = ndeck; | |
| } | |
| pub fn drawAnyCards( &mut self, amount : int ) { | |
| for _ in range::<int>( 0, amount ) { | |
| match self.deck.pop() { | |
| Some( card ) => self.hand.push( card ), | |
| None => break | |
| } | |
| } | |
| } | |
| pub fn mulligan( &mut self, keeps : Vec<bool> ) { | |
| if self.hand.len() != keeps.len() { | |
| fail!( "Mismatched hand and mulligan vectors." ); | |
| } | |
| let mut nhand = Vec::new(); | |
| for i in range( 0, keeps.len() ) { | |
| let card = *self.hand.get( i ); | |
| if !keeps.get( i ) { | |
| self.deck.push( card ); | |
| }else { | |
| nhand.push( card ); | |
| } | |
| } | |
| let missing = keeps.len() - nhand.len(); | |
| self.hand = nhand; | |
| if missing > 0 { | |
| self.drawAnyCards( missing as int ); | |
| } | |
| } | |
| } | |
| pub struct BoardHalf<'a> { | |
| playfield : Vec<Minion<'a>>, | |
| events : Vec< |&'a mut Base<'a>, &'a mut Game<'a>| : 'a -> bool > , | |
| bases : Vec<Base<'a>> | |
| } | |
| impl<'a> BoardHalf<'a> { | |
| pub fn empty<'a>() -> BoardHalf<'a> { | |
| BoardHalf{ playfield: Vec::new(), events: Vec::new(), bases: Vec::new() } | |
| } | |
| } | |
| pub struct Board<'a> { | |
| frieldyHalf : BoardHalf<'a>, | |
| opponentHalf : BoardHalf<'a> | |
| } | |
| impl<'a> Board<'a> { | |
| pub fn empty<'a>() -> Board<'a> { | |
| Board{ frieldyHalf: BoardHalf::empty(), opponentHalf: BoardHalf::empty() } | |
| } | |
| } | |
| pub struct Minion<'a> { | |
| health : int, | |
| maxHealth : int, | |
| attack : int, | |
| card : MinionCard<'a> | |
| } | |
| pub struct Base<'a> { | |
| health : int, | |
| maxSlotCount : int, | |
| slots : Vec<Structure<'a>>, | |
| card : &'a BaseCard<'a> | |
| } | |
| pub struct Structure<'a> { | |
| health : int, | |
| maxHealth : int, | |
| attack : int, | |
| card : &'a StructureCard<'a> | |
| } | |
| pub enum CardKind<'a> { | |
| MinionKind( MinionCard<'a> ), | |
| BaseKind( BaseCard<'a> ), | |
| EventKind( EventCard<'a> ), | |
| ActionKind( ActionCard<'a> ), | |
| StructureKind( StructureCard<'a> ) | |
| } | |
| struct MinionCard<'a> { | |
| health : int, | |
| attack : int, | |
| behaviour : Vec< |&'a mut Minion<'a>, &'a mut Game<'a>| : 'a > | |
| } | |
| struct BaseCard<'a> { | |
| health : int, | |
| slotCount : int, | |
| behaviour : Vec< |&'a mut Base<'a>, &'a mut Game<'a>| : 'a > | |
| } | |
| type EventCard<'a> = |&'a mut Game<'a>| : 'a; | |
| type ActionCard<'a> = |&'a mut Game<'a>| : 'a -> bool; | |
| struct StructureCard<'a> { | |
| health : int, | |
| attack : int, | |
| behaviour : Vec< |&'a mut Structure, &'a mut Game| : 'a > | |
| } | |
| pub struct CardDestriptor<'a> { | |
| cost : int, | |
| name : ~str, | |
| text : ~str, | |
| flavor : ~str, | |
| kind : CardKind<'a> | |
| } | |
| // Card is just a reference to a CardDestriptor | |
| // and the cost ( since that can change ) | |
| pub struct Card { | |
| cost : int, | |
| descriptor : &'static CardDestriptor<'static> | |
| } | |
| pub fn validateDeck( deck : &Vec<Card>, rules : GameRules ) -> bool { | |
| let mut acc = deck.len() as int <= rules.maxDeckSize; | |
| acc &= deck.len() as int >= rules.minDeckSize; | |
| return acc; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment