oolite 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a7c6827b7924ebbeca80991a4ce8557f68796687
4
+ data.tar.gz: 1910d5718f908f7f3726c6307c4060fb808916d7
5
+ SHA512:
6
+ metadata.gz: 8cf6dc36233b7896e6ae727a9190049d260c528249798d39ff242a21c95fa34fb627ed056d8927f9f6d108e031dac6ff3c294cf93db8d759bd9afbd569624e6e
7
+ data.tar.gz: ded361ce7720a382df492177d6c1bb55a6d1709ea7d31ed332682ef95529dc99e7452602713aee9413ddba63bc3610b12cf078e686f4b87d0df47bcb02d8cd86
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in oolite.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jeff McAffee
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.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Oolite
2
+
3
+ Utility scripts for monitoring the Oolite game's system markets and
4
+ providing trading suggestions based on the market data.
5
+
6
+ ## Installation
7
+
8
+ If you wish to clone the repository:
9
+
10
+ $ git clone https://github.com/jmcaffee/oolite.git
11
+ $ cd oolite
12
+ $ bundle
13
+
14
+ # Use rake to install the gem
15
+ rake install
16
+
17
+ # To start a pry console using the local version of the gem
18
+ rake console
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install oolite
23
+
24
+ ## Usage
25
+
26
+ These scripts are provided as standalone utilities. Simply install
27
+ the gem as detailed above to provide the following commands:
28
+
29
+ ooconfig - configure the scripts (ie. your save file location)
30
+ ootrader - suggest the best trades based on current location and destination
31
+ ooupdatemarket - update the market data (pulls from your save file)
32
+
33
+ ### ooconfig
34
+
35
+ `ooconfig` displays and edits the configuration file.
36
+
37
+ The oolite scripts will look for the config file starting in your current directory
38
+ and ascending the directory tree until it reaches the root, then look in your _home_
39
+ directory. I would suggest running your initial configuration from your home dir
40
+ so the scripts can always find the config file no matter where you call them from.
41
+
42
+ To get started, determine where your save file is located at and change to your
43
+ home directory.
44
+
45
+ # Assuming your save file is at ~/oolite-saves/Jameson.oolite-save
46
+ cd ~
47
+ ooconfig save_file_path ~/oolite-saves/Jameson.oolite-save
48
+
49
+ You can see where the config file is located at by running
50
+
51
+ ooconfig path
52
+
53
+ To see the current configuration values, run
54
+
55
+ ooconfig show
56
+
57
+ To see available commands/options, run
58
+
59
+ ooconfig
60
+
61
+ ### ooupdatemarket
62
+
63
+ `ooupdatemarket` saves its data in the same directory as your game save file.
64
+ It also generates a `CSV` dump of the most recent market data for all visited
65
+ systems.
66
+
67
+ Note that the data is only current for the system you are located at when you
68
+ save your game. The other system data is retained from the last time you visited
69
+ the system, saved your game, and ran `ooupdatemarket`.
70
+
71
+ ### ootrader
72
+
73
+ `ootrader` will ask you for your destination system based on existing data
74
+ (ie. you've visited the destination at least once, saved your game, and ran
75
+ `ooupdatemarket`), then calculate and display all profitable trades, then
76
+ display its suggested trades to make the most profit.
77
+
78
+ It uses the current market data, your available credits and max cargo space
79
+ to make its suggestions.
80
+
81
+ ## Workflow (Gameflow?)
82
+
83
+ * Dock your ship in game
84
+ * Sell your current cargo
85
+ * Refuel you ship
86
+ * Save your game
87
+
88
+ In a terminal, update your market data
89
+
90
+ ooupdatemarket
91
+
92
+ Now see what it suggests for trades
93
+
94
+ ootrader
95
+
96
+ **Note:** you'll need to visit more than one system, save your game,
97
+ and run `ooupdatemarket` before you'll be able to choose any destinations.
98
+
99
+ * In game, make your trades/purchases
100
+ * Travel to your destination
101
+ * Profit
102
+
103
+ ## About This Project
104
+
105
+ These scripts were thrown together over the course of a couple of days.
106
+ As such, the code is not the prettiest, and I'm sure it's ripe for
107
+ refactoring.
108
+
109
+ I know that there are OXPs that can perform the same functionality (and
110
+ they're in-game too!) but I'm just scratching my itch to code here.
111
+
112
+ If you find errors, please create issues in the issue tracker. If you'd like
113
+ to add additional features, fork the project and submit a pull request.
114
+
115
+ ## Roadmap
116
+
117
+ * Refactor the code
118
+
119
+ ## Contributing
120
+
121
+ 1. Fork it ( https://github.com/[my-github-username]/oolite/fork )
122
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
123
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
124
+ 4. Push to the branch (`git push origin my-new-feature`)
125
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc 'start a console'
4
+ task :console do
5
+ require 'pry'
6
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
7
+ require 'oolite'
8
+ ARGV.clear
9
+
10
+ def console_help
11
+ puts <<CONSOLE_HELP
12
+ CONSOLE HELP
13
+ -------------
14
+
15
+ Starts a pry console and requires the *local* version of Oolite.
16
+
17
+ Search and load the Oolite configuration (defaults will be set if
18
+ no configuration file is found)
19
+
20
+ Oolite.configure
21
+
22
+ OR
23
+
24
+ Oolite.configure do |config|
25
+ config.some_setting = some_value
26
+ end
27
+
28
+ After a configuration has been instantiated, you can retrieve the
29
+ current configuration with
30
+
31
+ Oolite.configuration
32
+
33
+
34
+ CONSOLE_HELP
35
+ end
36
+
37
+ console_help
38
+ Pry.start
39
+ end
40
+
data/bin/ooconfig ADDED
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # vim: set ft=ruby
4
+ ##############################################################################
5
+ # File:: ooconfig
6
+ # Purpose:: Configure the oolite utility
7
+ #
8
+ # Author:: Jeff McAffee 05/20/2015
9
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
10
+ # Website:: http://ktechsystems.com
11
+ ##############################################################################
12
+
13
+ require 'pathname'
14
+ begin
15
+ require 'oolite'
16
+ rescue LoadError
17
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
18
+ require 'oolite'
19
+ end
20
+
21
+
22
+ class Main
23
+
24
+ private
25
+
26
+ def usage
27
+ puts "Usage: #{File.basename($0)} [ CMD | OPTION VALUE ]"
28
+ puts
29
+ puts " Available commands:"
30
+ puts " show: show current configuration settings"
31
+ puts " path: show location of config file (if found)"
32
+ puts " update CATEGORY VALUES: update a category item"
33
+ puts " categories:"
34
+ puts " systems: accepts (in order) NAME ECONOMY GOVERNMENT TECHLEVEL"
35
+ puts
36
+ puts " Available options:"
37
+ puts " save_file_path: path to Oolite save file (~ is allowed)"
38
+ puts
39
+ end
40
+
41
+ def current_settings
42
+ puts "= Current Configuration Settings ="
43
+ puts
44
+ Oolite.configure do |config|
45
+ vars = config.instance_variables.map { |v| v.to_s.gsub('@','') }
46
+ vars.each do |var|
47
+ puts "#{var}: #{emit_value(config.send(var))}"
48
+ end
49
+ end
50
+ end
51
+
52
+ def emit_value val
53
+ case val
54
+ when Array
55
+ emit_array(val)
56
+ when Hash
57
+ emit_hash(val)
58
+ else
59
+ return val
60
+ end
61
+ end
62
+
63
+ def emit_array val
64
+ nl = "\n"
65
+ indent = " "
66
+ output = nl.dup
67
+
68
+ val.each do |elem|
69
+ output << indent << elem << nl
70
+ end
71
+ output << nl
72
+ end
73
+
74
+ def emit_hash val
75
+ nl = "\n"
76
+ indent = " "
77
+ output = nl.dup
78
+
79
+ val.each do |key,elem|
80
+ output << indent << "#{key}: " << indent << emit_value(elem) << nl
81
+ end
82
+ output
83
+ end
84
+
85
+ def set_config_values args
86
+ Oolite.configure do |config|
87
+ while args.count > 0
88
+ var = args.shift
89
+ val = args.shift
90
+ config.send("#{var}=", val)
91
+ end
92
+ end
93
+
94
+ Oolite.save_configuration
95
+ end
96
+
97
+ def system_data args
98
+ econ = args.shift
99
+ gov = args.shift
100
+ tech = args.shift
101
+
102
+ data = Hash.new
103
+ data[:economy] = econ unless econ.nil?
104
+ data[:government] = gov unless gov.nil?
105
+ data[:tech_level] = tech unless tech.nil?
106
+
107
+ data
108
+ end
109
+
110
+ def update args
111
+ category = args.shift
112
+ case category
113
+ when "systems"
114
+ Oolite.configure do |config|
115
+ name = args.shift
116
+ val = config.systems.fetch(name, Hash.new)
117
+ #val = val.merge( { name => system_data(args) } )
118
+ val = val.merge( system_data(args) )
119
+ config.systems[name] = val
120
+ end
121
+
122
+ Oolite.save_configuration
123
+ else
124
+ puts "Unknown category: #{category}"
125
+ end
126
+ end
127
+
128
+ def process_cmd args
129
+ return false unless args.count > 0
130
+
131
+ if args.first.downcase == 'show'
132
+ current_settings
133
+ return true
134
+ end
135
+
136
+ if args.first.downcase == 'path'
137
+ path = Oolite.find_config_path
138
+ path = 'Not found' if path.nil? || path.to_s.empty?
139
+ puts "path: #{path}"
140
+ return true
141
+ end
142
+
143
+ if args.first.downcase == 'update'
144
+ args.shift
145
+ update args
146
+ return true
147
+ end
148
+ end
149
+
150
+ public
151
+
152
+ def execute args
153
+ if process_cmd(args)
154
+ return 0
155
+ end
156
+
157
+ if args.count < 2
158
+
159
+ usage
160
+ return 1
161
+ end
162
+
163
+ set_config_values args
164
+ end
165
+ end
166
+
167
+ Main.new.execute ARGV
168
+
data/bin/ootrader ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # vim: set ft=ruby
4
+ ##############################################################################
5
+ # File:: ootrader
6
+ # Purpose:: Determine the best items to buy based on the current location
7
+ # and the next destination
8
+ #
9
+ # Author:: Jeff McAffee 05/20/2015
10
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
11
+ # Website:: http://ktechsystems.com
12
+ ##############################################################################
13
+
14
+ require 'pathname'
15
+ begin
16
+ require 'oolite'
17
+ rescue LoadError
18
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
19
+ require 'oolite'
20
+ end
21
+
22
+
23
+ class Main
24
+
25
+ def execute
26
+ savefile = Oolite.configuration.save_file_path
27
+ if savefile.nil? || savefile.empty?
28
+ fail "save file path not set.\nUse 'ooconfig save_file_path YOUR_PATH' to set."
29
+ end
30
+
31
+ # Update the market file so we're working with the latest data.
32
+ market = Oolite::Market.new
33
+ market.update
34
+
35
+ # Display the best trades.
36
+ trader = Oolite::Trade.new.display
37
+ end
38
+ end
39
+
40
+ Main.new.execute
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # vim: set ft=ruby
4
+ ##############################################################################
5
+ # File:: ooupdatemarket
6
+ # Purpose:: Parse the Oolite save file and generate market info based on the
7
+ # current docked location's market
8
+ #
9
+ # Author:: Jeff McAffee 05/19/2015
10
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
11
+ # Website:: http://ktechsystems.com
12
+ ##############################################################################
13
+
14
+ require 'pathname'
15
+ begin
16
+ require 'oolite'
17
+ rescue LoadError
18
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
19
+ require 'oolite'
20
+ end
21
+
22
+
23
+ class Main
24
+
25
+ def execute
26
+ savefile = Oolite.configuration.save_file_path
27
+ if savefile.nil? || savefile.empty?
28
+ fail "save file path not set.\nUse 'ooconfig save_file_path YOUR_PATH' to set."
29
+ end
30
+
31
+ market = Oolite::Market.new
32
+ market.update
33
+ market.write_csv
34
+ end
35
+ end
36
+
37
+ if ARGV.count > 0 && ARGV.first.downcase == 'upgrade'
38
+ market = Oolite::Market.new
39
+ market.upgrade
40
+ elsif ARGV.count > 0 && ARGV.first.downcase == 'upgradeprice'
41
+ market = Oolite::Market.new
42
+ market.upgrade_price
43
+ else
44
+ Main.new.execute
45
+ end
data/lib/oolite.rb ADDED
@@ -0,0 +1,191 @@
1
+ require "oolite/version"
2
+
3
+ if ENV['DEBUG'].nil?
4
+ $debug = false
5
+ else
6
+ $debug = true
7
+ end
8
+
9
+ module Oolite
10
+ CONFIG_FILE_NAME = '.oolite'
11
+
12
+ class << self
13
+ attr_accessor :configuration
14
+ end
15
+
16
+ ##
17
+ # Setup oolite configuration
18
+ #
19
+ # Attempts to find and load a configuration file the first time
20
+ # it's requested. If a config file cannot be found in the current
21
+ # directory tree (moving towards trunk, not the leaves), the user's
22
+ # home directory will be searched. If still not found, a default
23
+ # configuration object is created.
24
+ #
25
+ # If a block is provided, the configuration object is yielded to the block
26
+ # after the configuration is loaded/created.
27
+ #
28
+
29
+ def self.configure
30
+ if self.configuration.nil?
31
+ unless self.load_configuration
32
+ self.configuration = Configuration.new
33
+ end
34
+ end
35
+ yield(configuration) if block_given?
36
+ end
37
+
38
+ ##
39
+ # Walk up the directory tree from current working dir (pwd) till a file
40
+ # named .oolite is found
41
+ #
42
+ # Returns file path if found, nil if not.
43
+ #
44
+
45
+ def self.find_config_path
46
+ path = Pathname(Pathname.pwd).ascend{|d| h=d+CONFIG_FILE_NAME; break h if h.file?}
47
+ if path.nil? && (Pathname(ENV['HOME']) + CONFIG_FILE_NAME).exist?
48
+ path = Pathname(ENV['HOME']) + CONFIG_FILE_NAME
49
+ end
50
+ path
51
+ end
52
+
53
+ ##
54
+ # Write configuration to disk
55
+ #
56
+ # Writes to current working dir (pwd) if path is nil
57
+ #
58
+ # Returns path of emitted file
59
+ #
60
+
61
+ def self.save_configuration(path = nil)
62
+ # If no path provided, see if we can find one in the dir tree.
63
+ if path.nil?
64
+ path = find_config_path
65
+ end
66
+
67
+ # Still no path? Use the current working dir.
68
+ if path.nil?
69
+ path = Pathname.pwd
70
+ end
71
+
72
+ unless path.to_s.end_with?('/' + CONFIG_FILE_NAME)
73
+ path = Pathname(path) + CONFIG_FILE_NAME
74
+ end
75
+
76
+ path = Pathname(path).expand_path
77
+ File.write(path, YAML.dump(configuration))
78
+
79
+ path
80
+ end
81
+
82
+ ##
83
+ # Load the configuration from disk
84
+ #
85
+ # Returns true if config file found and loaded, false otherwise.
86
+ #
87
+
88
+ def self.load_configuration(path = nil)
89
+ # If no path provided, see if we can find one in the dir tree.
90
+ if path.nil?
91
+ path = find_config_path
92
+ end
93
+
94
+ return false if path.nil?
95
+ return false unless Pathname(path).exist?
96
+
97
+ File.open(path, 'r') do |f|
98
+ self.configuration = YAML.load(f)
99
+ puts "configuration loaded from #{path}" if $debug
100
+ end
101
+
102
+ true
103
+ end
104
+
105
+ class Configuration
106
+ attr_accessor :save_file_path
107
+ attr_accessor :market_data_filename
108
+ attr_accessor :current_system_name
109
+ attr_accessor :current_credits
110
+ attr_accessor :cargo
111
+ attr_accessor :trade_contraband
112
+ attr_accessor :contraband
113
+ attr_accessor :economies
114
+ attr_accessor :governments
115
+ attr_accessor :systems
116
+
117
+
118
+ def initialize
119
+ reset
120
+ end
121
+
122
+ def reset
123
+ @save_file_path = ''
124
+
125
+ @market_data_filename = 'oolite.market'
126
+
127
+ @current_system_name = ''
128
+ @current_credits = 0
129
+ @cargo = 0
130
+
131
+ @trade_contraband = false
132
+
133
+ @contraband = [
134
+ "Slaves",
135
+ "Narcotics",
136
+ "Firearms",
137
+ ]
138
+
139
+ @economies = [
140
+ "Rich Industrial",
141
+ "Average Industrial",
142
+ "Poor Industrial",
143
+ "Mainly Industrial",
144
+ "Mainly Agricultural",
145
+ "Rich Agricultural",
146
+ "Average Agricultural",
147
+ "Poor Agricultural"
148
+ ]
149
+
150
+ @governments = [
151
+ "Anarchy",
152
+ "Feudal",
153
+ "Multi-Government",
154
+ "Dictatorship",
155
+ "Communist",
156
+ "Confederacy",
157
+ "Democracy",
158
+ "Corporate State"
159
+ ]
160
+
161
+ @systems = Hash.new
162
+ end
163
+
164
+ ##
165
+ # Control which instance vars are emitted when dumped to YAML.
166
+ # Example - not used at this time.
167
+ #
168
+
169
+ def encode_with(coder)
170
+ vars = instance_variables.map { |x| x.to_s }
171
+ vars = vars - ["@dummy"]
172
+
173
+ vars.each do |var|
174
+ var_val = eval(var)
175
+ coder[var.gsub('@', '')] = var_val
176
+ end
177
+ end
178
+ end # Configuration
179
+ end
180
+
181
+ require 'yaml'
182
+
183
+ # Initialize the configuration
184
+ Oolite.configure
185
+
186
+ require 'oolite/csv_doc'
187
+ require 'oolite/save_file'
188
+ require 'oolite/market_file'
189
+ require 'oolite/market'
190
+ require 'oolite/trade'
191
+
@@ -0,0 +1,68 @@
1
+ ##############################################################################
2
+ # File:: csv_doc.rb
3
+ # Purpose:: CSVDoc class for emitting formatted CSV documents
4
+ #
5
+ # Author:: Jeff McAffee 05/19/2015
6
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
7
+ # Website:: http://ktechsystems.com
8
+ ##############################################################################
9
+
10
+
11
+ module Oolite
12
+ class CSVDoc
13
+ def lines
14
+ @lines ||= Array.new
15
+ end
16
+
17
+ def add line = []
18
+ new_line = Array.new
19
+
20
+ Array(line).each do |elem|
21
+ if elem.include?(',')
22
+ # Quote element if it contains a comma
23
+ new_line << "\"#{elem}\""
24
+ else
25
+ new_line << elem
26
+ end
27
+ end
28
+
29
+ lines << new_line
30
+ end
31
+
32
+ def write filepath
33
+ pad_lines
34
+ output_lines = Array.new
35
+ lines.each do |line|
36
+ output_lines << line.join(',')
37
+ end
38
+
39
+ File.open(filepath, 'w') do |f|
40
+ f.write(output_lines.join("\n"))
41
+ end
42
+ end
43
+
44
+ def pad_lines
45
+ max = 0
46
+ lines.each do |line|
47
+ len = line.count
48
+ if len > max
49
+ max = len
50
+ end
51
+ end
52
+
53
+ padded_lines = Array.new
54
+ lines.each do |line|
55
+ if line.count < max
56
+ pads = max = line.count
57
+ pads.times.each do
58
+ line << ''
59
+ end
60
+ end
61
+ padded_lines << line
62
+ end
63
+
64
+ @lines = padded_lines
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,143 @@
1
+ ##############################################################################
2
+ # File:: market.rb
3
+ # Purpose:: Write out a market data file
4
+ #
5
+ # Author:: Jeff McAffee 05/19/2015
6
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
7
+ # Website:: http://ktechsystems.com
8
+ ##############################################################################
9
+
10
+ require 'pathname'
11
+ require 'yaml'
12
+
13
+ module Oolite
14
+ class Market
15
+ def initialize
16
+ Oolite.configure do |config|
17
+ @save_file_path = Pathname(config.save_file_path)
18
+ path = @save_file_path.dirname
19
+ @market_data_path = path + (Pathname(config.market_data_filename).to_s + '.yml')
20
+ @market_data_csv = path + (Pathname(config.market_data_filename).to_s + '.csv')
21
+ end
22
+ end
23
+
24
+ def update filename = nil
25
+ filename ||= @save_file_path
26
+
27
+ savefile = SaveFile.new filename
28
+
29
+ add_credits_to_config savefile.credits
30
+ add_cargo_to_config savefile.cargo
31
+
32
+ system_name = savefile.current_system_name
33
+ add_system_to_config system_name
34
+ puts "Updating data for #{system_name} system"
35
+
36
+ data[system_name] = savefile.local_market_data
37
+
38
+ write_data_file
39
+ end
40
+
41
+ def upgrade
42
+ mf = MarketFile.new
43
+ old_data = mf.data
44
+
45
+ old_data.each do |key, d|
46
+ updated_hash = Hash.new
47
+ d.each do |item, price|
48
+ if price.class == Hash
49
+ updated_hash[item] = price
50
+ else
51
+ updated_hash[item] = { price: price, amount: 0 }
52
+ end
53
+ end
54
+
55
+ data[key] = updated_hash
56
+ end
57
+
58
+ write_data_file
59
+ end
60
+
61
+ def upgrade_price
62
+ mf = MarketFile.new
63
+ old_data = mf.data
64
+
65
+ old_data.each do |key, d|
66
+ updated_hash = Hash.new
67
+ d.each do |item, info|
68
+ updated_hash[item] = { price: (info[:price] * 10).to_i, amount: info[:amount] }
69
+ end
70
+
71
+ data[key] = updated_hash
72
+ end
73
+
74
+ write_data_file
75
+ end
76
+
77
+ def write_csv filename = nil
78
+ filename ||= @market_data_csv
79
+ csv_doc = CSVDoc.new
80
+ format_data csv_doc
81
+ csv_doc.write filename
82
+
83
+ puts "CSV file written to #{filename}"
84
+ end
85
+
86
+ private
87
+
88
+ def data
89
+ @data ||= MarketFile.new.data
90
+ end
91
+
92
+ def write_data_file
93
+ mf = MarketFile.new
94
+ mf.data = data
95
+ mf.write
96
+ end
97
+
98
+ def format_data csv_doc
99
+ line = Array.new
100
+ line << ''
101
+ line = line + data.keys
102
+ csv_doc.add line
103
+
104
+ data[data.keys.first].keys.each do |type|
105
+ line = Array(type)
106
+ data.each do |location, local_data|
107
+ line << (local_data[type][:price] / 10.0).to_s
108
+ end
109
+ csv_doc.add line
110
+ end
111
+ end
112
+
113
+ def add_system_to_config system
114
+ Oolite.configure do |config|
115
+ config.current_system_name = system
116
+
117
+ unless config.systems.key?(system)
118
+ details = { economy: nil,
119
+ government: nil,
120
+ tech_level: nil,
121
+ }
122
+ config.systems[system] = details
123
+ end
124
+ end
125
+ Oolite.save_configuration
126
+ end
127
+
128
+ def add_credits_to_config credits
129
+ Oolite.configure do |config|
130
+ config.current_credits = credits
131
+ end
132
+ Oolite.save_configuration
133
+ end
134
+
135
+ def add_cargo_to_config cargo
136
+ Oolite.configure do |config|
137
+ config.cargo = cargo
138
+ end
139
+ Oolite.save_configuration
140
+ end
141
+ end
142
+ end
143
+
@@ -0,0 +1,55 @@
1
+ ##############################################################################
2
+ # File:: market_file.rb
3
+ # Purpose:: Store market data
4
+ #
5
+ # Author:: Jeff McAffee 05/20/2015
6
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
7
+ # Website:: http://ktechsystems.com
8
+ ##############################################################################
9
+
10
+ require 'pathname'
11
+ require 'yaml'
12
+
13
+ module Oolite
14
+ class MarketFile
15
+ def initialize
16
+ Oolite.configure do |config|
17
+ @save_file_path = Pathname(config.save_file_path)
18
+ path = @save_file_path.dirname
19
+ @market_data_path = path + (Pathname(config.market_data_filename).to_s + '.yml')
20
+ end
21
+ end
22
+
23
+ def data
24
+ @data ||= self.load
25
+ end
26
+
27
+ def data= new_data
28
+ @data = new_data
29
+ end
30
+
31
+ def systems
32
+ data.keys
33
+ end
34
+
35
+ def load
36
+ if @market_data_path.nil? || @market_data_path.to_s.empty? || !@market_data_path.exist?
37
+ Hash.new
38
+ else
39
+ input = YAML.load_file(@market_data_path)
40
+ input or Hash.new
41
+ end
42
+ rescue
43
+ Hash.new
44
+ end
45
+
46
+ def write
47
+ raise "Missing filename" if @market_data_path.nil? || @market_data_path.to_s.empty?
48
+
49
+ File.open(@market_data_path, 'w') do |f|
50
+ f.write data.to_yaml
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,71 @@
1
+ ##############################################################################
2
+ # File:: save_file.rb
3
+ # Purpose:: Parse the Oolite save file
4
+ #
5
+ # Author:: Jeff McAffee 05/19/2015
6
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
7
+ # Website:: http://ktechsystems.com
8
+ ##############################################################################
9
+
10
+ require 'pathname'
11
+ require 'nokogiri'
12
+
13
+ module Oolite
14
+ class SaveFile
15
+ def initialize filename
16
+ parse filename
17
+ end
18
+
19
+ def parse filename
20
+ raise "Cannot find save file #{filename}" unless Pathname(filename).exist?
21
+
22
+ @doc = Nokogiri::XML(File.open(filename)) do |config|
23
+ config.noblanks
24
+ end
25
+ end
26
+
27
+ def current_system_name
28
+ node = get_data_node_for_key 'current_system_name'
29
+ node.text
30
+ end
31
+
32
+ def cargo
33
+ node = get_data_node_for_key 'max_cargo'
34
+ node.text.to_i
35
+ end
36
+
37
+ def credits
38
+ node = get_data_node_for_key 'credits'
39
+ node.text.to_i
40
+ end
41
+
42
+ def local_market_data
43
+ node = get_data_node_for_key 'localMarket'
44
+
45
+ mdata = {}
46
+
47
+ node.children.each do |child|
48
+ type = child.children[0].text
49
+ amount = child.children[1].text.to_i
50
+ # Price is stored as an integer and displayed as price / 10.
51
+ price = child.children[2].text.to_i
52
+ mdata[type] = { amount: amount, price: price }
53
+ end
54
+
55
+ mdata
56
+ end
57
+
58
+ private
59
+
60
+ def get_data_node_for_key key
61
+ @doc.css('dict').children.each do |node|
62
+ if node.name == 'key' && node.text == key
63
+ return node.next
64
+ end
65
+ end
66
+
67
+ raise "No data found for key #{key}"
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,213 @@
1
+ ##############################################################################
2
+ # File:: trade.rb
3
+ # Purpose:: Determine the best trades based on current location and the next
4
+ # destination
5
+ #
6
+ # Author:: Jeff McAffee 05/20/2015
7
+ # Copyright:: Copyright (c) 2015, kTech Systems LLC. All rights reserved.
8
+ # Website:: http://ktechsystems.com
9
+ ##############################################################################
10
+
11
+ require 'pathname'
12
+ require 'yaml'
13
+
14
+ module Oolite
15
+ class Trade
16
+ def display
17
+ puts "= Oolite Trader ="
18
+ puts
19
+ puts " Current Location: #{current_system_name}"
20
+ puts
21
+ puts " Available destinations:"
22
+ puts
23
+
24
+ systems = market.systems
25
+ systems.delete current_system_name
26
+ systems.each_with_index do |sys,i|
27
+ puts " #{i} - #{sys}"
28
+ end
29
+ puts
30
+ choice = ask " Choose your destination (q to abort): "
31
+
32
+ return if choice.downcase == 'q'
33
+ puts
34
+
35
+ dest_system = systems[choice.to_i]
36
+
37
+ puts " -- Suggested Trades (best to worst) for #{dest_system} --"
38
+ puts
39
+ puts " #{'Item'.ljust(14)} #{'Amt Avail'.to_s.ljust(10)} #{'PricePerUnit'.to_s.rjust(8)} #{'ProfitPerUnit'.to_s.rjust(12)}"
40
+ puts
41
+
42
+ avail_trades = all_trades(dest_system)
43
+ avail_trades.each do |trade|
44
+ puts " " + trade.to_s
45
+ end
46
+
47
+ puts
48
+
49
+ puts " -- Suggested Transactions for #{dest_system} --"
50
+ puts
51
+ puts " #{'Item'.ljust(14)} #{'Purch Amt'.to_s.ljust(10)} #{'Profit'.to_s.rjust(8)}"
52
+ puts
53
+
54
+ trans, total_profit = calc_best_trades avail_trades
55
+ trans.each do |tran|
56
+ name = tran[:item].name
57
+ revenue = tran[:item].revenue
58
+ amount = tran[:amount]
59
+ profit = revenue * amount
60
+
61
+ puts " #{name.ljust(14)} #{amount.to_s.ljust(10)} #{(profit / 10.0).to_s.rjust(8)}"
62
+ end
63
+
64
+ puts
65
+ puts "Total Profit: #{(total_profit / 10.0).to_s}"
66
+ puts
67
+
68
+ end
69
+
70
+ private
71
+
72
+ def ask msg
73
+ print "#{msg}"
74
+ val = STDIN.getc
75
+ end
76
+
77
+ def current_system_name
78
+ Oolite.configuration.current_system_name
79
+ end
80
+
81
+ def market
82
+ if @market.nil?
83
+ @market = MarketFile.new
84
+ @market.data
85
+ end
86
+ @market
87
+ end
88
+
89
+ def all_trades dest_system
90
+ calculate_all_trades dest_system
91
+ end
92
+
93
+ class TradeItem
94
+ attr_accessor :name
95
+ attr_accessor :amount
96
+ attr_accessor :cost
97
+ attr_accessor :revenue
98
+
99
+ def initialize name, amount, cost, revenue
100
+ @name = name
101
+ @amount = amount
102
+ @cost = cost
103
+ @revenue = revenue
104
+ end
105
+
106
+ def to_s
107
+ "#{name.ljust(14)} #{amount.to_s.ljust(10)} #{(cost / 10.0).to_s.rjust(8)} #{(revenue / 10.0).to_s.rjust(12)}"
108
+ end
109
+ end
110
+
111
+ def calculate_all_trades dest_system
112
+ src = market.data[current_system_name]
113
+ dest = market.data[dest_system]
114
+
115
+ # Remove contraband if configured.
116
+ if Oolite.configuration.trade_contraband == false
117
+ Oolite.configuration.contraband.each do |contr|
118
+ src.delete contr
119
+ end
120
+ end
121
+
122
+ positive_trades = Array.new
123
+
124
+ src.keys.each do |item|
125
+ sprice = src[item][:price]
126
+ amount = src[item][:amount]
127
+ dprice = dest[item][:price]
128
+
129
+ revenue = dprice - sprice
130
+ if revenue > 0.0 && amount > 0
131
+ positive_trades << TradeItem.new(item, amount, sprice, revenue)
132
+ end
133
+ end
134
+
135
+ positive_trades.sort { |a,b| b.revenue <=> a.revenue }
136
+ end
137
+
138
+ def calc_best_trades trades
139
+ avail_cargo = Oolite.configuration.cargo
140
+ credits = Oolite.configuration.current_credits
141
+
142
+ if avail_cargo <= 0
143
+ return [[], 0]
144
+ end
145
+
146
+ affordable_trades = []
147
+ trades.each do |trade|
148
+ if trade.cost <= credits
149
+ affordable_trades << trade
150
+ end
151
+ end
152
+
153
+ if affordable_trades.count <= 0
154
+ return [[], 0]
155
+ end
156
+
157
+ balance = credits
158
+ cargo = avail_cargo
159
+ suggested_trades_expensive_first = []
160
+ affordable_trades.each do |trade|
161
+ max_amt_by_price = balance / trade.cost
162
+ max_amt_by_cargo = [cargo, trade.amount].min
163
+ max_amt = [max_amt_by_price, max_amt_by_cargo].min
164
+
165
+ balance = balance - (max_amt * trade.cost)
166
+ cargo = cargo - max_amt
167
+
168
+ if max_amt > 0
169
+ transaction = { item: trade, amount: max_amt }
170
+ suggested_trades_expensive_first << transaction.dup
171
+ end
172
+ end
173
+
174
+ expensive_first_total_profit = 0
175
+ suggested_trades_expensive_first.each do |transaction|
176
+ profit = transaction[:item].revenue * transaction[:amount]
177
+ expensive_first_total_profit += profit
178
+ end
179
+
180
+ balance = credits
181
+ cargo = avail_cargo
182
+ suggested_trades_cheap_first = []
183
+ # Sort the trades in ascending order.
184
+ cheap_affordable_trades = affordable_trades.sort { |a,b| a.revenue <=> b.revenue }
185
+ cheap_affordable_trades.each do |trade|
186
+ max_amt_by_price = balance / trade.cost
187
+ max_amt_by_cargo = [cargo, trade.amount].min
188
+ max_amt = [max_amt_by_price, max_amt_by_cargo].min
189
+
190
+ balance = balance - (max_amt * trade.cost)
191
+ cargo = cargo - max_amt
192
+
193
+ if max_amt > 0
194
+ transaction = { item: trade, amount: max_amt }
195
+ suggested_trades_cheap_first << transaction.dup
196
+ end
197
+ end
198
+
199
+ cheap_first_total_profit = 0
200
+ suggested_trades_cheap_first.each do |transaction|
201
+ profit = transaction[:item].revenue * transaction[:amount]
202
+ cheap_first_total_profit += profit
203
+ end
204
+
205
+ if expensive_first_total_profit > cheap_first_total_profit
206
+ return [suggested_trades_expensive_first, expensive_first_total_profit]
207
+ else
208
+ return [suggested_trades_cheap_first, cheap_first_total_profit]
209
+ end
210
+ end
211
+ end
212
+ end
213
+
@@ -0,0 +1,3 @@
1
+ module Oolite
2
+ VERSION = "0.0.1"
3
+ end
data/oolite.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'oolite/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "oolite"
8
+ spec.version = Oolite::VERSION
9
+ spec.authors = ["Jeff McAffee"]
10
+ spec.email = ["jeff@ktechsystems.com"]
11
+ spec.summary = %q{Utility scripts for the Oolite game}
12
+ spec.description = %q{Utility scripts for tracking markets and assisting with trading in the Oolite game.}
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.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_runtime_dependency "nokogiri", "~> 1.6"
25
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oolite
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeff McAffee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ description: Utility scripts for tracking markets and assisting with trading in the
56
+ Oolite game.
57
+ email:
58
+ - jeff@ktechsystems.com
59
+ executables:
60
+ - ooconfig
61
+ - ootrader
62
+ - ooupdatemarket
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".gitignore"
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - bin/ooconfig
72
+ - bin/ootrader
73
+ - bin/ooupdatemarket
74
+ - lib/oolite.rb
75
+ - lib/oolite/csv_doc.rb
76
+ - lib/oolite/market.rb
77
+ - lib/oolite/market_file.rb
78
+ - lib/oolite/save_file.rb
79
+ - lib/oolite/trade.rb
80
+ - lib/oolite/version.rb
81
+ - oolite.gemspec
82
+ homepage: ''
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.3.0
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Utility scripts for the Oolite game
106
+ test_files: []
107
+ has_rdoc: