ms-toollib
Advanced tools
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
+1
-1
| [package] | ||
| name = "ms_toollib" | ||
| version = "1.5.2" | ||
| version = "1.5.3" | ||
| description = "Algorithms for Minesweeper" | ||
@@ -5,0 +5,0 @@ documentation = "https://docs.rs/ms_toollib" |
+1
-1
@@ -1,2 +0,2 @@ | ||
| use crate::videos::{ErrReadVideoReason, EvfVideo, NewSomeVideo, NewSomeVideo2}; | ||
| use crate::videos::{ErrReadVideoReason, EvfVideo, NewSomeVideo2}; | ||
| use crate::videos::byte_reader::ByteReader; | ||
@@ -3,0 +3,0 @@ #[cfg(any(feature = "py", feature = "rs"))] |
@@ -396,10 +396,10 @@ use crate::algorithms::{cal_probability_cells_not_mine, mark_board}; | ||
| let c_1 = last_event.x as usize / video.cell_pixel_size as usize; | ||
| // if video.video_action_state_recorder[ide].mouse == "lr" || video.video_action_state_recorder[ide].mouse == "rr"{ | ||
| // println!("{:?}+++{:?}", video.video_action_state_recorder[last_ide].time, video.video_action_state_recorder[last_ide].mouse_state); | ||
| // // println!("---{:?}", video.video_action_state_recorder[ide].useful_level); | ||
| // if mouse_event.mouse == "rc" || mouse_event.mouse == "rc"{ | ||
| // println!("{:?}, {:?}, {:?}, {:?}", vas.time, vas.mouse_state, x, y); | ||
| // println!("---{:?}", video.video_action_state_recorder[ide].useful_level); | ||
| // } | ||
| if mouse_event.mouse == "rc" | ||
| && vas.useful_level == 1 | ||
| && vas.prior_game_board.as_ref().unwrap().borrow().game_board[x][y] == 10 | ||
| && vas.useful_level == 1 | ||
| { | ||
@@ -406,0 +406,0 @@ // 正确的标雷 |
@@ -5,3 +5,3 @@ use crate::miscellaneous::s_to_ms; | ||
| use crate::safe_board::BoardSize; | ||
| use std::cmp::{max, min}; | ||
| use std::cmp::min; | ||
| use std::path::Path; | ||
@@ -454,3 +454,3 @@ use std::thread; | ||
| .extend_from_slice(&self.game_dynamic_params.rtime_ms.to_be_bytes()); | ||
| if self.country.len() < 2 { | ||
| if self.country.len() != 2 { | ||
| self.raw_data.extend("XX".as_bytes()); | ||
@@ -457,0 +457,0 @@ } else { |
@@ -294,4 +294,7 @@ use crate::miscellaneous::s_to_ms; | ||
| pub fn set_country(&mut self, country: String) -> Result<u8, ()> { | ||
| // 读取录像文件后,有可能要转存。此时,例如rmv,录像中的国家信息是用户手动输入的 | ||
| // 需要在外部传入。因为所有国家的文本信息有39k,放在工具箱里不合适 | ||
| if self.game_board_state != GameBoardState::Loss | ||
| && self.game_board_state != GameBoardState::Win | ||
| && self.game_board_state != GameBoardState::Display | ||
| { | ||
@@ -298,0 +301,0 @@ return Err(()); |
| // 录像相关的类,局面在board | ||
| use crate::board::GameBoard; | ||
| use crate::cal_cell_nums; | ||
| use crate::miscellaneous::s_to_ms; | ||
| #[cfg(any(feature = "py", feature = "rs"))] | ||
@@ -26,3 +25,3 @@ use crate::miscellaneous::time_ms_between; | ||
| use crate::{GameBoardState, MinesweeperBoard, MouseState}; | ||
| use crate::{GameBoardState, MinesweeperBoard}; | ||
| // use tract_onnx::prelude::Op; | ||
@@ -35,3 +34,3 @@ use crate::algorithms::cal_probability_cells_not_mine; | ||
| use crate::videos::types::{ | ||
| ErrReadVideoReason, Event, GameDynamicParams, KeyDynamicParams, MouseEvent, StaticParams, | ||
| Event, GameDynamicParams, KeyDynamicParams, MouseEvent, StaticParams, | ||
| VideoActionStateRecorder, VideoAnalyseParams, VideoDynamicParams, | ||
@@ -391,3 +390,12 @@ }; | ||
| let old_state = b.game_board_state; | ||
| // println!(">>> {:?}, {:?}", mouse_event.mouse, b.mouse_state); | ||
| // println!( | ||
| // ">>> {:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}", | ||
| // mouse_event.mouse, | ||
| // b.mouse_state, | ||
| // b.game_board_state, | ||
| // b.left, | ||
| // b.right, | ||
| // b.double, | ||
| // b.bbbv_solved | ||
| // ); | ||
| let u_level = b | ||
@@ -457,3 +465,3 @@ .step( | ||
| } | ||
| } else if let Some(Event::GameState(game_state_event)) = &svi.event { | ||
| } else if let Some(Event::GameState(_game_state_event)) = &svi.event { | ||
| continue; | ||
@@ -1150,3 +1158,3 @@ } else { | ||
| pub fn print_event(&self) { | ||
| pub fn print_event(&self, flag_print_game_board: bool) { | ||
| let num = 0; | ||
@@ -1159,5 +1167,20 @@ for e in &self.video_action_state_recorder { | ||
| "time = {:?}, mouse = {:?}, x = {:?}, y = {:?}, level = {:?}", | ||
| e.time, mouse_event.mouse, mouse_event.x, mouse_event.y, e.useful_level | ||
| e.time, | ||
| mouse_event.mouse, | ||
| mouse_event.x / self.get_pix_size().unwrap() as u16, | ||
| mouse_event.y / self.get_pix_size().unwrap() as u16, | ||
| e.useful_level | ||
| ); | ||
| } | ||
| if mouse_event.mouse != "mv" && flag_print_game_board { | ||
| println!( | ||
| "time = {:?}, mouse = {:?}, x = {:?}, y = {:?}", | ||
| e.time, mouse_event.mouse, mouse_event.x, mouse_event.y | ||
| ); | ||
| e.next_game_board.iter().for_each(|v| println!("{:?}", v)); | ||
| // e.prior_game_board | ||
| // .poss | ||
| // .iter() | ||
| // .for_each(|v| println!("{:?}", v)); | ||
| } | ||
| } | ||
@@ -1185,16 +1208,2 @@ // if e.mouse != "mv" { | ||
| // num += 1; | ||
| // if e.mouse != "mv" { | ||
| // println!( | ||
| // "time = {:?}, mouse = {:?}, x = {:?}, y = {:?}", | ||
| // e.time, e.mouse, e.x, e.y | ||
| // ); | ||
| // e.prior_game_board | ||
| // .game_board | ||
| // .iter() | ||
| // .for_each(|v| println!("{:?}", v)); | ||
| // e.prior_game_board | ||
| // .poss | ||
| // .iter() | ||
| // .for_each(|v| println!("{:?}", v)); | ||
| // } | ||
| } | ||
@@ -1222,3 +1231,3 @@ } | ||
| /// 软件的合法时间范围。单位为秒。 | ||
| /// 软件的合法时间范围。单位为秒。没人用,暂时搁置。 | ||
| pub fn valid_time_period(software: &str) -> Result<(String, String), String> { | ||
@@ -1225,0 +1234,0 @@ match software { |
@@ -90,6 +90,16 @@ use crate::videos::types::ErrReadVideoReason; | ||
| { | ||
| let code = self.get_buffer(length)?; | ||
| Self::get_unknown_encoding_string_from_buf(self.get_buffer(length)?) | ||
| } | ||
| fn get_unknown_encoding_string_from_buf(code: Vec<u8>) -> Result<String, ErrReadVideoReason> { | ||
| if let Ok(s) = String::from_utf8(code.clone()) { | ||
| return Ok(s); | ||
| } | ||
| match Self::get_unknown_cp_encoding_string_from_buf(code.clone()) { | ||
| Ok(str) => Ok(str), | ||
| Err(_) => Ok(String::from_utf8_lossy(&code).to_string()), | ||
| } | ||
| } | ||
| // won't consider utf-8 at all - useful for replay versions only produced by | ||
| // clones that never produce utf-8 | ||
| fn get_unknown_cp_encoding_string_from_buf(code: Vec<u8>) -> Result<String, ErrReadVideoReason> { | ||
| let (cow, _, had_errors) = GB18030.decode(&code); | ||
@@ -103,3 +113,3 @@ if !had_errors { | ||
| }; | ||
| Ok(String::from_utf8_lossy(&code).to_string()) | ||
| return Err(ErrReadVideoReason::InvalidParams); | ||
| } | ||
@@ -109,14 +119,3 @@ /// 读取以end结尾的未知编码字符串,假如所有编码都失败,返回utf-8乱码 | ||
| let code = self.get_c_buffer(end)?; | ||
| if let Ok(s) = String::from_utf8(code.clone()) { | ||
| return Ok(s); | ||
| } | ||
| let (cow, _, had_errors) = GB18030.decode(&code); | ||
| if !had_errors { | ||
| return Ok(cow.into_owned()); | ||
| }; | ||
| let (cow, _, had_errors) = WINDOWS_1252.decode(&code); | ||
| if !had_errors { | ||
| return Ok(cow.into_owned()); | ||
| }; | ||
| Ok(String::from_utf8_lossy(&code).to_string()) | ||
| Self::get_unknown_encoding_string_from_buf(code) | ||
| } | ||
@@ -123,0 +122,0 @@ // 是否闰年,计算阿比特时间戳 |
| use crate::GameStateEvent; | ||
| use crate::miscellaneous::s_to_ms; | ||
| use crate::utils::cal_board_numbers; | ||
@@ -648,4 +647,4 @@ use crate::videos::base_video::{BaseVideo, NewBaseVideo}; | ||
| } | ||
| b @ 100..=199 => {} | ||
| b @ 200..=254 => {} | ||
| _b @ 100..=199 => {} | ||
| _b @ 200..=254 => {} | ||
| // 开始解析停顿事件 | ||
@@ -652,0 +651,0 @@ 255 => { |
@@ -286,3 +286,4 @@ use crate::utils::refresh_board; | ||
| self.double += 1; | ||
| if self.game_board[x][y] == 0 || self.game_board[x][y] >= 8 { | ||
| // 在8、10、11、12上双击一定不会发生任何事情,但是在0上双击仍然可能有效! | ||
| if self.game_board[x][y] >= 8 { | ||
| return Ok(0); | ||
@@ -620,2 +621,9 @@ } | ||
| } | ||
| "mc" => { | ||
| // 阿比特中有在预标雷阶段中键按下弹起 | ||
| self.middle_hold = true; | ||
| } | ||
| "mr" => { | ||
| self.middle_hold = false; | ||
| } | ||
| _ => return Err(()), | ||
@@ -622,0 +630,0 @@ }, |
+215
-68
@@ -97,52 +97,87 @@ use crate::utils::cal_board_numbers; | ||
| }; | ||
| match self.data.get_u16() { | ||
| Ok(1u16) => {} | ||
| let format_version = match self.data.get_u16() { | ||
| Ok(format_version) => format_version, | ||
| _ => return Err(ErrReadVideoReason::FileIsNotRmv), | ||
| }; | ||
| if format_version == 0 || format_version > 2 { | ||
| // TODO: maybe add a better reason here? | ||
| // this is compatible with how it used to work, tho | ||
| // Perhaps VersionBackward is a better fit? | ||
| return Err(ErrReadVideoReason::FileIsNotRmv); | ||
| } | ||
| let clone_id = if format_version >= 2 { | ||
| self.data.get_u8()? | ||
| } else { 0 }; | ||
| let _major_version_of_clone = if format_version >= 2 { | ||
| self.data.get_u8()? | ||
| } else { 0 }; | ||
| // skip file_size | ||
| self.data.offset += 4; | ||
| let result_string_size = self.data.get_u16()?; | ||
| let result_string_size = if format_version == 1 { | ||
| self.data.get_u16()? | ||
| } else { 0 }; | ||
| let version_info_size = self.data.get_u16()?; | ||
| // skip player_info_size | ||
| // skip board_size | ||
| self.data.offset += 4; | ||
| // self.data.get_unsized_int4()?; | ||
| let preflags_size = self.data.get_u16()?; // Gets bytes 18-19 | ||
| let properties_size = self.data.get_u16()?; // Gets bytes 20-21 | ||
| self.data.offset += 7; | ||
| let preflags_size = self.data.get_u16()?; | ||
| let properties_size = self.data.get_u16()?; | ||
| let _extension_properties_size = if format_version >= 2 { | ||
| self.data.get_u16()? | ||
| } else { 0 }; | ||
| if result_string_size > 35 { | ||
| self.data.offset += (result_string_size - 32) as usize; | ||
| // 这种录像格式,3BV最多只支持3位数,宽和高支持最大256,雷数最多65536 | ||
| // 注意,3BV如果解析得到0,说明局面没有完成(我认为这种设计并不合理) | ||
| let mut bbbv: String = "".to_string(); | ||
| // skip vid_size | ||
| // skip checksum_size | ||
| self.data.offset += 6; | ||
| for _ in 0..3 { | ||
| let v = self.data.get_char()?; | ||
| if v as u8 >= 48 && v as u8 <= 57 { | ||
| bbbv.push(v); | ||
| if format_version == 1 { | ||
| // ignore leading newline | ||
| self.data.offset += 1; | ||
| self.data.static_params.bbbv = 0; | ||
| if result_string_size > 35 { | ||
| // full result string | ||
| // go to 31 before the end, as that is where bbbv will start | ||
| // this relies on "#NF:?#TIMESTAMP:1234567890#" always having | ||
| // the same length | ||
| // if the bbbv has less than 3 digits, this will start 1-2 chars | ||
| // early, but that's OK as they should never be digits | ||
| self.data.offset += (result_string_size - 32) as usize; | ||
| // 这种录像格式,3BV最多只支持3位数,宽和高支持最大256,雷数最多65536 | ||
| // 注意,3BV如果解析得到0,说明局面没有完成(我认为这种设计并不合理) | ||
| let mut bbbv: String = "".to_string(); | ||
| for _ in 0..3 { | ||
| let v = self.data.get_char()?; | ||
| if v as u8 >= 48 && v as u8 <= 57 { | ||
| bbbv.push(v); | ||
| } | ||
| } | ||
| } | ||
| self.data.static_params.bbbv = match bbbv.parse() { | ||
| Ok(v) => v, | ||
| Err(_) => return Err(ErrReadVideoReason::InvalidParams), | ||
| }; | ||
| self.data.is_completed = self.data.static_params.bbbv > 0; | ||
| // 没有判断是否公正的方法,只能根据是否扫完 | ||
| self.data.is_official = self.data.is_completed; | ||
| self.data.is_fair = self.data.is_completed; | ||
| self.data.static_params.bbbv = match bbbv.parse() { | ||
| Ok(v) => v, | ||
| Err(_) => return Err(ErrReadVideoReason::InvalidParams), | ||
| }; | ||
| self.data.offset += 16; | ||
| // 2286-11-21以后,会遇到时间戳溢出 | ||
| let timestamp = self.data.get_utf8_string(10usize)?; | ||
| self.data.start_time = timestamp | ||
| .parse::<u64>() | ||
| .map_err(|_| ErrReadVideoReason::InvalidParams)?; | ||
| self.data.start_time *= 1000000; | ||
| // 2 beta和更早的版本里没有3bv和时间戳 | ||
| } else { | ||
| self.data.static_params.bbbv = 0; | ||
| for _ in 0..result_string_size - 3 { | ||
| self.data.get_u8()?; | ||
| // "#NF:?#TIMESTAMP:??????????" | ||
| // no need to parse the timestamp - it is always the same as | ||
| // timestamp_boardgen if present | ||
| self.data.offset += 26; | ||
| } else if result_string_size >= 3 { | ||
| // this should always be >= 3, but let's be on the safe side | ||
| // here we have a reduced result string that doesn't contain bbbv | ||
| // => just ignore the whole result string! | ||
| // we subtract -3 for leading \n and trailing #\n | ||
| self.data.offset += result_string_size as usize - 3; | ||
| } | ||
| // trailing "#\n" | ||
| self.data.offset += 2; | ||
| } | ||
| self.data.offset += version_info_size as usize + 2; | ||
| // skip version_info | ||
| self.data.offset += version_info_size as usize; | ||
@@ -152,5 +187,12 @@ // 这里是uint16,不合理 | ||
| let mut token = vec![]; | ||
| // we need to store these in a buffer first, as how we parse them needs | ||
| // to depend on the utf8 property | ||
| let mut player_identifier_buffer = vec![]; | ||
| let mut uniqueness_identifier_buffer = vec![]; | ||
| let mut country_buffer = vec![]; | ||
| if num_player_info > 0 { | ||
| let name_length = self.data.get_u8()?; | ||
| self.data.player_identifier = self.data.get_unknown_encoding_string(name_length)?; | ||
| player_identifier_buffer = self.data.get_buffer(name_length)?; | ||
| } | ||
@@ -160,7 +202,7 @@ // 昵称不解析 | ||
| let nick_length = self.data.get_u8()?; | ||
| self.data.uniqueness_identifier = self.data.get_unknown_encoding_string(nick_length)?; | ||
| uniqueness_identifier_buffer = self.data.get_buffer(nick_length)?; | ||
| } | ||
| if num_player_info > 2 { | ||
| let country_length = self.data.get_u8()?; | ||
| self.data.country = self.data.get_unknown_encoding_string(country_length)?; | ||
| country_buffer = self.data.get_buffer(country_length)?; | ||
| } | ||
@@ -170,8 +212,7 @@ // 令牌不解析 | ||
| let token_length = self.data.get_u8()?; | ||
| for _ in 0..token_length { | ||
| self.data.get_char()?; | ||
| } | ||
| token = self.data.get_buffer(token_length as usize)?; | ||
| } | ||
| self.data.offset += 4; | ||
| // timestamp_boardgen | ||
| let timestamp_boardgen: u32 = self.data.get_u32()?.into(); | ||
@@ -195,2 +236,3 @@ self.data.width = self.data.get_u8()?.into(); | ||
| // 开始前已经标上的雷 | ||
| let mut preflags_items = vec![]; | ||
| if preflags_size > 0 { | ||
@@ -201,15 +243,10 @@ let num_pre_flags = self.data.get_u16()?; | ||
| let d = self.data.get_u8()? as u16; | ||
| self.data | ||
| .video_action_state_recorder | ||
| .push(VideoActionStateRecorder { | ||
| event: Some(Event::Mouse(MouseEvent { | ||
| mouse: "pf".to_string(), | ||
| x: d * 16, | ||
| y: c * 16, | ||
| })), | ||
| ..VideoActionStateRecorder::default() | ||
| }); | ||
| preflags_items.push((c, d)); | ||
| } | ||
| } | ||
| let preflags_items = preflags_items; | ||
| let mut square_size = 16u8; // v1 default | ||
| let mut utf8 = true; // v2 default | ||
| // skip questionmarks property | ||
| self.data.offset += 1; | ||
@@ -223,19 +260,113 @@ self.data.nf = if self.data.get_u8()? == 1 { | ||
| self.data.level = self.data.get_u8()? + 3; | ||
| let mut properties_read = 4; | ||
| self.data.offset += (properties_size - 4) as usize; | ||
| if format_version >= 2 { | ||
| let bbbv_low = self.data.get_u8()? as usize; | ||
| let bbbv_high = self.data.get_u8()? as usize; | ||
| self.data.static_params.bbbv = bbbv_low + (bbbv_high << 8); | ||
| square_size = self.data.get_u8()?; | ||
| properties_read += 3; | ||
| } else { | ||
| utf8 = false; | ||
| if properties_size > 4 { | ||
| utf8 = if self.data.get_u8()? == 1 { | ||
| true | ||
| } else { | ||
| false | ||
| }; | ||
| properties_read += 1; | ||
| } | ||
| } | ||
| let square_size = square_size; | ||
| let utf8 = utf8; | ||
| self.data.cell_pixel_size = square_size; | ||
| // ignore remaining properties | ||
| self.data.offset += (properties_size - properties_read) as usize; | ||
| // read extension properties. In the process, also set the clone_name, | ||
| // if provided. | ||
| // clone_name is a replacement for clone_id for new clones that don't | ||
| // have an ID assigned yet. | ||
| let mut clone_name = None; | ||
| if format_version >= 2 { | ||
| let num_extension_properties = self.data.get_u16()?; | ||
| for _ii in 0..num_extension_properties { | ||
| let key_size = self.data.get_u8()?; | ||
| let key = self.data.get_utf8_string(key_size as usize)?; | ||
| let value_size = self.data.get_u8()?; | ||
| let value = self.data.get_buffer(value_size as usize)?; | ||
| if key == "clone_name" { | ||
| clone_name = Some(String::from_utf8(value)); | ||
| } | ||
| } | ||
| } | ||
| let clone_name = match clone_name { | ||
| None => None, | ||
| Some(Ok(s)) => Some(s), | ||
| Some(Err(_)) => { | ||
| return Err(ErrReadVideoReason::Utf8Error); | ||
| } | ||
| }; | ||
| if utf8 { | ||
| // verify that text fields that we read are valid utf-8 as specified by the RMV spec | ||
| let utf8_errfunc = |_e| ErrReadVideoReason::Utf8Error; | ||
| self.data.player_identifier = String::from_utf8(player_identifier_buffer).map_err(utf8_errfunc)?; | ||
| self.data.uniqueness_identifier = String::from_utf8(uniqueness_identifier_buffer).map_err(utf8_errfunc)?; | ||
| self.data.country = String::from_utf8(country_buffer).map_err(utf8_errfunc)?; | ||
| let _ = String::from_utf8(token.clone()).map_err(utf8_errfunc)?; | ||
| } | ||
| else { | ||
| self.data.player_identifier = <BaseVideo<Vec<Vec<i32>>>>::get_unknown_cp_encoding_string_from_buf(player_identifier_buffer)?; | ||
| self.data.uniqueness_identifier = <BaseVideo<Vec<Vec<i32>>>>::get_unknown_cp_encoding_string_from_buf(uniqueness_identifier_buffer)?; | ||
| self.data.country = <BaseVideo<Vec<Vec<i32>>>>::get_unknown_cp_encoding_string_from_buf(country_buffer)?; | ||
| } | ||
| // 是不是第一个操作。录像里省略了第一个左键按下。 | ||
| let mut first_op_flag = true; | ||
| let xoffset = if format_version == 1 {12} else {0}; | ||
| let yoffset = if format_version == 1 {56} else {0}; | ||
| let (mut x, mut y, mut time) = (0u16, 0u16, 0u32); | ||
| for (c, d) in preflags_items { | ||
| self.data | ||
| .video_action_state_recorder | ||
| .push(VideoActionStateRecorder { | ||
| event: Some(Event::Mouse(MouseEvent { | ||
| mouse: "pf".to_string(), | ||
| x: c * self.data.cell_pixel_size as u16, | ||
| y: d * self.data.cell_pixel_size as u16, | ||
| })), | ||
| ..VideoActionStateRecorder::default() | ||
| }); | ||
| } | ||
| loop { | ||
| let c = self.data.get_u8()?; | ||
| if c == 0 { | ||
| if format_version >= 2 { | ||
| return Err(ErrReadVideoReason::InvalidVideoEvent); | ||
| } | ||
| self.data.offset += 4; | ||
| } else if c <= 7 { | ||
| let time = self.data.get_u32()? >> 8; | ||
| let mut x = (self.data.get_u16()?).wrapping_sub(12); | ||
| let mut y = (self.data.get_u16()?).wrapping_sub(56); | ||
| } else if c <= 7 || (format_version >= 2 && c == 28 && !first_op_flag) { | ||
| if c == 28 { | ||
| time += self.data.get_u8()? as u32; | ||
| let mv = self.data.get_u8()?; | ||
| // mv is two 4bit two's complement signed integers packed into a single byte | ||
| // n & 8 = leading digit, the one that has negative weight in two's complement | ||
| // n & 7 = remaining three digits | ||
| // for x, we shift into position first | ||
| x = x.wrapping_add(((mv >> 4) & 7u8) as u16); | ||
| x = x.wrapping_sub(((mv >> 4) & 8u8) as u16); | ||
| y = y.wrapping_add((mv & 7u8) as u16); | ||
| y = y.wrapping_sub((mv & 8u8) as u16); | ||
| } else { | ||
| time = self.data.get_u32()? >> 8; | ||
| x = (self.data.get_u16()?).wrapping_sub(xoffset); | ||
| y = (self.data.get_u16()?).wrapping_sub(yoffset); | ||
| } | ||
| if c >= 1 { | ||
| if x >= self.data.width as u16 * 16 || y >= self.data.height as u16 * 16 { | ||
| x = self.data.width as u16 * 16; | ||
| y = self.data.height as u16 * 16; | ||
| if x >= self.data.width as u16 * self.data.cell_pixel_size as u16 | ||
| || y >= self.data.height as u16 * self.data.cell_pixel_size as u16 { | ||
| x = self.data.width as u16 * self.data.cell_pixel_size as u16; | ||
| y = self.data.height as u16 * self.data.cell_pixel_size as u16; | ||
| } | ||
@@ -269,2 +400,3 @@ if first_op_flag { | ||
| 7 => "mr".to_string(), | ||
| 28 => "mv".to_string(), | ||
| _ => return Err(ErrReadVideoReason::InvalidVideoEvent), | ||
@@ -283,2 +415,3 @@ }, | ||
| } else if c <= 17 { | ||
| self.data.is_completed = c == 16; | ||
| break; | ||
@@ -292,7 +425,21 @@ } else { | ||
| .unwrap(); | ||
| if result_string_size > 35 { | ||
| self.data.end_time = | ||
| self.data.start_time + (self.data.get_rtime_ms().unwrap() as u64) * 1000; | ||
| } | ||
| self.data.software = "Viennasweeper".to_string(); | ||
| self.data.start_time = timestamp_boardgen as u64 * 1000000; | ||
| self.data.end_time = | ||
| self.data.start_time + (self.data.get_rtime_ms().unwrap() as u64) * 1000; | ||
| self.data.software = if format_version == 1 { | ||
| "Viennasweeper".to_string() | ||
| } else { | ||
| match clone_id { | ||
| 0 => match clone_name { | ||
| Some(s) => s, | ||
| None => { | ||
| return Err(ErrReadVideoReason::InvalidParams) | ||
| }, | ||
| }, | ||
| 1 => "Viennasweeper".to_string(), | ||
| _ => "Unknown".to_string(), | ||
| } | ||
| }; | ||
| self.data.is_official = self.data.is_completed; | ||
| self.data.is_fair = self.data.is_completed; | ||
| self.data.can_analyse = true; | ||
@@ -299,0 +446,0 @@ return Ok(()); |
@@ -165,3 +165,3 @@ // 测试录像分析模块 | ||
| "super_fl_local", | ||
| ]); | ||
| ]).expect("feature analysis should work!"); | ||
| } |
@@ -1,10 +0,5 @@ | ||
| use ms_toollib::videos::base_video::NewBaseVideo2; | ||
| use ms_toollib::videos::NewSomeVideo; | ||
| use ms_toollib::{ | ||
| AvfVideo, BaseVideo, EvfVideo, GameBoardState, MinesweeperBoard, MouseState, MvfVideo, | ||
| RmvVideo, SafeBoard, | ||
| AvfVideo, EvfVideo, | ||
| }; | ||
| use std::mem::transmute; | ||
| use std::thread; | ||
| use std::time::Duration; | ||
| use ms_toollib::Event; | ||
@@ -11,0 +6,0 @@ |
+2
-2
| Metadata-Version: 2.4 | ||
| Name: ms_toollib | ||
| Version: 1.5.2 | ||
| Version: 1.5.3 | ||
| Summary: Algorithms for minesweeper. | ||
@@ -11,6 +11,6 @@ Keywords: minesweeper,sweeper,probability,solver,3BV | ||
| Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM | ||
| Project-URL: documentation, https://docs.rs/ms_toollib/latest/ms_toollib | ||
| Project-URL: homepage, https://github.com/eee555/ms_toollib | ||
| Project-URL: documentation, https://docs.rs/ms_toollib/latest/ms_toollib | ||
| Project-URL: repository, https://github.com/eee555/ms_toollib | ||
| (还没写) |
+1
-1
| [project] | ||
| name = "ms_toollib" | ||
| version = "1.5.2" | ||
| version = "1.5.3" | ||
| description = "Algorithms for minesweeper." | ||
@@ -5,0 +5,0 @@ readme = "readme.md" |
@@ -100,5 +100,5 @@ # This file is automatically @generated by Cargo. | ||
| name = "cc" | ||
| version = "1.2.49" | ||
| version = "1.2.52" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" | ||
| checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" | ||
| dependencies = [ | ||
@@ -242,5 +242,5 @@ "find-msvc-tools", | ||
| name = "find-msvc-tools" | ||
| version = "0.1.5" | ||
| version = "0.1.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" | ||
| checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" | ||
@@ -351,5 +351,5 @@ [[package]] | ||
| name = "itoa" | ||
| version = "1.0.15" | ||
| version = "1.0.17" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" | ||
| checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" | ||
@@ -374,5 +374,5 @@ [[package]] | ||
| name = "libc" | ||
| version = "0.2.178" | ||
| version = "0.2.180" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" | ||
| checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" | ||
@@ -387,9 +387,9 @@ [[package]] | ||
| name = "libredox" | ||
| version = "0.1.11" | ||
| version = "0.1.12" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" | ||
| checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" | ||
| dependencies = [ | ||
| "bitflags", | ||
| "libc", | ||
| "redox_syscall 0.6.0", | ||
| "redox_syscall 0.7.0", | ||
| ] | ||
@@ -442,3 +442,3 @@ | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] | ||
@@ -537,3 +537,3 @@ | ||
| "itertools 0.6.5", | ||
| "ms_toollib 1.5.2", | ||
| "ms_toollib 1.5.3", | ||
| "pyo3", | ||
@@ -544,3 +544,3 @@ ] | ||
| name = "ms_toollib" | ||
| version = "1.5.2" | ||
| version = "1.5.3" | ||
| dependencies = [ | ||
@@ -655,5 +655,5 @@ "encoding_rs", | ||
| name = "pest" | ||
| version = "2.8.4" | ||
| version = "2.8.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" | ||
| checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" | ||
| dependencies = [ | ||
@@ -666,5 +666,5 @@ "memchr", | ||
| name = "pest_derive" | ||
| version = "2.8.4" | ||
| version = "2.8.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "51f72981ade67b1ca6adc26ec221be9f463f2b5839c7508998daa17c23d94d7f" | ||
| checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" | ||
| dependencies = [ | ||
@@ -677,5 +677,5 @@ "pest", | ||
| name = "pest_generator" | ||
| version = "2.8.4" | ||
| version = "2.8.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "dee9efd8cdb50d719a80088b76f81aec7c41ed6d522ee750178f83883d271625" | ||
| checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" | ||
| dependencies = [ | ||
@@ -686,3 +686,3 @@ "pest", | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] | ||
@@ -692,5 +692,5 @@ | ||
| name = "pest_meta" | ||
| version = "2.8.4" | ||
| version = "2.8.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "bf1d70880e76bdc13ba52eafa6239ce793d85c8e43896507e43dd8984ff05b82" | ||
| checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" | ||
| dependencies = [ | ||
@@ -703,5 +703,5 @@ "pest", | ||
| name = "portable-atomic" | ||
| version = "1.11.1" | ||
| version = "1.13.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" | ||
| checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" | ||
@@ -743,5 +743,5 @@ [[package]] | ||
| name = "proc-macro2" | ||
| version = "1.0.103" | ||
| version = "1.0.105" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" | ||
| checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" | ||
| dependencies = [ | ||
@@ -819,3 +819,3 @@ "unicode-ident", | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] | ||
@@ -833,3 +833,3 @@ | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] | ||
@@ -839,5 +839,5 @@ | ||
| name = "quote" | ||
| version = "1.0.42" | ||
| version = "1.0.43" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" | ||
| checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" | ||
| dependencies = [ | ||
@@ -904,5 +904,5 @@ "proc-macro2", | ||
| name = "redox_syscall" | ||
| version = "0.6.0" | ||
| version = "0.7.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" | ||
| checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" | ||
| dependencies = [ | ||
@@ -957,5 +957,5 @@ "bitflags", | ||
| name = "rustix" | ||
| version = "1.1.2" | ||
| version = "1.1.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" | ||
| checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" | ||
| dependencies = [ | ||
@@ -1026,3 +1026,3 @@ "bitflags", | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] | ||
@@ -1095,5 +1095,5 @@ | ||
| name = "syn" | ||
| version = "2.0.111" | ||
| version = "2.0.114" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" | ||
| checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" | ||
| dependencies = [ | ||
@@ -1118,5 +1118,5 @@ "proc-macro2", | ||
| name = "target-lexicon" | ||
| version = "0.13.3" | ||
| version = "0.13.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" | ||
| checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" | ||
@@ -1487,5 +1487,5 @@ [[package]] | ||
| name = "zerocopy" | ||
| version = "0.8.31" | ||
| version = "0.8.33" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" | ||
| checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" | ||
| dependencies = [ | ||
@@ -1497,9 +1497,9 @@ "zerocopy-derive", | ||
| name = "zerocopy-derive" | ||
| version = "0.8.31" | ||
| version = "0.8.33" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" | ||
| checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn 2.0.111", | ||
| "syn 2.0.114", | ||
| ] |
@@ -383,2 +383,8 @@ use crate::{PyGameBoard, PyVideoActionStateRecorder}; | ||
| } | ||
| // 读取录像文件后,有可能要转存。此时,例如rmv,录像中的国家信息是用户手动输入的 | ||
| // 需要在外部传入。因为所有国家的文本信息有39k,放在工具箱里不合适 | ||
| #[setter] | ||
| pub fn set_country(&mut self, country: String) { | ||
| self.core.data.set_country(country).unwrap(); | ||
| } | ||
| } | ||
@@ -385,0 +391,0 @@ }; |
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
923208
36.08%60
20%