worldgen 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: de4a34b0248c80788bc6ce2f4a12403b49e8df05
4
+ data.tar.gz: d8210298cd91385beab0cb5366dcc19bfba9eefd
5
+ SHA512:
6
+ metadata.gz: 2829eab4c21503c6243774487c0121dd84fc41300103759116d97c2eeb378ed0a0b5cce0a2f16061d70e24b81bd8ec226375abda3e50827828e3d5316ab8b26f
7
+ data.tar.gz: 58b82dcbc654c466ced978d629881bcba395d4577becff34b40017b912bff9a51462668e426033c36ec7106618be51c2e7b1d066fc24054dd55270acf1822691
@@ -0,0 +1,19 @@
1
+ # Gem/Bundler stuff
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ Makefile
16
+ mkmf.log
17
+
18
+ # Vim stuff
19
+ *.sw[op]
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in worldgen.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Rob Britton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,59 @@
1
+ # Worldgen
2
+
3
+ Worldgen allows you to generate random worlds.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'worldgen'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install worldgen
20
+
21
+ ## Usage
22
+
23
+ So far there is not much. You can do square heightmaps:
24
+
25
+ ```ruby
26
+ # Create a 50x50 heightmap - this will be flat
27
+ heightmap = Worldgen::HeightMap.new 50
28
+ ```
29
+
30
+ Then you can do a diamond square fractal to it:
31
+
32
+ ```ruby
33
+ Worldgen::Algorithms.diamond_square! heightmap
34
+ ```
35
+
36
+ Then dump it to an image file:
37
+
38
+ ```ruby
39
+ Worldgen::Render.heightmap heightmap, "output.png"
40
+ ```
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it ( https://github.com/robbrit/worldgen/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
49
+
50
+ ### Notes
51
+
52
+ Heightmaps are purely written in C for performance. If you're going to be
53
+ writing code that interacts with heightmaps, you're going to have a much
54
+ better time doing it in C since Ruby is a fair bit too slow once you get to
55
+ larger maps (512x512 or higher).
56
+
57
+ ### TODO
58
+
59
+ * Diamond Square output seems to be rougher than it should be
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake/extensiontask"
4
+
5
+ spec = Gem::Specification.load("worldgen.gemspec")
6
+ Rake::ExtensionTask.new("worldgen", spec)
@@ -0,0 +1,31 @@
1
+ #include "common.h"
2
+
3
+ /**
4
+ * Convert an array of doubles into normalized doubles between 0 and 1
5
+ **/
6
+ void normalize(double * values, int size) {
7
+ double min = values[0],
8
+ max = values[0];
9
+
10
+ int x;
11
+
12
+ for (x = 1; x < num_points(size); x++) {
13
+ if (values[x] > max) {
14
+ max = values[x];
15
+ }
16
+ if (values[x] < min) {
17
+ min = values[x];
18
+ }
19
+ }
20
+
21
+ for (x = 0; x < num_points(size); x++) {
22
+ values[x] = (values[x] - min) / (max - min);
23
+ }
24
+ }
25
+
26
+ /** Get the number of points for a heightmap of a given size. This will change
27
+ * later when we move from beyond just a simple square geometry.
28
+ */
29
+ int num_points(int size) {
30
+ return size * size;
31
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef COMMON_H__
2
+ #define COMMON_H__
3
+
4
+ #define ARR(a, x, y) a[(x) * size + (y)]
5
+
6
+ typedef double * heightmap_points;
7
+
8
+ typedef struct {
9
+ int size;
10
+ heightmap_points heights;
11
+ } heightmap;
12
+
13
+ int num_points(int);
14
+ void normalize(double *, int);
15
+
16
+ #endif // COMMON_H__
@@ -0,0 +1,106 @@
1
+ #include <ruby.h>
2
+ #include <stdlib.h>
3
+
4
+ #include "common.h"
5
+
6
+ #define DEFAULT_ROUGHNESS 5
7
+
8
+ extern heightmap get_heights(VALUE);
9
+ extern void set_heights(VALUE, heightmap_points);
10
+ extern int get_size(VALUE);
11
+
12
+ double diamond_shift(double roughness) {
13
+ double r = (double)rand() / (double)RAND_MAX;
14
+
15
+ return (r * 2.0 - 1.0) * roughness;
16
+ }
17
+
18
+ /**
19
+ * Generate terrain using a diamond square algorithm.
20
+ * Arguments:
21
+ * `heightmap` - The heightmap to use for the algorithm
22
+ * `roughness` (optional) - How "rough" to make the surface
23
+ *
24
+ * Return value: nil
25
+ **/
26
+ VALUE diamond_square(int argc, VALUE *argv, VALUE self) {
27
+ int x, y;
28
+ double ratio = 500.0;
29
+ VALUE heightmap_obj, vroughness;
30
+ int size, side_size;
31
+ double roughness;
32
+ heightmap_points heights;
33
+
34
+ rb_scan_args(argc, argv, "11", &heightmap_obj, &vroughness);
35
+
36
+ size = get_size(heightmap_obj);
37
+ side_size = size - 1;
38
+
39
+ roughness = vroughness == Qnil ? DEFAULT_ROUGHNESS : NUM2DBL(vroughness);
40
+
41
+ // need to allocate on the heap since Ruby will throw stack size problems
42
+ // if we don't
43
+ heights = (double *)malloc(sizeof(double) * num_points(size));
44
+
45
+ memset(heights, 0.0, sizeof(double) * num_points(size));
46
+
47
+ ARR(heights, 0, 0) = ARR(heights, 0, size - 1) =
48
+ ARR(heights, size - 1, 0) = ARR(heights, size - 1, size - 1) =
49
+ diamond_shift(roughness);
50
+
51
+ while (side_size >= 2) {
52
+ int half_side = side_size / 2;
53
+
54
+ // Square step
55
+ for (x = 0; x < size - 1; x += side_size) {
56
+ for (y = 0; y < size - 1; y += side_size) {
57
+ double avg = (ARR(heights, x, y) +
58
+ ARR(heights, x + side_size, y) +
59
+ ARR(heights, x, y + side_size) +
60
+ ARR(heights, x + side_size, y + side_size)) / 4.0;
61
+
62
+ ARR(heights, x + half_side, y + half_side) = avg + diamond_shift(roughness);
63
+ }
64
+ }
65
+
66
+ for (x = 0; x < size - 1; x += half_side) {
67
+ for (y = (x + half_side) % side_size; y < size - 1; y += side_size) {
68
+ double avg = (ARR(heights, (x - half_side + size - 1) % (size - 1), y) +
69
+ ARR(heights, (x + half_side) % (size - 1), y) +
70
+ ARR(heights, x, (y + half_side) % (size - 1)) +
71
+ ARR(heights, x, (y - half_side + size - 1) % (size - 1))) / 4.0;
72
+
73
+ avg += diamond_shift(roughness);
74
+
75
+ ARR(heights, x, y) = avg;
76
+
77
+ if (x == 0) {
78
+ ARR(heights, size - 1, y) = avg;
79
+ }
80
+ if (y == 0) {
81
+ ARR(heights, x, size - 1) = avg;
82
+ }
83
+ }
84
+ }
85
+
86
+ side_size /= 2.0;
87
+ ratio /= 2.0;
88
+ }
89
+
90
+ // normalize
91
+ normalize(heights, size);
92
+
93
+ // copy into the array
94
+ set_heights(heightmap_obj, heights);
95
+
96
+ return Qnil;
97
+ }
98
+
99
+ void load_diamond_square() {
100
+ VALUE mod, algos;
101
+
102
+ mod = rb_define_module("Worldgen");
103
+ algos = rb_define_module_under(mod, "Algorithms");
104
+
105
+ rb_define_singleton_method(algos, "diamond_square!", diamond_square, -1);
106
+ }
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("worldgen")
4
+ create_makefile("worldgen")
@@ -0,0 +1,106 @@
1
+ #include <ruby.h>
2
+
3
+ #include "common.h"
4
+
5
+ #include <stdlib.h>
6
+ #include <stdio.h>
7
+ #include <time.h>
8
+
9
+ VALUE HeightmapData; // conversion between heightmap struct and Ruby
10
+
11
+ void delete_heightmap(void * ptr) {
12
+ heightmap *map = (heightmap *)ptr;
13
+ free(map->heights);
14
+ }
15
+
16
+ /**
17
+ * Get the heightmap for a HeightMap object
18
+ */
19
+ heightmap get_heights(VALUE heightmap_obj) {
20
+ VALUE heights_ptr = rb_iv_get(heightmap_obj, "@heights_ptr");
21
+ heightmap *map;
22
+
23
+ Data_Get_Struct(heights_ptr, heightmap, map);
24
+
25
+ return *map;
26
+ }
27
+
28
+ int get_size(VALUE heightmap_obj) {
29
+ return FIX2INT(rb_iv_get(heightmap_obj, "@size"));
30
+ }
31
+
32
+ void set_heights(VALUE heightmap_obj, heightmap_points map) {
33
+ // if we already have a height, kill it
34
+ VALUE heights_ptr;
35
+ heightmap * hmap;
36
+
37
+ hmap = ALLOC(heightmap);
38
+ hmap->heights = map;
39
+ hmap->size = get_size(heightmap_obj);
40
+
41
+ heights_ptr = Data_Wrap_Struct(HeightmapData, 0, delete_heightmap, hmap);
42
+
43
+ rb_iv_set(heightmap_obj, "@heights_ptr", heights_ptr);
44
+ }
45
+
46
+ /**
47
+ * Initialize the C side of things for a heightmap
48
+ */
49
+ VALUE initialize_native(VALUE self, VALUE vsize) {
50
+ int size = FIX2INT(vsize);
51
+ int memsize = num_points(size) * sizeof(double);
52
+
53
+ heightmap_points map = (heightmap_points)malloc(memsize);
54
+ memset(map, 0, memsize);
55
+ set_heights(self, map);
56
+
57
+ return Qnil;
58
+ }
59
+
60
+ /**
61
+ * Get the number of points within the heightmap. Right now this is a very
62
+ * simple calculation of size * size.
63
+ */
64
+ VALUE num_points_wrapped(VALUE self) {
65
+ return INT2FIX(num_points(FIX2INT(rb_iv_get(self, "@size"))));
66
+ }
67
+
68
+ /**
69
+ * Iterate over all the points in the heightmap.
70
+ * Example:
71
+ * ```
72
+ * heightmap.each_height do |x, y, height|
73
+ * puts "Height at (#{x}, #{y}) is #{height}"
74
+ * end
75
+ */
76
+ VALUE each_height(VALUE self) {
77
+ heightmap map = get_heights(self);
78
+ heightmap_points ptr = map.heights;
79
+ VALUE args = rb_ary_new2(3);
80
+ int size = get_size(self);
81
+ int x, y;
82
+
83
+ for (x = 0; x < size; x++) {
84
+ rb_ary_store(args, 0, INT2FIX(x));
85
+ for (y = 0; y < size; y++) {
86
+ rb_ary_store(args, 1, INT2FIX(y));
87
+ rb_ary_store(args, 2, DBL2NUM(*ptr++));
88
+ rb_yield(args);
89
+ }
90
+ }
91
+ return self;
92
+ }
93
+
94
+ void load_heightmap() {
95
+ VALUE mod, height_map;
96
+
97
+ mod = rb_define_module("Worldgen");
98
+
99
+ height_map = rb_define_class_under(mod, "HeightMap", rb_cObject);
100
+
101
+ rb_define_private_method(height_map, "initialize_native", initialize_native, 1);
102
+ rb_define_method(height_map, "num_points", num_points_wrapped, 0);
103
+ rb_define_method(height_map, "each_height", each_height, 0);
104
+
105
+ HeightmapData = rb_define_class_under(height_map, "HeightmapData", rb_cObject);
106
+ }
@@ -0,0 +1,13 @@
1
+ #include <ruby.h>
2
+ #include <stdlib.h>
3
+ #include <time.h>
4
+
5
+ extern void load_heightmap();
6
+ extern void load_diamond_square();
7
+
8
+ void Init_worldgen() {
9
+ srand((unsigned)time(NULL));
10
+
11
+ load_heightmap();
12
+ load_diamond_square();
13
+ }
@@ -0,0 +1,51 @@
1
+ require 'optparse'
2
+ require "worldgen"
3
+
4
+ options = {}
5
+
6
+ OptionParser.new do |opts|
7
+ opts.on("--heightmap [FILE]", String, "Output a heightmap to FILE") do |file|
8
+ options[:heightmap] = file
9
+ end
10
+
11
+ opts.on("--platemap [FILE]", String, "Output a platemap to FILE") do |file|
12
+ options[:platemap] = file
13
+ end
14
+
15
+ opts.on("--size N", Integer, "Generate a map of size 2^N + 1") do |n|
16
+ options[:size] = 2**n + 1
17
+ end
18
+
19
+ opts.on("--num-plates [N]", Integer, "Generate N plates") do |n|
20
+ options[:num_plates] = n
21
+ end
22
+ end.parse!
23
+
24
+ if not options[:size]
25
+ puts "No size specified."
26
+ exit
27
+ end
28
+
29
+ if options[:heightmap]
30
+ puts "Generating heightmap..."
31
+ heightmap = Worldgen::HeightMap.new(options[:size])
32
+ Worldgen::Algorithms.diamond_square!(heightmap)
33
+ Worldgen::Render.heightmap heightmap, options[:heightmap]
34
+ end
35
+
36
+ if options[:platemap]
37
+ puts "Generating plate map..."
38
+ if not options[:num_plates]
39
+ puts "num_plates not specified."
40
+ exit
41
+ end
42
+
43
+ platemap = Worldgen::PlateMap.new(options[:size])
44
+ platemap.generate_plates! options[:num_plates]
45
+ puts "Converting to height map..."
46
+ heightmap = platemap.to_height_map
47
+ render_heightmap heightmap, options[:platemap]
48
+ end
49
+
50
+ puts "Done."
51
+
@@ -0,0 +1,8 @@
1
+ require "worldgen/version"
2
+ require "worldgen/heightmap"
3
+ require "worldgen/render"
4
+ require_relative "worldgen.so"
5
+
6
+ module Worldgen
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,18 @@
1
+ module Worldgen
2
+ # A square heightmap
3
+ class HeightMap
4
+ # A class used internally to manage C-allocated memory
5
+ class HeightmapData
6
+ end
7
+
8
+ attr_reader :size
9
+
10
+ # Create a new square heightmap.
11
+ # Arguments:
12
+ # * size - the width/height of the map
13
+ def initialize size
14
+ @size = size
15
+ initialize_native(size)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ require 'RMagick'
2
+
3
+ module Worldgen::Render
4
+ # Render a heightmap to a grayscale file.
5
+ # Arguments:
6
+ # * map - The heightmap to render
7
+ # * filename - The filename to use. Image format will be inferred from the filename
8
+ def self.heightmap map, filename
9
+ # loading each one in is crazy slow, just throw it into a pixel map
10
+ image = Magick::Image.new(map.size, map.size) { self.background_color = "black" }
11
+
12
+ map.each_height do |x, y, pix_height|
13
+ grey = ("%2X" % (pix_height * 255).round) * 3
14
+ image.pixel_color x, y, "##{grey}"
15
+ end
16
+
17
+ #image.display
18
+ image.write filename
19
+ end
20
+
21
+ =begin
22
+ def self.platemap map, filename
23
+ image = Magick::Image.new(map.size, map.size) { self.background_color = "black" }
24
+
25
+ # draw plates
26
+ colours = [
27
+ "#FF0000", "#0000FF", "#FFFF00", "#00FF00",
28
+ "#FF6600", "#FF00FF", "#00FFFF", "#CCCCCC",
29
+ "#006600", "#000066", "#660066", "#666600"
30
+ ]
31
+ map.each_plate_point do |x, y, plate|
32
+ begin
33
+ image.pixel_color x, y, colours[plate]
34
+ rescue
35
+ puts "colour fail"
36
+ puts [x, y, plate, colour[plate]].inspect
37
+ end
38
+ end
39
+
40
+ #image.display
41
+ image.write filename
42
+ end
43
+ =end
44
+ end
@@ -0,0 +1,3 @@
1
+ module Worldgen
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'worldgen/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "worldgen"
8
+ spec.version = Worldgen::VERSION
9
+ spec.authors = ["Rob Britton"]
10
+ spec.email = ["rob@robbritton.com"]
11
+ spec.summary = %q{Gem to handle procedural content generation for worlds.}
12
+ #spec.description = %q{TODO: Write a longer description. Optional.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.extensions << "ext/worldgen/extconf.rb"
22
+
23
+ spec.add_dependency "rmagick", "~> 2.13.3"
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rake-compiler", "~> 0.9.3"
27
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: worldgen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Rob Britton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rmagick
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.13.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.13.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake-compiler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.3
69
+ description:
70
+ email:
71
+ - rob@robbritton.com
72
+ executables: []
73
+ extensions:
74
+ - ext/worldgen/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - ext/worldgen/common.c
83
+ - ext/worldgen/common.h
84
+ - ext/worldgen/diamondsquare.c
85
+ - ext/worldgen/extconf.rb
86
+ - ext/worldgen/heightmap.c
87
+ - ext/worldgen/worldgen.c
88
+ - generate.rb
89
+ - lib/worldgen.rb
90
+ - lib/worldgen/heightmap.rb
91
+ - lib/worldgen/render.rb
92
+ - lib/worldgen/version.rb
93
+ - worldgen.gemspec
94
+ homepage: ''
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.1.11
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Gem to handle procedural content generation for worlds.
118
+ test_files: []