Last active
February 23, 2020 07:19
-
-
Save optozorax/f6e0ac596af6b55f7e6a4f3d9e29a6ae to your computer and use it in GitHub Desktop.
genetic_alg.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Что это такое? Читай начиная с https://t.me/optozorax_dev/46 | |
*/ | |
use enigo::*; | |
use spiril::unit::Unit; | |
use spiril::population::Population; | |
use rand::{thread_rng, Rng}; | |
use std::process::{Command, Stdio}; | |
use std::thread::sleep; | |
use std::time::Duration; | |
use std::fs; | |
const FILE_SERVICE_POS: (i32, i32) = (1147, 508); | |
const WRITE: (i32, i32) = (1124, 621); | |
const EXIT: (i32, i32) = (1242, 882); | |
const PATH: &str = "C:/Users/zorax/Desktop/TELMA/PRIMER"; | |
fn run_async(command: &str) { | |
Command::new(command) | |
.current_dir(PATH) | |
.stdin(Stdio::null()) | |
.stdout(Stdio::null()) | |
.spawn() | |
.expect("failed to execute process"); | |
} | |
fn click(pos: (i32, i32)) { | |
let mut enigo = Enigo::new(); | |
enigo.mouse_move_to(pos.0, pos.1); | |
enigo.mouse_click(MouseButton::Left); | |
} | |
#[derive(Default, Debug, Clone)] | |
struct SredaField { | |
size: f32, | |
step: f32, | |
} | |
#[derive(Default, Debug, Clone)] | |
struct Sreda { | |
canonical_result: (Vec<f32>, i32), | |
x: Vec<SredaField>, | |
y: Vec<SredaField>, | |
lines_before_x: Vec<String>, | |
lines_after_x_before_y: Vec<String>, | |
lines_after_y: Vec<String>, | |
} | |
fn read_sreda(file: &str, canonical_result: (Vec<f32>, i32)) -> Sreda { | |
let mut result = Sreda::default(); | |
result.canonical_result = canonical_result; | |
let file = fs::read_to_string(PATH.to_owned() + "/" + file).unwrap(); | |
let mut lines = file.lines(); | |
for _ in 0..20 { | |
result.lines_before_x.push(lines.next().unwrap().to_string()); | |
} | |
let x_size_line = lines.next().unwrap(); | |
result.lines_before_x.push(x_size_line.to_string()); | |
let mut x_size: Vec<f32> = x_size_line.split_whitespace().map(|x| x.parse::<f32>().unwrap()).collect(); | |
let x_size_next = x_size.clone(); | |
x_size.insert(0, -6e-2); | |
for (a, b) in x_size.iter().zip(x_size_next.iter()) { | |
result.x.push(SredaField { size: b-a, step: 0.0 }); | |
} | |
let x_line = lines.next().unwrap(); | |
for (i, v) in x_line.split_whitespace().map(|x| x.parse::<f32>().unwrap()).enumerate() { | |
result.x[i].step = v / result.x[i].size; | |
} | |
for _ in 0..3 { | |
result.lines_after_x_before_y.push(lines.next().unwrap().to_string()); | |
} | |
let y_size_line = lines.next().unwrap(); | |
result.lines_after_x_before_y.push(y_size_line.to_string()); | |
let mut y_size: Vec<f32> = y_size_line.split_whitespace().map(|y| y.parse::<f32>().unwrap()).collect(); | |
let y_size_next = y_size.clone(); | |
y_size.insert(0, 0.0); | |
for (a, b) in y_size.iter().zip(y_size_next.iter()) { | |
result.y.push(SredaField { size: b-a, step: 0.0 }); | |
} | |
let y_line = lines.next().unwrap(); | |
for (i, v) in y_line.split_whitespace().map(|y| y.parse::<f32>().unwrap()).enumerate() { | |
result.y[i].step = v / result.y[i].size; | |
} | |
for _ in 0..3 { | |
result.lines_after_y.push(lines.next().unwrap().to_string()); | |
} | |
result | |
} | |
fn write_sreda(sreda: &Sreda) { | |
let mut result = String::new(); | |
for line in &sreda.lines_before_x { | |
result += &line; | |
result += "\n"; | |
} | |
for field in &sreda.x { | |
result += &((field.size * field.step).to_string() + " "); | |
} | |
result += "\n"; | |
for line in &sreda.lines_after_x_before_y { | |
result += &line; | |
result += "\n"; | |
} | |
for field in &sreda.y { | |
result += &((field.size * field.step).to_string() + " "); | |
} | |
result += "\n"; | |
for line in &sreda.lines_after_y { | |
result += &line; | |
result += "\n"; | |
} | |
fs::write(PATH.to_owned() + "/sreda", result).unwrap(); | |
} | |
fn get_result() -> (Vec<f32>, i32) { | |
fs::remove_file(PATH.to_owned() + "/result").unwrap_or_default(); | |
fs::remove_file(PATH.to_owned() + "/inf2tr.dat").unwrap_or_default(); | |
run_async(&(PATH.to_owned() + "/pusk.bat")); | |
sleep(Duration::from_millis(1000)); | |
click(FILE_SERVICE_POS); | |
sleep(Duration::from_millis(100)); | |
click(WRITE); | |
sleep(Duration::from_millis(100)); | |
click(EXIT); | |
let mut vec = Vec::new(); | |
let contents = fs::read_to_string(PATH.to_owned() + "/result").unwrap(); | |
let mut lines = contents.lines(); | |
lines.next().unwrap(); | |
for (index, line) in lines.enumerate() { | |
if index == 1 || index == 3 { | |
vec.push(line | |
.split_whitespace().nth(3).unwrap() | |
.parse().unwrap() | |
); | |
} | |
} | |
let count = | |
fs::read_to_string(PATH.to_owned() + "/inf2tr.dat") | |
.unwrap() | |
.lines().nth(1).unwrap() | |
.split_whitespace().nth(1).unwrap() | |
.parse().unwrap(); | |
(vec, count) | |
} | |
fn init() { | |
fs::remove_file(PATH.to_owned() + "/sreda").unwrap_or_default(); | |
fs::copy(PATH.to_owned() + "/sreda1", PATH.to_owned() + "/sreda").unwrap(); | |
} | |
fn mutate_float(f: &mut f32) { | |
let mut rng = thread_rng(); | |
*f *= rng.gen_range(0.5, 1.5); | |
if *f > 1.0 { *f = 1.0; } | |
if *f < 0.002 { *f = 0.002; } | |
} | |
impl Sreda { | |
fn mutate(mut self) -> Self { | |
let mut rng = thread_rng(); | |
if rng.gen() { | |
let pos = rng.gen_range(0, self.x.len()); | |
mutate_float(&mut self.x[pos].step); | |
} else { | |
let pos = rng.gen_range(0, self.y.len()); | |
mutate_float(&mut self.y[pos].step); | |
} | |
self | |
} | |
} | |
static mut BEST_RESULT: i32 = 1_000_000; | |
static mut FUNCTION_CALLS: i32 = 0; | |
impl Unit for Sreda { | |
fn fitness(&self) -> f64 { | |
unsafe { | |
FUNCTION_CALLS += 1; | |
} | |
write_sreda(self); | |
let result = get_result(); | |
let all_values_in_one_percentile = self.canonical_result.0 | |
.iter().zip(result.0.iter()) | |
.all(|(&a, &b)| (1.0 - (a/b)).abs() < 0.01); | |
if all_values_in_one_percentile { | |
unsafe { | |
if result.1 < BEST_RESULT { | |
BEST_RESULT = result.1; | |
write_sreda(self); | |
fs::copy(PATH.to_owned() + "/sreda", PATH.to_owned() + "/sreda_" + &result.1.to_string()).unwrap(); | |
println!("Found new best! Score: {}, Calls: {}", BEST_RESULT, FUNCTION_CALLS); | |
} | |
} | |
1.0/result.1 as f64 | |
} else { | |
1.0/10000.0 | |
} | |
} | |
fn breed_with(&self, other: &Sreda) -> Sreda { | |
let mut result = self.clone(); | |
let mut rng = thread_rng(); | |
for (a, b) in result.x.iter_mut().zip(other.x.iter()).filter(|_| rng.gen()) { | |
a.step = b.step; | |
} | |
for (a, b) in result.y.iter_mut().zip(other.y.iter()).filter(|_| rng.gen()) { | |
a.step = b.step; | |
} | |
result.mutate() | |
} | |
} | |
fn main() { | |
init(); | |
let canonical_sreda = read_sreda("sreda1", (vec![0.0], 0)); | |
write_sreda(&canonical_sreda); | |
let canonical_result = get_result(); | |
let sreda = read_sreda("sreda_162", canonical_result.clone()); | |
println!("canonical: {:#?}", canonical_result); | |
write_sreda(&sreda); | |
println!("162: {:#?}", get_result()); | |
let units: Vec<Sreda> = (0..15) | |
.map(|_| sreda.clone().mutate()) | |
.collect(); | |
let mut pop = Population::new(units); | |
pop.set_size(15) | |
.set_breed_factor(0.3) | |
.set_survival_factor(0.5); | |
for i in 0..100 { | |
pop.epochs(1); | |
println!("Generation {} --------------------------", i); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment