konnektoren_core/game/
game.rs

1use super::GamePath;
2use crate::Xp;
3use crate::challenges::{
4    Challenge, ChallengeConfig, ChallengeFactory, ChallengeHistory, Performance,
5};
6use crate::game::error::{GameError, Result};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct Game {
11    pub game_paths: Vec<GamePath>,
12    pub challenge_factory: ChallengeFactory,
13    pub challenge_history: ChallengeHistory,
14    pub xp: Xp,
15}
16
17impl Default for Game {
18    fn default() -> Self {
19        let game_path = GamePath::default();
20        Game {
21            game_paths: vec![game_path],
22            challenge_factory: ChallengeFactory::default(),
23            challenge_history: Default::default(),
24            xp: Default::default(),
25        }
26    }
27}
28
29impl Game {
30    pub fn find_game_path_index(&self, challenge_id: &str) -> Option<usize> {
31        self.game_paths.iter().position(|game_path| {
32            game_path
33                .challenge_ids()
34                .contains(&challenge_id.to_string())
35        })
36    }
37
38    pub fn create_challenge(&self, challenge_config_id: &str) -> Result<Challenge> {
39        let challenge_config = self
40            .get_challenge_config(challenge_config_id)
41            .ok_or_else(|| GameError::ChallengeNotFound(challenge_config_id.to_string()))?;
42
43        self.challenge_factory
44            .create_challenge(&challenge_config)
45            .map_err(GameError::ChallengeError)
46    }
47
48    pub fn get_challenge_config(&self, challenge_config_id: &str) -> Option<ChallengeConfig> {
49        self.game_paths
50            .iter()
51            .map(|game_path| game_path.get_challenge_config(challenge_config_id))
52            .find(|challenge_config| challenge_config.is_some())
53            .flatten()
54            .cloned()
55    }
56
57    pub fn calculate_xp_reward(&self, challenge: &Challenge) -> Xp {
58        challenge.performance(&challenge.challenge_result)
59            * challenge.stars(&challenge.challenge_result)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn create_challenge() {
69        let game = Game::default();
70        let challenge = game.create_challenge("unknown");
71        assert!(challenge.is_err());
72        assert_eq!(game.game_paths[0].challenge_ids().len(), 8);
73        assert_eq!(
74            game.game_paths[0].challenge_ids(),
75            vec![
76                "konnektoren-1",
77                "konnektoren-2",
78                "konnektoren-3",
79                "konnektoren-4",
80                "konnektoren-5",
81                "articles-1",
82                "past-tense-1",
83                "sentence-structure-1"
84            ]
85        );
86        let challenge = game.create_challenge("konnektoren-1");
87        assert!(challenge.is_ok());
88    }
89
90    #[test]
91    fn calculate_xp_reward() {
92        let game = Game::default();
93        let challenge = game.create_challenge("konnektoren-1").unwrap();
94        let xp = game.calculate_xp_reward(&challenge);
95        assert_eq!(xp, 0);
96    }
97
98    #[test]
99    fn get_challenge_config() {
100        let game = Game::default();
101        let challenge_config = game.get_challenge_config("konnektoren-1");
102        assert!(challenge_config.is_some());
103    }
104
105    #[test]
106    fn find_game_path_index() {
107        let game = Game::default();
108        let index = game.find_game_path_index("konnektoren-1");
109        assert_eq!(index, Some(0));
110    }
111}