Browse Source

Initial commit

master
Cameron Weinfurt 3 years ago
commit
415e1c9481
  1. 180
      Cargo.lock
  2. 7
      Cargo.toml
  3. 399
      src/main.rs

180
Cargo.lock

@ -0,0 +1,180 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nuclear_reactor_planner"
version = "0.1.0"
dependencies = [
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

7
Cargo.toml

@ -0,0 +1,7 @@
[package]
name = "nuclear_reactor_planner"
version = "0.1.0"
authors = ["Cameron Weinfurt <weinfurt.c@hotmail.com>"]
[dependencies]
rand = "0.6"

399
src/main.rs

@ -0,0 +1,399 @@
extern crate rand;
use rand::{thread_rng, Rng};
#[derive(Copy, Clone, PartialEq)]
enum ReactorPart { Empty, Cell, Cooler }
#[derive(Clone)]
struct Reactor
{
parts: Vec<ReactorPart>,
xsize: usize,
ysize: usize,
zsize: usize,
volume: usize,
cell_count: u64,
cooler_count: u64,
}
struct ReactorResults
{
internal: Reactor,
net_heat : i32,
steam_per_tick : u64,
steam_total : u64,
reactor_duration_in_ticks : u64,
}
impl Reactor
{
fn is_left_cell(&self, index : usize) -> bool
{
if index % self.xsize == 0 { false }
else { self.parts[index - 1] == ReactorPart::Cell }
}
fn is_right_cell(&self, index : usize) -> bool
{
if (index + 1) % self.xsize == 0 { false }
else { self.parts[index + 1] == ReactorPart::Cell }
}
fn is_down_cell(&self, index : usize) -> bool
{
if (index / self.xsize) % self.ysize == 0 { false }
else { self.parts[index - self.xsize] == ReactorPart::Cell }
}
fn is_up_cell(&self, index : usize) -> bool
{
if ((index + self.xsize) / self.xsize) % self.ysize == 0 { false }
else { self.parts[index + self.xsize] == ReactorPart::Cell }
}
fn is_front_cell(&self, index : usize) -> bool
{
if index < self.xsize * self.ysize { false }
else { self.parts[index - self.xsize * self.ysize] == ReactorPart::Cell }
}
fn is_back_cell(&self, index : usize) -> bool
{
if index >= self.xsize * self.ysize * (self.zsize - 1) { false }
else { self.parts[index + self.xsize * self.ysize] == ReactorPart::Cell }
}
fn test(&self, base_heat: i32, base_power: u64, base_duration_in_sec: u64) -> ReactorResults
{
let mut heat_per_tick : i32 = 0;
let mut steam_per_tick : u64 = 0;
for i in {0..self.parts.len()}
{
match self.parts[i]
{
ReactorPart::Empty => {},
ReactorPart::Cell => {
let mut local_cell_count = 0;
if self.is_left_cell(i) { local_cell_count += 1; }
if self.is_right_cell(i) { local_cell_count += 1; }
if self.is_front_cell(i) { local_cell_count += 1; }
if self.is_back_cell(i) { local_cell_count += 1; }
if self.is_up_cell(i) { local_cell_count += 1; }
if self.is_down_cell(i) { local_cell_count += 1; }
steam_per_tick += (local_cell_count + 1) * base_power * 30 / 4;
heat_per_tick += ((local_cell_count + 1) * (local_cell_count + 2)) as i32 * base_heat / 2;
},
ReactorPart::Cooler => {
if self.is_left_cell(i) || self.is_right_cell(i) || self.is_front_cell(i) || self.is_back_cell(i) || self.is_up_cell(i) || self.is_down_cell(i) { heat_per_tick -= 160; }
else { heat_per_tick -= 80; }
},
}
}
if self.cell_count > 0
{
ReactorResults
{
internal: self.clone(),
net_heat : heat_per_tick,
steam_per_tick : steam_per_tick,
steam_total : 2 * steam_per_tick * base_duration_in_sec / self.cell_count,
reactor_duration_in_ticks : 20 * base_duration_in_sec / self.cell_count,
}
}
else
{
ReactorResults
{
internal: self.clone(),
net_heat : heat_per_tick,
steam_per_tick : steam_per_tick,
steam_total : 0 ,
reactor_duration_in_ticks : 0,
}
}
}
fn print(&self)
{
for y in {0..self.ysize}
{
for z in {0..self.zsize}
{
print!("|");
for x in {0..self.xsize}
{
match self.parts[(x + y*self.xsize + z*self.xsize*self.ysize)]
{
ReactorPart::Empty => print!(" "),
ReactorPart::Cell => print!("*"),
ReactorPart::Cooler => print!("#"),
}
}
print!("|\n");
}
println!("");
}
}
fn neighbor<R: Rng + ?Sized>(&self, rng: &mut R) -> Reactor
{
let index : usize = rng.gen_range(0, self.volume);
let mut other_indexes : Vec<usize> = Vec::new();
if index % self.xsize != 0 { other_indexes.push(index - 1) }
if (index + 1) % self.xsize != 0 { other_indexes.push(index + 1); }
if (index / self.xsize) % self.ysize != 0 { other_indexes.push(index - self.xsize); }
if ((index + self.xsize) / self.xsize) % self.ysize != 0 { other_indexes.push(index + self.xsize); }
if index >= self.xsize * self.ysize { other_indexes.push(index - self.xsize * self.ysize); }
if index < self.xsize * self.ysize * (self.zsize - 1) { other_indexes.push(index + self.xsize * self.ysize); }
let other_index = other_indexes[rng.gen_range(0, other_indexes.len())];
let mut neighbor = self.clone();
let tmp_part = neighbor.parts[index];
neighbor.parts[index] = neighbor.parts[other_index];
neighbor.parts[other_index] = tmp_part;
neighbor
}
}
fn sim_anneal(mut curr_reactor : Reactor, heat_factor: f64, cell_props: (i32, u64, u64)) -> Reactor
{
let max_temp = 1000.0;
let max_iter = 1000;
let mut rng = thread_rng();
let mut curr_result = curr_reactor.test(cell_props.0, cell_props.1, cell_props.2);
for k in {0..max_iter}
{
// if k % 1000 == 0 { println!("Annealing process {0}% complete", k / 100); }
let temp = -max_temp/(max_temp * (max_iter as f64)) * (k as f64) + max_temp;
let neighbor_reactor = curr_reactor.neighbor(&mut rng);
let neighbor_result = neighbor_reactor.test(cell_props.0, cell_props.1, cell_props.2);
let steam_cmp = ((neighbor_result.steam_total as f64) - (curr_result.steam_total as f64)) / (neighbor_result.steam_total as f64 + 1.0);
let mut heat_cmp = -(neighbor_result.net_heat - curr_result.net_heat) as f64 / (neighbor_result.net_heat as f64 + 1.0);
let overheat_penalty = if neighbor_result.net_heat > 1 { heat_factor * temp / (curr_result.net_heat as f64).log10() } else { 1.0 };
let no_steam_penalty = if neighbor_result.steam_total == 0 { 0.01 * temp } else { 1.0 };
if ((steam_cmp + heat_cmp) / 2.0 + 0.5) * (temp / 20.0) * overheat_penalty * no_steam_penalty >= rng.gen_range(0.0, 1.0)
{
curr_reactor = neighbor_reactor;
curr_result = neighbor_result;
}
}
curr_reactor
}
fn gen_reactors(dim: (usize, usize, usize), cell_props: (i32, u64, u64)) -> Vec<Reactor>
{
let mut ret_vec : Vec<Reactor> = Vec::new();
let volume = dim.0 * dim.1 * dim.2;
let mut cells = 1;
loop
{
let needed_coolers = cells * cell_props.1 / 100;
if needed_coolers + cells > volume as u64 || cells > volume as u64 / 4 { break; }
let mut coolers = 0;
let mut parts : Vec<ReactorPart> = Vec::new();
for _i in {0..cells}
{
parts.push(ReactorPart::Cell);
parts.push(ReactorPart::Cooler);
coolers += 1;
}
for _i in {cells*2..volume as u64}
{
parts.push(ReactorPart::Cooler);
coolers += 1;
}
ret_vec.push(Reactor
{
parts: parts.clone(),
xsize: dim.0,
ysize: dim.1,
zsize: dim.2,
volume: volume,
cell_count: cells,
cooler_count: coolers,
});
for i in {0..cells as usize}
{
parts[i] = ReactorPart::Cell;
}
for i in {cells as usize..volume}
{
parts[i] = ReactorPart::Cooler;
}
ret_vec.push(Reactor
{
parts: parts,
xsize: dim.0,
ysize: dim.1,
zsize: dim.2,
volume: volume,
cell_count: cells,
cooler_count: coolers,
});
println!("Queued 2 reactors with {0} cells.", cells);
cells += 1;
}
ret_vec
}
fn print_best_result(dims: (usize, usize, usize), best_result: ReactorResults)
{
let best_reactor = &best_result.internal;
println!("\n\nBest reactor design found:");
best_reactor.print();
println!("Heat: {0} Hu/t\nSteam: {1} mB\nRate: {2} mB/t\nRun time: {3} s\nCell count: {4}", best_result.net_heat, best_result.steam_total, best_result.steam_per_tick, best_result.reactor_duration_in_ticks / 20, best_reactor.cell_count);
println!("Cooler count: {0}", best_reactor.cooler_count);
let casing_crafts = (((dims.0 + 1)*(dims.1 + 1)*(dims.2 + 1) - best_reactor.volume) as f32 / 16.0).ceil() as u64;
let cooler_crafts = (best_reactor.cooler_count as f32 / 16.0).ceil() as u64;
let tough_alloy = casing_crafts * 4 + best_reactor.cell_count + 8;
let u_reactant = tough_alloy + cooler_crafts * 4;
let basic_plating = cooler_crafts * 12 + best_reactor.cell_count * 8 + casing_crafts * 12 + 69;
println!("Resource cost:");
println!(" Coal Dust: {0}\n Iron: {1}\n Lapis: {2}\n Lead: {3}\n Redstone dust: {4}\n Silver: {5}\n Sugar: {6}",
basic_plating * 3/2 + tough_alloy * 2, tough_alloy * 2 + 2, u_reactant, basic_plating * 3/2 + tough_alloy * 2 + 8, u_reactant + best_reactor.cooler_count * 10 + 2, tough_alloy * 2, u_reactant);
println!(" Bronze: 4\n Tin: 200\n Gold: 2\n Boron-10: 3\n Uranium-238: 8");
}
fn select_best(results: Vec<ReactorResults>) -> Option<ReactorResults>
{
let mut best_result = ReactorResults
{
internal: Reactor
{
parts: Vec::new(),
xsize: 0,
ysize: 0,
zsize: 0,
volume: 0,
cell_count: 0,
cooler_count: 0,
},
net_heat : 0,
steam_per_tick : 0,
steam_total : 0 ,
reactor_duration_in_ticks : 0,
};
for result in results
{
if result.net_heat <= 0
{
if best_result.steam_total < result.steam_total
{
println!("New best result with {0} mB of steam.", result.steam_total);
best_result = result;
}
else
{
println!("Valid reactor with {0} cells that produces {1} steam did not perform better than current best.", result.internal.cell_count, result.steam_total);
}
}
else
{
println!("Failed reactor with {0} Hu/t", result.net_heat);
}
}
if best_result.net_heat > 0
{
None
}
else
{
Some(best_result)
}
}
fn main()
{
let dims = (5,5,5);
let cell_props = (320, 600, 4000); // HEN-236
let heat_factor : f64 = 0.005;
let reactors = gen_reactors(dims, cell_props);
let mut results : Vec<ReactorResults> = Vec::new();
for reactor in reactors
{
println!("Testing reactor with {0} cells", reactor.cell_count);
results.push(sim_anneal(reactor, heat_factor, cell_props).test(cell_props.0, cell_props.1, cell_props.2));
}
let best_result = select_best(results);
if best_result.is_none()
{
println!("Could not find valid arrangements for a reactor of this size and fuel of this rating.")
}
else
{
let mut reactors_phase_2 : Vec<Reactor> = Vec::new();
let mut best_reactor = best_result.unwrap().internal;
reactors_phase_2.push(best_reactor.clone());
for index in {0..best_reactor.volume}.rev()
{
if best_reactor.parts[index] == ReactorPart::Cooler
{
best_reactor.parts[index] = ReactorPart::Empty;
best_reactor.cooler_count -= 1;
reactors_phase_2.push(best_reactor.clone());
}
}
results = Vec::new();
for reactor in reactors_phase_2
{
println!("Testing reactor with {0} coolers", reactor.cooler_count);
results.push(reactor.test(cell_props.0, cell_props.1, cell_props.2));
}
let mut cheapest_result = ReactorResults
{
internal: Reactor
{
parts: Vec::new(),
xsize: 0,
ysize: 0,
zsize: 0,
volume: 0,
cell_count: 0,
cooler_count: u64::max_value(),
},
net_heat : 0,
steam_per_tick : 0,
steam_total : 0 ,
reactor_duration_in_ticks : 0,
};
for result in results
{
if result.net_heat > 0
{
println!("Failed reactor with {0} Hu/t", result.net_heat);
}
else if result.internal.cooler_count < cheapest_result.internal.cooler_count
{
println!("New cheapest result with {0} coolers.", result.internal.cooler_count);
cheapest_result = result;
}
else
{
println!("Valid reactor with {0} coolers that produces {1} heat did not cost less than current best.", result.internal.cooler_count, result.net_heat);
}
}
print_best_result(dims, cheapest_result);
}
}
Loading…
Cancel
Save