pub fn stable_byte_hash(bytes: &[u8]) -> u64Examples found in repository?
examples/hash_frame.rs (line 52)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}More examples
examples/analyze_state.rs (line 119)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}