ksudoku.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Read a Ksudoku's XML save file.
  2. use std::collections::HashMap;
  3. use std::error;
  4. use std::fmt;
  5. use std::fs::File;
  6. use std::io::BufReader;
  7. use xml::reader::{EventReader, XmlEvent};
  8. use xml::writer::XmlEvent as WrXmlEvent;
  9. use xml::EmitterConfig;
  10. #[derive(Debug, Clone)]
  11. struct UnsupportedGroup {
  12. message: String,
  13. }
  14. impl fmt::Display for UnsupportedGroup {
  15. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  16. write!(f, "Unsupported group: {}", self.message)
  17. }
  18. }
  19. impl error::Error for UnsupportedGroup {}
  20. pub fn load_ksudoku(filename: std::path::PathBuf) -> Result<String, Box<dyn error::Error>> {
  21. let fh = File::open(filename)?;
  22. let buffer = BufReader::new(fh);
  23. let parser = EventReader::new(buffer);
  24. // I'm interested in values and (maybe) solution
  25. let mut values: String = String::from("");
  26. let mut element_name: String = String::from("");
  27. for e in parser {
  28. match e {
  29. Ok(XmlEvent::StartElement {
  30. name, attributes, ..
  31. }) => {
  32. element_name = name.local_name.clone();
  33. if element_name == "graph" {
  34. // Check the attributes here
  35. // <graph specific-type="Plain" type="sudoku" order="9"/>
  36. // Verify these are correct / not some other puzzle type!
  37. // {"specific-type": "Plain", "type": "sudoku", "order": "9"}
  38. let mut attrs: HashMap<String, String> = HashMap::new();
  39. for a in attributes {
  40. attrs.insert(a.name.to_string(), a.value);
  41. }
  42. let blank = String::new();
  43. // Format in specific order here.
  44. let expected = format!(
  45. "{}-{}-{}",
  46. attrs.get(&"specific-type".to_string()).unwrap_or(&blank),
  47. attrs.get(&"type".to_string()).unwrap_or(&blank),
  48. attrs.get(&"order".to_string()).unwrap_or(&blank)
  49. );
  50. if expected != "Plain-sudoku-9" {
  51. // println!("Unknown ksudoku type! {}", expected);
  52. return Err(Box::new(UnsupportedGroup {
  53. message: format!("Unsupported Ksudoku game type: {}", expected),
  54. }));
  55. }
  56. println!("{:?}", attrs);
  57. }
  58. }
  59. Ok(XmlEvent::Characters(text)) => {
  60. if element_name == "values" {
  61. values = text.clone();
  62. }
  63. }
  64. Err(e) => {
  65. return Err(Box::new(e));
  66. }
  67. _ => {}
  68. }
  69. }
  70. Ok(values)
  71. }
  72. pub fn save_ksudoku(
  73. filename: std::path::PathBuf,
  74. puz: &String,
  75. sol: &String,
  76. ) -> Result<(), Box<dyn error::Error>> {
  77. let fh = File::create(filename)?;
  78. let mut writer = EmitterConfig::new().perform_indent(true).create_writer(fh);
  79. let mut event: WrXmlEvent = WrXmlEvent::start_element("ksudoku").into();
  80. writer.write(event)?;
  81. event = WrXmlEvent::start_element("game")
  82. .attr("had-help", "0")
  83. .attr("msecs-elapsed", "0")
  84. .into();
  85. writer.write(event)?;
  86. event = WrXmlEvent::start_element("puzzle").into();
  87. writer.write(event)?;
  88. event = WrXmlEvent::start_element("graph")
  89. .attr("specific-type", "Plain")
  90. .attr("type", "sudoku")
  91. .attr("order", "9")
  92. .into();
  93. writer.write(event)?;
  94. event = WrXmlEvent::end_element().into();
  95. writer.write(event)?;
  96. // values (puzzle)
  97. event = WrXmlEvent::start_element("values").into();
  98. writer.write(event)?;
  99. event = WrXmlEvent::characters(puz).into();
  100. writer.write(event)?;
  101. event = WrXmlEvent::end_element().into();
  102. writer.write(event)?;
  103. // solution
  104. event = WrXmlEvent::start_element("solution").into();
  105. writer.write(event)?;
  106. event = WrXmlEvent::characters(sol).into();
  107. writer.write(event)?;
  108. event = WrXmlEvent::end_element().into();
  109. writer.write(event)?;
  110. // Apparently, the events are consumed...
  111. event = WrXmlEvent::end_element().into();
  112. writer.write(event)?;
  113. event = WrXmlEvent::end_element().into();
  114. writer.write(event)?;
  115. event = WrXmlEvent::end_element().into();
  116. writer.write(event)?;
  117. /*
  118. let pStr: String = puzzle.save_to_tld(start_ch: 'b', blank: '_');
  119. let solStr: solution.save_to_tld(start_ch: 'b', blank: '_');
  120. let ksudoko = Ksudoku {
  121. game: Game {
  122. help: 0,
  123. elapsed: 0,
  124. puzzle: Puzzle {
  125. graph: Graph {
  126. order: 9,
  127. game_type: String::from("sudoku"),
  128. specific_type: String::from("Plain"),
  129. },
  130. values: puz.to_string(),
  131. solution: sol.to_string(),
  132. },
  133. },
  134. };
  135. let fh = File::create(filename)?;
  136. let _res = to_writer(fh, &ksudoko)?;
  137. */
  138. Ok(())
  139. }