Summary Files Commits Branches @commit @diff @stats
diff options
context:
space:
mode:
Commit10c4219db0fd5957c332e2a98e276107bd5a37b3 (patch)
Author
 Syndamia <kamen@syndamia.com>
2024-11-10 19:23:07 +0200
Committer
 Syndamia <kamen@syndamia.com>
2024-11-10 19:23:07 +0200
Files89511599271c1bb44a1f3b7adde242dff7d4b5a8
uni-projects-10c4219db0fd5957c332e2a98e276107bd5a37b3.tar
uni-projects-10c4219db0fd5957c332e2a98e276107bd5a37b3.tar.gz
uni-projects-10c4219db0fd5957c332e2a98e276107bd5a37b3.zip
Parent7b9257cc4e7fb4137e0be79f0cf3db4d1ae1aa3f (diff)
hw(4/AI): Final changes and improvements
1 files changed, 104 insertions, 58 deletions
-rw-r--r--Year 4/Artificial Intelligence/hw02/src/main.rs162
diff --git a/Year 4/Artificial Intelligence/hw02/src/main.rs b/Year 4/Artificial Intelligence/hw02/src/main.rs
index 0d2ec11..f36f5c6 100644
--- a/Year 4/Artificial Intelligence/hw02/src/main.rs
+++ b/Year 4/Artificial Intelligence/hw02/src/main.rs
@@ -4,56 +4,74 @@ use rand::{Rng, rngs::ThreadRng};
use std::fmt::{Display, Formatter, Result};
use std::time::Instant;
+const MAXN: usize = 10000;
+
struct Puzzle {
- in_col: Vec<usize>,
- per_row: Vec<i32>,
- per_d1: Vec<i32>,
- per_d2: Vec<i32>,
+ in_col: [usize; MAXN],
+ per_row: [i32; MAXN],
+ per_d1: [i32; 2 * MAXN - 1],
+ per_d2: [i32; 2 * MAXN - 1],
+
+ max_attack: i32,
+ max_queens: Vec<usize>,
N: usize,
rng: ThreadRng,
}
impl Puzzle {
+ /* Helper */
+
pub fn new(N: usize) -> Puzzle {
Puzzle {
- in_col: vec![0; N],
- per_row: vec![0; N],
- per_d1: vec![0; 2 * N - 1],
- per_d2: vec![0; 2 * N - 1],
+ in_col: [0; MAXN],
+ per_row: [0; MAXN],
+ per_d1: [0; 2 * MAXN - 1],
+ per_d2: [0; 2 * MAXN - 1],
+
+ max_attack: 0,
+ max_queens: Vec::with_capacity(N),
+
N: N,
rng: rand::thread_rng(),
}
}
- fn max_queen_col(&mut self) -> usize {
- let (mut max_attacks, mut ind) = (0, Vec::new());
- for col in 0..self.N {
- let attacks = self.per_row[self.in_col[col]] +
- self.per_d1[col + self.N - 1 - self.in_col[col]] +
- self.per_d2[col + self.in_col[col]];
+ fn attacks(&self, col: usize, row: usize) -> i32 {
+ self.per_row[row] +
+ self.per_d1[col + self.N - 1 - row] +
+ self.per_d2[col + row]
+ }
- if max_attacks < attacks {
- max_attacks = attacks;
- ind.clear();
- }
- if max_attacks == attacks {
- ind.push(col);
+ fn clear(&mut self) {
+ self.max_attack = 0;
+ self.max_queens.clear();
+ for i in 0..2 * self.N - 1 {
+ self.per_d1[i] = 0;
+ self.per_d2[i] = 0;
+ if i < self.N {
+ self.per_row[i] = 0;
}
}
+ }
+
+ /* Cells */
+
+ fn max_queen_col(&mut self) -> usize {
+ if self.max_attack == 3 {
+ return self.N;
+ }
- if ind.len() > 1 {
- return ind[self.rng.gen_range(0..ind.len())];
+ if self.max_queens.len() > 1 {
+ return self.max_queens[self.rng.gen_range(0..self.max_queens.len())];
}
- return ind[0];
+ return self.max_queens[0];
}
fn min_col_row(&mut self, colI: usize) -> usize {
let (mut min_row, mut min_ind) = (i32::MAX, Vec::new());
for row in 0..self.N {
- let attacks = self.per_row[row] +
- self.per_d1[colI + self.N - 1 - row] +
- self.per_d2[colI + row];
+ let attacks = self.attacks(colI, row);
if attacks < min_row {
min_row = attacks;
@@ -71,10 +89,36 @@ impl Puzzle {
}
fn update(&mut self, colI: usize, val: i32) {
- self.per_row[self.in_col[colI]] += val;
+ let old_attack = self.attacks(colI, self.in_col[colI]);
+
+ self.per_row[self.in_col[colI]] += val;
self.per_d1[colI + self.N - 1 - self.in_col[colI]] += val;
- self.per_d2[colI + self.in_col[colI]] += val;
+ self.per_d2[colI + self.in_col[colI]] += val;
+
+ if val < 0 {
+ if old_attack != self.max_attack { return; }
+
+ for i in 0..self.max_queens.len() {
+ if self.max_queens[i] == colI {
+ self.max_queens.remove(i);
+ return;
+ }
+ }
+ unreachable!();
+ }
+
+ let current_attack = self.attacks(colI, self.in_col[colI]);
+
+ if self.max_attack < current_attack {
+ self.max_queens.clear();
+ self.max_queens.push(colI);
+ self.max_attack = current_attack;
+ }
+ if self.max_attack == current_attack {
+ self.max_queens.push(colI);
+ }
}
+
fn move_queen(&mut self, colI: usize, rowI: usize) {
if rowI == self.in_col[colI] { return; }
@@ -83,6 +127,8 @@ impl Puzzle {
self.update(colI, 1);
}
+ /* Algorithm */
+
fn has_conflicts(&self) -> bool {
for i in 0..self.N {
if self.per_row[i] > 1 { return true; }
@@ -93,51 +139,51 @@ impl Puzzle {
return false;
}
- fn init(&mut self) {
- // Clear
- for i in 0..2 * self.N - 1 {
- self.per_d1[i] = 0;
- self.per_d2[i] = 0;
- if i < self.N {
- self.per_row[i] = 0;
- }
- }
+ fn init_horse(&mut self) {
+ self.clear();
- for col in 0..self.N {
- let row = self.min_col_row(col);
+ let (mut col, mut row) = (1, 0);
+ for _ in 0..self.N / 2 {
self.in_col[col] = row;
self.update(col, 1);
+ col += 2;
+ row += 1;
}
- return;
+ let (mut col, mut row) = (0, self.N / 2);
+ for _ in 0..self.N / 2 {
+ self.in_col[col] = row;
+ self.update(col, 1);
+ col += 2;
+ row += 1;
+ }
+ }
- // Horse
- // let (mut col, mut row) = (1, 0);
- // for _ in 0..self.N / 2 {
- // self.in_col[col] = row;
- // self.update(col, 1);
- // col += 2;
- // row += 1;
- // }
- // let (mut col, mut row) = (0, self.N / 2);
- // for _ in 0..self.N / 2 {
- // self.in_col[col] = row;
- // self.update(col, 1);
- // col += 2;
- // row += 1;
- // }
+ fn init_rand(&mut self) {
+ self.clear();
+
+ self.in_col[0] = self.rng.gen_range(0..self.N);
+ self.update(0, 1);
+
+ for col in 1..self.N {
+ self.in_col[col] = self.min_col_row(col);
+ self.update(col, 1);
+ }
}
pub fn solve(&mut self) {
+ self.init_horse();
loop {
- self.init();
- for _ in 0..self.N {
+ for _ in 0..2 * self.N {
let col = self.max_queen_col();
+ if col == self.N { return; }
+
let row = self.min_col_row(col);
self.move_queen(col, row);
}
if !self.has_conflicts() {
break;
}
+ self.init_rand();
}
}
}
@@ -164,7 +210,7 @@ impl Display for Puzzle {
fn main() {
let N: usize = read!();
- if N < 4 {
+ if N == 2 || N == 3 {
println!("-1");
return;
}