github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/examples/xo_rust/src/handler/game.rs (about) 1 /* 2 * Copyright 2018 Bitwise IO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * ----------------------------------------------------------------------------- 16 */ 17 18 use std::collections::HashMap; 19 20 use sawtooth_sdk::processor::handler::ApplyError; 21 22 const POSSIBLE_WINS: [(usize, usize, usize); 8] = [ 23 (1, 2, 3), 24 (4, 5, 6), 25 (7, 8, 9), 26 (1, 4, 7), 27 (2, 5, 8), 28 (3, 6, 9), 29 (1, 5, 9), 30 (3, 5, 7), 31 ]; 32 33 #[derive(Debug, Clone)] 34 pub struct Game { 35 name: String, 36 board: String, 37 game_state: String, 38 player1: String, 39 player2: String, 40 player1_short: String, 41 player2_short: String, 42 } 43 44 impl Game { 45 pub fn new(name: String) -> Game { 46 Game { 47 name: name, 48 board: "-".repeat(9), 49 game_state: String::from("P1-NEXT"), 50 player1: String::from(""), 51 player2: String::from(""), 52 player1_short: String::from(""), 53 player2_short: String::from(""), 54 } 55 } 56 57 fn to_string(&self) -> String { 58 let fields = vec![ 59 self.name.clone(), 60 self.board.clone(), 61 self.game_state.clone(), 62 self.player1.clone(), 63 self.player2.clone(), 64 ]; 65 fields.join(",") 66 } 67 68 fn from_string(game_string: String) -> Option<Game> { 69 let items: Vec<&str> = game_string.split(",").collect(); 70 if items.len() != 5 { 71 return None; 72 } 73 let mut g = Game { 74 name: items[0].to_string(), 75 board: items[1].to_string(), 76 game_state: items[2].to_string(), 77 player1: String::from(""), 78 player2: String::from(""), 79 player1_short: String::from(""), 80 player2_short: String::from(""), 81 }; 82 g.set_player1(items[3]); 83 g.set_player2(items[4]); 84 Some(g) 85 } 86 87 pub fn serialize_games(games: HashMap<String, Game>) -> String { 88 let mut game_strings: Vec<String> = vec![]; 89 for (_, game) in games { 90 game_strings.push(game.to_string().clone()); 91 } 92 game_strings.sort(); 93 game_strings.join("|") 94 } 95 96 pub fn deserialize_games(games_string: String) -> Option<HashMap<String, Game>> { 97 let mut ret: HashMap<String, Game> = HashMap::new(); 98 let game_string_list: Vec<&str> = games_string.split("|").collect(); 99 for g in game_string_list { 100 let game = Game::from_string(g.to_string()); 101 match game { 102 Some(game_item) => ret.insert(game_item.name.clone(), game_item), 103 None => return None, 104 }; 105 } 106 Some(ret) 107 } 108 109 pub fn mark_space(&mut self, space: usize) -> Result<(), ApplyError> { 110 let mark = match self.game_state.as_str() { 111 "P1-NEXT" => "X", 112 "P2-NEXT" => "O", 113 other_state => { 114 return Err(ApplyError::InvalidTransaction(String::from(format!( 115 "Invalid state {}", 116 other_state 117 )))) 118 } 119 }; 120 121 let index = space - 1; 122 123 let board_vec: Vec<String> = self.board 124 .chars() 125 .enumerate() 126 .map(|(i, ch)| { 127 if i == index { 128 mark.to_string() 129 } else { 130 ch.to_string() 131 } 132 }) 133 .collect(); 134 self.board = board_vec.join(""); 135 Ok(()) 136 } 137 138 pub fn update_state(&mut self) -> Result<(), ApplyError> { 139 let x_wins = self.is_win("X"); 140 let o_wins = self.is_win("O"); 141 142 let winner = match (x_wins, o_wins) { 143 (true, true) => { 144 return Err(ApplyError::InvalidTransaction(String::from( 145 "Two winners (there can only be one)", 146 ))) 147 } 148 (true, false) => Some(String::from("P1-WIN")), 149 (false, true) => Some(String::from("P2-WIN")), 150 _ => None, 151 }; 152 153 if let Some(w) = winner { 154 self.game_state = w; 155 return Ok(()); 156 } 157 158 if !self.board.contains("-") { 159 self.game_state = String::from("TIE"); 160 return Ok(()); 161 } 162 163 if self.game_state.as_str() == "P1-NEXT" { 164 self.game_state = String::from("P2-NEXT"); 165 return Ok(()); 166 } 167 168 if self.game_state.as_str() == "P2-NEXT" { 169 self.game_state = String::from("P1-NEXT"); 170 return Ok(()); 171 } 172 173 Err(ApplyError::InvalidTransaction(String::from(format!( 174 "Unhandled state: {}", 175 self.game_state 176 )))) 177 } 178 179 pub fn is_win(&self, letter: &str) -> bool { 180 let letter = letter.to_string(); 181 for (i1, i2, i3) in POSSIBLE_WINS.iter() { 182 let board_chars: Vec<char> = self.board.chars().collect(); 183 if board_chars[*i1 - 1].to_string() == letter 184 && board_chars[*i2 - 1].to_string() == letter 185 && board_chars[*i3 - 1].to_string() == letter 186 { 187 return true; 188 } 189 } 190 false 191 } 192 193 pub fn display(&self) { 194 let b: Vec<char> = self.board.chars().collect(); 195 info!( 196 " 197 GAME: {} 198 PLAYER 1: {} 199 PLAYER 2: {} 200 STATE: {} 201 202 {} | {} | {} 203 ---|---|--- 204 {} | {} | {} 205 ---|---|--- 206 {} | {} | {} 207 ", 208 self.name, 209 self.player1, 210 self.player2, 211 self.game_state, 212 b[0], 213 b[1], 214 b[2], 215 b[3], 216 b[4], 217 b[5], 218 b[6], 219 b[7], 220 b[8] 221 ); 222 } 223 224 pub fn get_state(&self) -> String { 225 self.game_state.clone() 226 } 227 228 pub fn get_player1(&self) -> String { 229 self.player1.clone() 230 } 231 232 pub fn get_player2(&self) -> String { 233 self.player2.clone() 234 } 235 236 pub fn get_board(&self) -> String { 237 self.board.clone() 238 } 239 240 pub fn set_player1(&mut self, p1: &str) { 241 self.player1 = p1.to_string(); 242 if p1.len() > 6 { 243 self.player1_short = p1[..6].to_string(); 244 } else { 245 self.player1_short = String::from(p1); 246 } 247 } 248 249 pub fn set_player2(&mut self, p2: &str) { 250 self.player2 = p2.to_string(); 251 if p2.len() > 6 { 252 self.player2_short = p2[..6].to_string(); 253 } else { 254 self.player2_short = String::from(p2); 255 } 256 } 257 } 258 259 impl PartialEq for Game { 260 fn eq(&self, other: &Self) -> bool { 261 self.name == other.name && self.game_state == other.board 262 && self.game_state == other.game_state && self.player1 == other.player1 263 && self.player2 == other.player2 264 } 265 }