Metrics Fixed: #20, Fixed #21.

This commit is contained in:
klangner 2021-01-14 12:18:31 +01:00
parent f25b454c00
commit 56417cf9b4
10 changed files with 159 additions and 83 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mapgen-demo" name = "mapgen-demo"
version = "0.1.1" version = "0.1.2"
authors = ["Krzysztof Langner <klangner@gmail.com>"] authors = ["Krzysztof Langner <klangner@gmail.com>"]
description = "Map generator demo" description = "Map generator demo"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -11,8 +11,9 @@ edition = "2018"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
rand = { version = "0.7", features = ["wasm-bindgen"] }
mapgen = {path=".."} mapgen = {path=".."}
getrandom = { version = "0.2", features = ["js"] }
rand = "0.8"
wasm-bindgen = "0.2" wasm-bindgen = "0.2"
js-sys = "0.3" js-sys = "0.3"

View File

@ -1,59 +0,0 @@
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
</head>
<body>
<!-- Note the usage of `type=module` here as this is an ES6 module -->
<script type="module">
// Use ES module import syntax to import functionality from the module
// that we have compiled.
//
// Note that the `default` import is an initialization function which
// will "boot" the module and make it ready to use. Currently browsers
// don't support natively imported WebAssembly as an ES module, but
// eventually the manual initialization won't be required!
import init, { add } from './pkg/mapgen_demo.js';
async function run() {
// First up we need to actually load the wasm file, so we use the
// default export to inform it where the wasm file is located on the
// server, and then we wait on the returned promise to wait for the
// wasm to be loaded.
//
// It may look like this: `await init('./pkg/without_a_bundler_bg.wasm');`,
// but there is also a handy default inside `init` function, which uses
// `import.meta` to locate the wasm file relatively to js file.
//
// Note that instead of a string you can also pass in any of the
// following things:
//
// * `WebAssembly.Module`
//
// * `ArrayBuffer`
//
// * `Response`
//
// * `Promise` which returns any of the above, e.g. `fetch("./path/to/wasm")`
//
// This gives you complete control over how the module is loaded
// and compiled.
//
// Also note that the promise, when resolved, yields the wasm module's
// exports which is the same as importing the `*_bg` module in other
// modes
await init();
// And afterwards we can use all the functionality defined in wasm.
const result = add(1, 2);
console.log(`1 + 2 = ${result}`);
if (result !== 3)
throw new Error("wasm addition doesn't work!");
}
run();
</script>
</body>
</html>

View File

@ -3,6 +3,7 @@ use web_sys;
use rand::prelude::*; use rand::prelude::*;
use mapgen::{Map, MapBuilder, TileType, geometry::Point}; use mapgen::{Map, MapBuilder, TileType, geometry::Point};
use mapgen::filter::*; use mapgen::filter::*;
use mapgen::metric;
#[wasm_bindgen] #[wasm_bindgen]
@ -48,6 +49,7 @@ impl World {
.with(CullUnreachable::new()) .with(CullUnreachable::new())
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -60,6 +62,7 @@ impl World {
.with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP)) .with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP))
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -72,6 +75,7 @@ impl World {
.with(AreaStartingPosition::new(XStart::LEFT, YStart::BOTTOM)) .with(AreaStartingPosition::new(XStart::LEFT, YStart::BOTTOM))
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -84,6 +88,7 @@ impl World {
.with(CullUnreachable::new()) .with(CullUnreachable::new())
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -96,6 +101,7 @@ impl World {
.with(CullUnreachable::new()) .with(CullUnreachable::new())
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -107,6 +113,7 @@ impl World {
.with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP)) .with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP))
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -118,6 +125,7 @@ impl World {
.with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP)) .with(AreaStartingPosition::new(XStart::LEFT, YStart::TOP))
.with(DistantExit::new()) .with(DistantExit::new())
.build_with_rng(&mut rng); .build_with_rng(&mut rng);
World::print_map_metrics(&map);
World::new(width, height, map) World::new(width, height, map)
} }
@ -167,6 +175,16 @@ impl World {
let div = document.get_element_by_id("map-info").expect("Need div with id: map-info"); let div = document.get_element_by_id("map-info").expect("Need div with id: map-info");
div.set_inner_html(&info); div.set_inner_html(&info);
} }
fn print_map_metrics(map: &Map) {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
let div = document.get_element_by_id("map-metrics").expect("Need div with id: map-metrics");
let density = metric::density(map);
let path_length = metric::path_length(map);
let info = format!("Metrics: density: {}, path length: {}", density, path_length);
div.set_inner_html(&info);
}
} }
#[wasm_bindgen] #[wasm_bindgen]

View File

@ -55,6 +55,7 @@
<canvas id="mapgen-canvas"></canvas> <canvas id="mapgen-canvas"></canvas>
<div id="map-info" style="text-align: center"></div> <div id="map-info" style="text-align: center"></div>
<div id="map-metrics" style="text-align: center"></div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>

File diff suppressed because one or more lines are too long

Binary file not shown.

54
docs/bootstrap.js vendored
View File

@ -58,33 +58,30 @@
/******/ "__wbindgen_object_drop_ref": function(p0i32) { /******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_object_drop_ref"](p0i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ }, /******/ },
/******/ "__wbg_getRandomValues_3ac1b33c90b52596": function(p0i32,p1i32,p2i32) { /******/ "__wbg_getRandomValues_c73f06b5ed8b878d": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_getRandomValues_3ac1b33c90b52596"](p0i32,p1i32,p2i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_getRandomValues_c73f06b5ed8b878d"](p0i32,p1i32);
/******/ }, /******/ },
/******/ "__wbg_randomFillSync_6f956029658662ec": function(p0i32,p1i32,p2i32) { /******/ "__wbg_randomFillSync_5fa0a72035c7bfd9": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_randomFillSync_6f956029658662ec"](p0i32,p1i32,p2i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_randomFillSync_5fa0a72035c7bfd9"](p0i32,p1i32,p2i32);
/******/ }, /******/ },
/******/ "__wbg_self_1c83eb4471d9eb9b": function() { /******/ "__wbg_self_23b14d60c8dbf9da": function() {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_self_1c83eb4471d9eb9b"](); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_self_23b14d60c8dbf9da"]();
/******/ }, /******/ },
/******/ "__wbg_static_accessor_MODULE_abf5ae284bffdf45": function() { /******/ "__wbg_static_accessor_MODULE_ff1e47f7076e0ee1": function() {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_static_accessor_MODULE_abf5ae284bffdf45"](); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_static_accessor_MODULE_ff1e47f7076e0ee1"]();
/******/ }, /******/ },
/******/ "__wbg_require_5b2b5b594d809d9f": function(p0i32,p1i32,p2i32) { /******/ "__wbg_require_1dab18ea211c4fa1": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_require_5b2b5b594d809d9f"](p0i32,p1i32,p2i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_require_1dab18ea211c4fa1"](p0i32,p1i32,p2i32);
/******/ }, /******/ },
/******/ "__wbg_crypto_c12f14e810edcaa2": function(p0i32) { /******/ "__wbg_crypto_df96f3577c8a9bae": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_crypto_c12f14e810edcaa2"](p0i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_crypto_df96f3577c8a9bae"](p0i32);
/******/ }, /******/ },
/******/ "__wbg_msCrypto_679be765111ba775": function(p0i32) { /******/ "__wbg_msCrypto_331efcdb9be40d7c": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_msCrypto_679be765111ba775"](p0i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_msCrypto_331efcdb9be40d7c"](p0i32);
/******/ }, /******/ },
/******/ "__wbindgen_is_undefined": function(p0i32) { /******/ "__wbindgen_is_undefined": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_is_undefined"](p0i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_is_undefined"](p0i32);
/******/ }, /******/ },
/******/ "__wbg_getRandomValues_05a60bf171bfc2be": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_getRandomValues_05a60bf171bfc2be"](p0i32);
/******/ },
/******/ "__wbg_instanceof_Window_adf3196bdc02b386": function(p0i32) { /******/ "__wbg_instanceof_Window_adf3196bdc02b386": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_instanceof_Window_adf3196bdc02b386"](p0i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_instanceof_Window_adf3196bdc02b386"](p0i32);
/******/ }, /******/ },
@ -118,8 +115,29 @@
/******/ "__wbg_global_e16303fe83e1d57f": function() { /******/ "__wbg_global_e16303fe83e1d57f": function() {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_global_e16303fe83e1d57f"](); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_global_e16303fe83e1d57f"]();
/******/ }, /******/ },
/******/ "__wbg_buffer_49131c283a06686f": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_buffer_49131c283a06686f"](p0i32);
/******/ },
/******/ "__wbg_length_2b13641a9d906653": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_length_2b13641a9d906653"](p0i32);
/******/ },
/******/ "__wbg_new_9b295d24cf1d706f": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_new_9b295d24cf1d706f"](p0i32);
/******/ },
/******/ "__wbg_set_3bb960a9975f3cd2": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_set_3bb960a9975f3cd2"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbg_newwithlength_3c570aeea9a95954": function(p0i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_newwithlength_3c570aeea9a95954"](p0i32);
/******/ },
/******/ "__wbg_subarray_4eaeb3de00cf1955": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbg_subarray_4eaeb3de00cf1955"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) { /******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_throw"](p0i32,p1i32); /******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_memory": function() {
/******/ return installedModules["../pkg/mapgen_demo_bg.js"].exports["__wbindgen_memory"]();
/******/ } /******/ }
/******/ } /******/ }
/******/ }; /******/ };
@ -222,7 +240,7 @@
/******/ promises.push(installedWasmModuleData); /******/ promises.push(installedWasmModuleData);
/******/ else { /******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId](); /******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/mapgen_demo_bg.wasm":"f22182091a16774e383e"}[wasmModuleId] + ".module.wasm"); /******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/mapgen_demo_bg.wasm":"98c7bb1ad7a2b17fcade"}[wasmModuleId] + ".module.wasm");
/******/ var promise; /******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') { /******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) { /******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

View File

@ -55,6 +55,7 @@
<canvas id="mapgen-canvas"></canvas> <canvas id="mapgen-canvas"></canvas>
<div id="map-info" style="text-align: center"></div> <div id="map-info" style="text-align: center"></div>
<div id="map-metrics" style="text-align: center"></div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>

View File

@ -31,6 +31,7 @@
pub mod filter; pub mod filter;
pub mod geometry; pub mod geometry;
pub mod map; pub mod map;
pub mod metric;
pub use map::{Map, Symmetry, TileType}; pub use map::{Map, Symmetry, TileType};
pub use filter::*; pub use filter::*;

95
src/metric.rs Normal file
View File

@ -0,0 +1,95 @@
//! Different metrics for the map
//! Can be used to meausre the quality of the map or the quality of the generator.
//! To meause the quality of the generator; generate lots of maps, measure them
//! and the provide generator score as an average.
//!
use super::map::{Map, TileType};
use super::dijkstra::DijkstraMap;
/// This metric calculates the percentage of walkable cells (Floor).
/// If this number is very low (like < 10%) then it means that the map
/// is probably to degenerated and shouldn't be used
pub fn density(map: &Map) -> f32 {
let floor_count = map.tiles.iter()
.filter(|&t| *t == TileType::Floor)
.count();
floor_count as f32 / map.tiles.len() as f32
}
/// Calculate the length of the shortes path from the starting point
/// to the exit.
/// If this path is very short, then the map is probably degenerated.
pub fn path_length(map: &Map) -> f32 {
if map.starting_point.is_none() {
return 0.0
}
match map.exit_point {
None => 0.0,
Some(exit) => {
let dijkstra = DijkstraMap::new(map);
dijkstra.tiles[map.xy_idx(exit.x, exit.y)]
},
}
}
/// ------------------------------------------------------------------------------------------------
/// Module unit tests
/// ------------------------------------------------------------------------------------------------
#[cfg(test)]
mod tests {
use super::*;
use crate::geometry::Point;
#[test]
fn test_density_no_floor() {
let map = Map::new(10, 10);
let score = density(&map);
assert_eq!(score, 0.0);
}
#[test]
fn test_density() {
let map_str = "
##########
# ## #
##########
";
let map = Map::from_string(map_str);
let score = density(&map);
assert_eq!(score, 0.2);
}
#[test]
fn test_no_path() {
let map_str = "
##########
# ## #
##########
";
let map = Map::from_string(map_str);
let score = path_length(&map);
assert_eq!(score, 0.0);
}
#[test]
fn test_path_length() {
let map_str = "
##########
# ## #
# #
##########
";
let mut map = Map::from_string(map_str);
map.starting_point = Some(Point::new(1,1));
map.exit_point = Some(Point::new(8,1));
let score = path_length(&map);
assert!(f32::abs(score - 7.9) <= 0.01);
}
}