Почему переменная должна продолжать жить после потребления продукции? - PullRequest
0 голосов
/ 20 октября 2019
use std::cell::RefCell;
use std::collections::VecDeque;

// minimum reproducible example for stack overflow question
// which is essentially the whole thing b/c all of these types
// depend on each other

// this is an implementation of Monopoly Deal (see http://monopolydealrules.com/)
// but the only relevant part to the question is in main(), around line 400

// card.rs

pub trait Card {
    fn value(&self) -> i32;

    fn kind(&self) -> CardKind;
}

pub enum CardKind {
    Money,
    Action,
    Property,
    Building,
}

// property.rs

pub struct PropertySet {
    color: Color,
    properties: Vec<Property>,
    house: bool,
    hotel: bool,
}

impl PropertySet {
    pub fn rent(&self) -> i32 {
        unimplemented!() // stub
    }

    pub fn color(&self) -> Color {
        self.color
    }

    pub fn properties(&self) -> &Vec<Property> {
        &self.properties
    }

    pub fn is_full(&self) -> bool {
        self.properties().len() == self.color.set_size() as usize
    }

    pub fn is_empty(&self) -> bool {
        self.properties().len() == 0
    }

    pub fn add(&mut self, property: Property) -> Result<(), PropertySetAddError> {
        if !property.matches(self.color) {
            return Err(PropertySetAddError {
                property,
                kind: PropertySetAddErrorKind::WrongColor,
            });
        }

        if self.properties.len() + 1 < self.color.set_size() as usize {
            self.properties.push(property);
            Ok(())
        } else {
            Err(PropertySetAddError {
                property,
                kind: PropertySetAddErrorKind::SetFull,
            })
        }
    }

    fn remove(&mut self, index: usize) -> Property {
        self.properties.remove(index)
    }
}

pub struct PropertySetAddError {
    property: Property,
    kind: PropertySetAddErrorKind,
}

pub enum PropertySetAddErrorKind {
    WrongColor,
    SetFull,
}

pub enum Property {
    Basic { name: String, color: Color },
    Wild { colors: [Color; 2], value: i32 },
    Any,
}

impl Card for Property {
    fn value(&self) -> i32 {
        unimplemented!() // stub
    }

    fn kind(&self) -> CardKind {
        CardKind::Property
    }
}

impl Property {
    pub fn matches(&self, color: Color) -> bool {
        unimplemented!() // stub
    }
}

#[derive(Eq, PartialEq, Hash, Copy, Clone)]
pub enum Color {
    Red,
    Orange,
    Yellow,
    Green,
    LightBlue,
    DarkBlue,
    Magenta,
    Brown,
    Utility,
    Railroad,
}

impl Color {
    pub fn set_size(&self) -> i32 {
        unimplemented!() // stub
    }
}

// money.rs

#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Money(pub i32);

impl Card for Money {
    fn value(&self) -> i32 {
        self.0
    }

    fn kind(&self) -> CardKind {
        CardKind::Money
    }
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct Id(pub usize);

pub struct Possessions {
    bank: Vec<Money>,
    hand: Vec<Box<dyn Card>>,
    properties: Vec<PropertySet>,
}

// brain.rs

pub trait Brain {
    fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect>;

    fn react(
        &self,
        state: &GameState,
        possessions: &mut Possessions,
        effect: &Effect,
    ) -> Vec<Effect>;
}

pub struct Human {}

impl Human {
    pub fn new() -> Human {
        Human {}
    }
}

impl Brain for Human {
    fn act(&self, state: &GameState, possessions: &mut Possessions) -> Vec<Effect> {
        unimplemented!()
    }

    fn react(
        &self,
        state: &GameState,
        possessions: &mut Possessions,
        effect: &Effect,
    ) -> Vec<Effect> {
        unimplemented!()
    }
}

// action.rs

pub enum Action {
    Rent { colors: [Color; 2] },
    AnyRent,
    DoubleRent,
    DealBreaker,
    DebtCollector,
    Birthday,
    SayNo,
    PassGo,
    SlyDeal,
    ForcedDeal,
}

impl Card for Action {
    fn value(&self) -> i32 {
        unimplemented!() // stub
    }

    fn kind(&self) -> CardKind {
        CardKind::Action
    }
}

impl Action {
    pub fn effect<'a>(
        &self,
        source: Id,
        target: ActionTarget<'a>,
    ) -> Result<Effect<'a>, EffectError> {
        unimplemented!() // stub
    }
}

pub enum ActionTarget<'a> {
    None,

    Player {
        player: Id,
    },

    Set {
        /// The player that this action is targeted against
        player: Id,

        /// Can be a set that player owns, such as in the case of Deal Breaker, or it
        /// can be a set that the source owns, such as in the case of rent cards
        set: &'a PropertySet,
    },

    Property {
        player: Id,
        property: (&'a PropertySet, usize),
    },

    Swap {
        player: Id,
        take: (&'a PropertySet, usize),
        give: (&'a PropertySet, usize),
    },
}

// effect.rs

#[derive(Clone)]
pub enum Effect<'a> {
    // swaps properties with another player
    Swap {
        source: Id,
        target: Id,
        give: (&'a PropertySet, usize),
        take: (&'a PropertySet, usize),
    },

    // steals properties from another player
    Steal {
        source: Id,
        target: Id,
        set: &'a PropertySet,
        indices: Vec<usize>,
    },

    // charges another player
    Charge {
        source: Id,
        target: Option<Id>,
        amount: i32,
        reason: ChargeReason,
    },

    // cancels prior effect
    Cancel {
        source: Id,
        target: Id,
    },

    // pass Go, credit $2M
    Go {
        source: Id,
    },
}

#[derive(Clone)]
pub enum ChargeReason {
    Rent,
    Birthday,
    DebtCollector,
}

pub enum EffectError {
    /// The target supplied was not valid for this action.
    InvalidTarget,

    /// You tried to charge rent for a color, but the specified set isn't that color
    NoProperty,
}

// player.rs

pub struct Player {
    pub id: Id,
    pub name: String,
    pub possessions: Possessions,
    pub brain: Box<dyn Brain>,
}

impl Player {
    pub fn new(id: Id, name: String, brain: Box<dyn Brain>) -> Player {
        Player {
            id,
            possessions: Possessions {
                bank: vec![],
                hand: vec![],
                properties: vec![],
            },
            name,
            brain,
        }
    }

    pub fn id(&self) -> Id {
        self.id
    }
    pub fn bank(&self) -> &Vec<Money> {
        &self.possessions.bank
    }
    pub fn properties(&self) -> &Vec<PropertySet> {
        &self.possessions.properties
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn brain(&self) -> &Box<dyn Brain> {
        &self.brain
    }

    pub fn act(&mut self, state: &GameState) -> Vec<Effect> {
        self.brain.act(state, &mut self.possessions)
    }

    pub fn react(&mut self, state: &GameState, effect: &Effect) -> Vec<Effect> {
        self.brain.react(state, &mut self.possessions, effect)
    }
}

// state.rs

pub struct GameState {
    pub players: Vec<RefCell<Player>>,
    pub current: Id,
    pub stack: Vec<Box<dyn Card>>,
}

impl GameState {
    pub fn next(&mut self) {
        self.current = Id((self.current.0 + 1) % self.players.len())
    }

    pub fn current_player(&self) -> &RefCell<Player> {
        self.players.get(self.current.0).unwrap()
    }

    pub fn get_player(&self, id: Id) -> Option<&RefCell<Player>> {
        self.players.get(id.0)
    }
}

// deck.rs

pub fn create_deck() -> Vec<Box<dyn Card>> {
    vec![
        // ...
    ]
}

// main.rs

pub fn main() {
    let brain = Human::new(); // Human implements Brain
    let me = Player::new(Id(0), "Ibi".to_owned(), Box::new(brain));
    let current = me.id();
    let players = vec![RefCell::new(me)];
    let stack = create_deck(); // returns Vec<Box<dyn Card>>

    let mut state = GameState {
        players,
        stack,
        current,
    };

    while !state.players.iter().any(|player| {
        player
            .borrow()
            .properties()
            .iter()
            .filter(|&set| set.is_full())
            .count()
            >= 3
    }) {
        // ...

        let mut effects = VecDeque::new();

        {
            let mut current_player = state.current_player().borrow_mut();
            let action = current_player.act(&state);
            effects.extend(action);
        }

        // let all other players react to effects until no more reactions are generated
        while !effects.is_empty() {
            let effect = effects.pop_front().unwrap();

            // ...
        }
    }
}

Я не могу получить этот код для компиляции;он говорит, что current_player не живет достаточно долго и жалуется, что он сброшен в конце блока. Почему current_player нужно выживать после конца блока? Насколько я понимаю, он возвращает Vec<Effect>, которым теперь владеет мой метод, а затем этот вектор используется extend(), а содержащиеся в нем значения теперь принадлежат effects, так почему же current_player все еще необходимо?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...