monotony 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 +7 -0
- data/.gitignore +9 -0
- data/.rdoc_options +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +78 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/monotony.rb +22 -0
- data/lib/monotony/.yardoc/checksums +0 -0
- data/lib/monotony/.yardoc/object_types +0 -0
- data/lib/monotony/.yardoc/objects/root.dat +0 -0
- data/lib/monotony/.yardoc/proxy_types +0 -0
- data/lib/monotony/basicproperty.rb +174 -0
- data/lib/monotony/behaviour.rb +103 -0
- data/lib/monotony/chance.rb +53 -0
- data/lib/monotony/communitychest.rb +57 -0
- data/lib/monotony/doc/_index.html +88 -0
- data/lib/monotony/doc/class_list.html +58 -0
- data/lib/monotony/doc/css/common.css +1 -0
- data/lib/monotony/doc/css/full_list.css +57 -0
- data/lib/monotony/doc/css/style.css +339 -0
- data/lib/monotony/doc/file_list.html +57 -0
- data/lib/monotony/doc/frames.html +26 -0
- data/lib/monotony/doc/index.html +88 -0
- data/lib/monotony/doc/js/app.js +219 -0
- data/lib/monotony/doc/js/full_list.js +181 -0
- data/lib/monotony/doc/js/jquery.js +4 -0
- data/lib/monotony/doc/method_list.html +57 -0
- data/lib/monotony/doc/top-level-namespace.html +102 -0
- data/lib/monotony/game.rb +307 -0
- data/lib/monotony/player.rb +191 -0
- data/lib/monotony/purchasable.rb +131 -0
- data/lib/monotony/square.rb +23 -0
- data/lib/monotony/station.rb +24 -0
- data/lib/monotony/utility.rb +23 -0
- data/lib/monotony/variants.rb +405 -0
- data/lib/monotony/version.rb +4 -0
- data/monotony.gemspec +33 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 794754b6881e940805c2ece03fb4a204ef8f40bf
|
4
|
+
data.tar.gz: 2e5a91ef47ee68cbc1c920ad8af18949881a2d63
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0dbbdc07c2e4007d6335b3edaa17f2fd5634599b5fb4dfe865066e312ef43d84f271934f0d03d075715092e2c34b5f84c66935c12751db60ea869faab52f9fe0
|
7
|
+
data.tar.gz: f68ae2180ee5880fa4d90479e164498d96fcd99d2b166db16aa4e02fe73c973f8e55c3aaf6f3fb591cbddc70784b9ebf3f3a3e899f03f068c1e9fa2c6a2f6dc9
|
data/.gitignore
ADDED
data/.rdoc_options
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
--- !ruby/object:RDoc::Options
|
2
|
+
encoding: UTF-8
|
3
|
+
static_path: []
|
4
|
+
rdoc_include:
|
5
|
+
- .
|
6
|
+
charset: UTF-8
|
7
|
+
exclude:
|
8
|
+
hyperlink_all: false
|
9
|
+
line_numbers: false
|
10
|
+
main_page:
|
11
|
+
markup: markdown
|
12
|
+
page_dir:
|
13
|
+
show_hash: false
|
14
|
+
tab_width: 8
|
15
|
+
title:
|
16
|
+
visibility: :protected
|
17
|
+
webcvs:
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 James Denness
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Monotony
|
2
|
+
|
3
|
+
This gem is an engine to simulate games of Monopoly.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'monotony'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install monotony
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
To play a quick game of Monopoly, with classic board layout and four randomly generated players"
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
|
27
|
+
game = Monotony::Game.new
|
28
|
+
game.play
|
29
|
+
|
30
|
+
# See the results of the game
|
31
|
+
game.summary
|
32
|
+
|
33
|
+
```
|
34
|
+
|
35
|
+
You can step through the game a few turns at a time, and use the ```summary``` method to view an ASCII representation of the state of the game.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
game.play(10).summary
|
39
|
+
```
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
monopoly_players = [
|
43
|
+
Player.new( name: 'James', behaviour: behaviour ),
|
44
|
+
Player.new( name: 'Jody', behaviour: behaviour ),
|
45
|
+
Player.new( name: 'Ryan', behaviour: behaviour ),
|
46
|
+
Player.new( name: 'Tine', behaviour: behaviour )
|
47
|
+
]
|
48
|
+
|
49
|
+
monopoly = Monotony::Game.new(
|
50
|
+
board: monopoly_board,
|
51
|
+
chance: chance,
|
52
|
+
community_chest: community_chest,
|
53
|
+
num_dice: 2,
|
54
|
+
die_size: 6,
|
55
|
+
starting_currency: 1500,
|
56
|
+
bank_balance: 12755,
|
57
|
+
num_hotels: 12,
|
58
|
+
num_houses: 48,
|
59
|
+
go_amount: 200,
|
60
|
+
max_turns_in_jail: 3,
|
61
|
+
players: monopoly_players
|
62
|
+
)```
|
63
|
+
|
64
|
+
## Development
|
65
|
+
|
66
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
67
|
+
|
68
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/monotony.
|
73
|
+
|
74
|
+
|
75
|
+
## License
|
76
|
+
|
77
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
78
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "monotony"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/monotony.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'colorize'
|
5
|
+
|
6
|
+
require 'monotony/basicproperty'
|
7
|
+
require 'monotony/chance'
|
8
|
+
require 'monotony/communitychest'
|
9
|
+
require 'monotony/game'
|
10
|
+
require 'monotony/player'
|
11
|
+
require 'monotony/purchasable'
|
12
|
+
require 'monotony/square'
|
13
|
+
require 'monotony/station'
|
14
|
+
require 'monotony/utility'
|
15
|
+
require 'monotony/variants'
|
16
|
+
require 'monotony/behaviour'
|
17
|
+
|
18
|
+
# The Monopoly Engine!
|
19
|
+
# @author James Denness <james@recordlive.net>
|
20
|
+
module Monotony
|
21
|
+
|
22
|
+
end
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'monotony/square'
|
2
|
+
require 'monotony/purchasable'
|
3
|
+
|
4
|
+
module Monotony
|
5
|
+
# A property class representing the majority of properties on the board.
|
6
|
+
class BasicProperty < PurchasableProperty
|
7
|
+
# @return [Integer] Returns the cost of purchasing a house on this property.
|
8
|
+
attr_accessor :house_cost
|
9
|
+
# @return [Integer] Returns the cost of purchasing a hotel on this property.
|
10
|
+
attr_accessor :hotel_cost
|
11
|
+
# @return [Symbol] Returns the name of the set containing this property.
|
12
|
+
attr_accessor :set
|
13
|
+
# @return [Integer] Returns the number of houses on this property.
|
14
|
+
attr_accessor :num_houses
|
15
|
+
# @return [Integer] Returns the number of hotels on this property.
|
16
|
+
attr_accessor :num_hotels
|
17
|
+
# @return [Array<Integer>] Returns an array of six elements containing rent values for an property with no houses, one house, two houses, three houses, four houses, and a hotel.
|
18
|
+
attr_accessor :rent
|
19
|
+
# @param opts [Hash]
|
20
|
+
# @option opts [Array<Integer>] :rent An array of six elements containing rent values for an property with no houses, one house, two houses, three houses, four houses, and a hotel.
|
21
|
+
# @option opts [Integer] :house_cost The cost of purchasing a house on this property.
|
22
|
+
# @option opts [Integer] :hotel_cost The cost of purchasing a hotel on this property. Traditionally equal to house_cost.
|
23
|
+
# @option opts [Symbol] :set A symbol identifying this property as a member of a set of properties.
|
24
|
+
def initialize(opts)
|
25
|
+
super
|
26
|
+
@rent = opts[:rent]
|
27
|
+
@house_cost = opts[:house_cost]
|
28
|
+
@hotel_cost = opts[:hotel_cost]
|
29
|
+
@set = opts[:set]
|
30
|
+
@num_houses = 0
|
31
|
+
@num_hotels = 0
|
32
|
+
@action = Proc.new do |game, owner, player, property|
|
33
|
+
if owner
|
34
|
+
if set_owned?
|
35
|
+
rent_to_pay = (property.num_hotels == 1 ? property.rent[5] : ( property.num_houses == 0 ? (@rent[0] * 2) : property.rent[property.num_houses] ) )
|
36
|
+
else
|
37
|
+
rent_to_pay = property.rent[0]
|
38
|
+
end
|
39
|
+
if owner != player
|
40
|
+
if not owner.is_out? and not is_mortgaged?
|
41
|
+
puts '[%s] Due to pay £%d rent to %s for landing on %s with %s' % [ player.name, rent_to_pay, owner.name, property.name, ( property.num_hotels == 1 ? 'a hotel' : '%d houses' % property.num_houses) ]
|
42
|
+
player.pay(owner, rent_to_pay)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
player.behaviour[:purchase_possible].call(game, player, self) if player.currency >= cost
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Mortgage the property to raise cash for its owner.
|
52
|
+
# @return [self]
|
53
|
+
def mortgage
|
54
|
+
super
|
55
|
+
properties_in_set(@owner.game).each do |other|
|
56
|
+
other.sell_hotel if @num_hotels > 0
|
57
|
+
other.sell_houses if @num_houses > 0
|
58
|
+
end
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
# Buy houses on the property.
|
63
|
+
# @param [Integer] number number of houses to add to the property.
|
64
|
+
# @return [self]
|
65
|
+
def add_houses(number)
|
66
|
+
housing_value = @house_cost * number
|
67
|
+
if @owner.game.num_houses >= number
|
68
|
+
if (@num_houses + number) > 4
|
69
|
+
puts '[%s] Cannot place more than 4 houses on %s' % [ @owner.name, @name ]
|
70
|
+
else
|
71
|
+
if @owner.currency < housing_value
|
72
|
+
puts '[%s] Unable to buy %d houses! (short of cash by £%d)' % [ @owner.name, number, (housing_value - @owner.currency) ]
|
73
|
+
false
|
74
|
+
else
|
75
|
+
@owner.currency = @owner.currency - housing_value
|
76
|
+
@owner.game.num_houses = @owner.game.num_houses - number
|
77
|
+
@num_houses = @num_houses + number
|
78
|
+
puts '[%s] Purchased %d houses on %s for £%d (new balance: £%d)' % [ @owner.name, number, @name, housing_value, @owner.currency ]
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
else
|
83
|
+
puts '[%s] Not enough houses left to purchase %d more for %s' % [ @owner.name, number, @name ]
|
84
|
+
end
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sell houses from the property.
|
89
|
+
# @param [Integer] number number of houses to sell from the property.
|
90
|
+
# @return [self]
|
91
|
+
def sell_houses(number)
|
92
|
+
housing_value = (@house_cost / 2) * number
|
93
|
+
if number > @num_houses
|
94
|
+
puts "[%s] Can't sell %d houses on %s, as there are only %d" % [ @owner.name, number, @name, @num_houses ]
|
95
|
+
false
|
96
|
+
else
|
97
|
+
@num_houses = @num_houses - number
|
98
|
+
@owner.game.num_houses = @owner.game.num_houses + number
|
99
|
+
@owner.currency = @owner.currency + housing_value
|
100
|
+
puts '[%s] Sold %d houses on %s for £%d (%d remaining)' % [ @owner.name, number, @name, housing_value, @num_houses ]
|
101
|
+
end
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# Buy a hotel on the property.
|
106
|
+
# @return [self]
|
107
|
+
def add_hotel
|
108
|
+
if @num_houses == 4
|
109
|
+
if @owner.game.num_houses > 0
|
110
|
+
if @owner.currency < @hotel_cost
|
111
|
+
puts '[%s] Unable to buy a hotel! (short of cash by £%d)' % [ @owner.name, (@hotel_cost - @owner.currency) ]
|
112
|
+
else
|
113
|
+
@owner.currency = @owner.currency - @hotel_cost
|
114
|
+
@num_houses, @num_hotels = 0, 1
|
115
|
+
@owner.game.num_houses = @owner.game.num_houses + 4
|
116
|
+
@owner.game.num_hotels = @owner.game.num_hotels - 1
|
117
|
+
puts '[%s] Purchased a hotel on %s for £%d (new balance: £%d)' % [ @owner.name, @name, @hotel_cost, @owner.currency ]
|
118
|
+
end
|
119
|
+
else
|
120
|
+
puts '[%s] Not enough hotels left to purchase one for %s' % [ @owner.name, @name ]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
# Sell hotels from the property.
|
127
|
+
# @return [self]
|
128
|
+
def sell_hotel
|
129
|
+
if @num_hotels < 1
|
130
|
+
puts "[%s] Can't sell hotel on %s, as there isn't one!" % [ @owner.name, @name ]
|
131
|
+
else
|
132
|
+
housing_value = (@hotel_cost / 2)
|
133
|
+
@num_hotels = 0
|
134
|
+
@owner.game.num_hotels = @owner.game.num_hotels + 1
|
135
|
+
@owner.currency = @owner.currency + housing_value
|
136
|
+
puts '[%s] Sold hotel on %s for £%d' % [ @owner.name, @name, housing_value ]
|
137
|
+
case @owner.game.num_houses
|
138
|
+
when 1..3
|
139
|
+
sell_houses(4 - @owner.game.num_houses)
|
140
|
+
puts '[%s] Devolved %s to %d houses as 4 were not available' % [ @owner.name, @name, @num_houses ]
|
141
|
+
when 0
|
142
|
+
sell_houses(4)
|
143
|
+
puts '[%s] Devolved to undeveloped site as no houses were available' % [ @owner.name, @name, @num_houses ]
|
144
|
+
else
|
145
|
+
@owner.game.num_houses = @owner.game.num_houses - 4
|
146
|
+
@num_houses = 4
|
147
|
+
puts '[%s] Devolved %s to %d houses' % [ @owner.name, @name, @num_houses ]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
# Draw an ASCII representation of this property's housing.
|
154
|
+
# @return [void]
|
155
|
+
def display_house_ascii
|
156
|
+
house_array = []
|
157
|
+
house_string = ''
|
158
|
+
|
159
|
+
if @num_hotels == 1
|
160
|
+
house_string << ' '.colorize(:background => :light_black) + ' '.colorize(:background => :red) + ' '.colorize(:background => :light_black)
|
161
|
+
else
|
162
|
+
until house_array.length == @num_houses
|
163
|
+
house_array << ' '.colorize(:background => :green)
|
164
|
+
end
|
165
|
+
until house_array.length == 4
|
166
|
+
house_array << ' '.colorize(:background => :light_black)
|
167
|
+
end
|
168
|
+
|
169
|
+
house_string = house_array.join(' '.colorize(:background => :light_black))
|
170
|
+
end
|
171
|
+
house_string + ' '.colorize(:color => :default)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Monotony
|
2
|
+
# Conains predefined behaviours
|
3
|
+
class DefaultBehaviour
|
4
|
+
DEFAULT = {
|
5
|
+
purchase_possible: Proc.new { |game, player, property|
|
6
|
+
if player.properties.collect{ |p| p.set }.include? property.set
|
7
|
+
# Will definitely buy if player already owns one or more of this set
|
8
|
+
property.sell_to(player)
|
9
|
+
elsif game.players.collect { |p| p.properties.collect { |p| p.set } }.flatten.include? property.set
|
10
|
+
# Less likely to buy if another player already owns one of the set
|
11
|
+
property.sell_to(player) if Random.rand(0..100) >= 75
|
12
|
+
else
|
13
|
+
# Will probably buy if nobody has bought any of this set yet
|
14
|
+
property.sell_to(player) if Random.rand(0..100) >= 25
|
15
|
+
end
|
16
|
+
},
|
17
|
+
unmortgage_possible: Proc.new { |game, player, property|
|
18
|
+
# Only bother unmortgaging something if I have the rest of the set, or it's less than 15% of my cash
|
19
|
+
if player.sets_owned.include? property.set
|
20
|
+
property.unmortgage
|
21
|
+
elsif ( property.cost.to_f / player.currency.to_f * 100.0 ) < 15.0
|
22
|
+
property.unmortgage
|
23
|
+
end
|
24
|
+
},
|
25
|
+
houses_available: Proc.new {|game, player, property|
|
26
|
+
# Buy houses when possible, but don't spend more than 40% of my money on them in any one turn
|
27
|
+
can_afford = ( ( player.currency * 0.4 ) / property.house_cost ).floor
|
28
|
+
max_available = 4 - property.num_houses
|
29
|
+
to_buy = [ can_afford, max_available ].min
|
30
|
+
property.add_houses(to_buy) if to_buy > 0 unless game.active_players == 1
|
31
|
+
},
|
32
|
+
hotel_available: Proc.new {|game, player, property|
|
33
|
+
# Buy a hotel, unless it's more than half my current balance.
|
34
|
+
property.add_hotel unless ( property.hotel_cost.to_f / player.currency.to_f * 100.0) > 50.0
|
35
|
+
},
|
36
|
+
money_trouble: Proc.new {|game, player, amount|
|
37
|
+
portfolio = player.properties.sort_by { |p| p.mortgage_value }
|
38
|
+
while player.currency < amount do
|
39
|
+
if portfolio.length > 0
|
40
|
+
property = portfolio.shift
|
41
|
+
if property.is_a? BasicProperty
|
42
|
+
if property.num_hotels == 1
|
43
|
+
property = property.sell_hotel
|
44
|
+
end
|
45
|
+
break if player.currency >= amount
|
46
|
+
|
47
|
+
while property.num_houses > 0
|
48
|
+
property = property.sell_houses(1)
|
49
|
+
break if player.currency >= amount
|
50
|
+
end
|
51
|
+
break if player.currency >= amount
|
52
|
+
|
53
|
+
property = property.mortgage
|
54
|
+
end
|
55
|
+
else
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
},
|
60
|
+
use_jail_card: Proc.new {|game, player|
|
61
|
+
# Unless less than 50% of active sets are mine, get out of jail with a card when possible
|
62
|
+
player.use_jail_card! unless ( player.sets_owned.count.to_f / game.all_sets_owned.count.to_f * 100.0 ) < 50
|
63
|
+
},
|
64
|
+
trade_possible: Proc.new {|game, player|
|
65
|
+
puts '[%s] Considering possible trades' % player.name
|
66
|
+
invested_colours = player.properties.collect(&:set).uniq
|
67
|
+
player.opponents.each do |opponent|
|
68
|
+
opponent.properties.select { |r| invested_colours.include? r.set }.each do |desirable_property|
|
69
|
+
factors = {}
|
70
|
+
# e.g. 66% chance of buying if one property is owned, 99% chance of buying if two are
|
71
|
+
factors[:number_owned] = ( desirable_property.number_of_set_owned.to_f + 1.0 ) / desirable_property.number_in_set(game).to_f
|
72
|
+
# More likely to trade if player has over £1000
|
73
|
+
factors[:currency] = player.currency.to_f / 1000.to_f
|
74
|
+
# More likely to trade if close to GO
|
75
|
+
factors[:proximity_to_go] = 1 - ( player.distance_to_go.to_f / game.board.length.to_f )
|
76
|
+
|
77
|
+
# We use these factors to work out how much to offer relative to how much we have
|
78
|
+
offer_amount = player.currency * factors.values.inject(&:*)
|
79
|
+
if offer_amount > desirable_property.cost and player.currency >= offer_amount
|
80
|
+
puts '[%s] Placing offer of £%d on %s (owned by %s) [%f]' % [ player.name, offer_amount, desirable_property.name, desirable_property.owner.name, factors.values.inject(&:*) * 100 ]
|
81
|
+
|
82
|
+
desirable_property.place_offer(player, offer_amount)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
},
|
87
|
+
trade_proposed: Proc.new {|game, player, proposer, property, amount|
|
88
|
+
factors = {}
|
89
|
+
# More likely to accept a trade the longer the game has been going on for (definitely at 100 turns)
|
90
|
+
factors[:longevity] = ( [0, game.turn, 100].sort[1].to_f / 100.0 ).to_f
|
91
|
+
# More likely to accept a trade if it is far over the list price
|
92
|
+
factors[:value_added] = 1 - ( property.cost.to_f / amount.to_f )
|
93
|
+
# More likely to accept a trade if low on cash
|
94
|
+
factors[:currency] = 1 - ( player.currency.to_f / 1000.to_f )
|
95
|
+
|
96
|
+
# Random element
|
97
|
+
factors[:random] = Random.rand(1..100)
|
98
|
+
puts '[%s] Considering offer of £%d for %s (from %s) [%f]' % [ player.name, amount, property.name, proposer.name, ( factors.values.collect{ |f| ( 100 / factors.count ) * f }.inject(:+) / 100 ) ]
|
99
|
+
property.sell_to(proposer, amount) if Random.rand(1..100) > ( factors.values.collect{ |f| ( 100 / factors.count ) * f }.inject(:+) / 100 )
|
100
|
+
}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|