Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
.DS_Store | ||
*~ | ||
*# | ||
*.o | ||
*.so | ||
*.swp | ||
*.old | ||
*.bak | ||
*.kate-swp | ||
*.dylib | ||
*.dSYM | ||
*.dll | ||
*.rlib | ||
*.dummy | ||
*.exe | ||
*-test | ||
/bin/main | ||
/bin/test-internal | ||
/bin/test-external | ||
/doc/ | ||
/target/ | ||
/build/ | ||
/.rust/ | ||
rusti.sh | ||
watch.sh | ||
/examples/** | ||
!/examples/*.rs | ||
!/examples/assets/ | ||
!/bin/assets/ | ||
|
||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "piston_mix_economy" | ||
version = "0.1.0" | ||
authors = ["bvssvni <bvssvni@gmail.com>"] | ||
description = "A research project to mix-regulate economy in MMO worlds" | ||
|
||
[dev-dependencies] | ||
piston_window = "0.32.0" | ||
rand = "0.3.11" | ||
piston-timer_controller = "0.1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,51 @@ | ||
# mix_economy | ||
A research project to mix-regulate economy in MMO worlds | ||
|
||
[Why mix_economy?](https://github.com/PistonDevelopers/mix_economy/issues/1) | ||
|
||
A [virtual economy](https://en.wikipedia.org/wiki/Virtual_economy) | ||
is an emergent economy existing in a virtual persistent world, | ||
usually exchanging virtual goods in the context of an Internet game. | ||
|
||
One challenge is to balance gameplay to be fun for both causual and | ||
experienced players, which most small to medium MMO games do not have | ||
substantial resources to do. | ||
|
||
This research project studies a simple model that can be mixed with | ||
an existing economy model: | ||
|
||
1. A normalized thresold sets a soft limit of the wealth of a player. | ||
2. Money "burns in the pockets" of rich players, encouraging spending. | ||
3. Controlled inflation charged by "total lack of money". | ||
4. Rewards weighted as negative tax on fortune (more money = more rewards). | ||
|
||
At start of joining the game, each player gets a start fortune. | ||
Each player receive money rewards through regular time interval. | ||
|
||
The rewards increases with the amount of money, meaning that saving or | ||
earning money is beneficial to the player. | ||
|
||
Rewards are charged through the lack of money in circulation, | ||
by summing the difference from the soft limit of wealth. | ||
This means inviting new players to join is beneficial for all players. | ||
|
||
### Text example 1 | ||
|
||
A game has an infinite resource reserve that requires a minimum amount | ||
of time to mine. By buying an expensive equipment, the resource can be | ||
mined faster. A player owning the expensive equipment can sell the resource | ||
to players that do not own it, for a cheaper price than these player | ||
earn during the same amount of time. This means a huge cash flow from | ||
many players to a few players, which they then invest in other equipment | ||
or spend on other goods or services to keep the value of that cash flow | ||
from disappearing. | ||
|
||
### Text example 2 | ||
|
||
A player want to take on a mission that takes a long time. | ||
The reward for this mission could be an expensive equipment. | ||
By living off the saved fortune and regular rewards, the player can | ||
take on the mission without without worrying about running out of money. | ||
Other players take risks as well to get economic benefits in the long term. | ||
The game could allow items to be "programmed" to allow a greater flexibility. | ||
This will lead the players to find creative ways to make money. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
//! Shows distribution curve under random transactions. | ||
|
||
extern crate piston_mix_economy; | ||
extern crate piston_window; | ||
extern crate rand; | ||
extern crate timer_controller; | ||
|
||
use rand::Rng; | ||
use piston_window::*; | ||
use piston_mix_economy::Economy; | ||
use timer_controller::Timer; | ||
|
||
fn main() { | ||
let window: PistonWindow = | ||
WindowSettings::new("Random transactions", [1024, 768]) | ||
.exit_on_esc(true) | ||
.build() | ||
.unwrap(); | ||
|
||
let tax = 0.01; | ||
let start_fortune = 0.2; | ||
let players = 1000; | ||
let diff = 5.0; | ||
let mut economy = Economy::new(tax, start_fortune, players); | ||
let mut economy2 = Economy::new(tax * diff, start_fortune, players); | ||
let update_interval = 0.1; | ||
let mut timer = Timer::new(update_interval); | ||
|
||
let avg_transaction = tax; | ||
let transactions = 1000; | ||
|
||
let mut rng = rand::thread_rng(); | ||
|
||
for e in window { | ||
e.draw_2d(|c, g| { | ||
clear([1.0, 1.0, 1.0, 1.0], g); | ||
draw_economy(&economy, &c, g); | ||
let d = c.trans(0.0, 200.0); | ||
draw_economy(&economy2, &d, g); | ||
}); | ||
timer.event(&e, || { | ||
// Make random transactions. | ||
for _ in 0..transactions { | ||
let len = economy.players.len(); | ||
let from = rng.gen_range(0, len); | ||
let to = rng.gen_range(0, len); | ||
let _ = economy.transaction(from, to, avg_transaction); | ||
let _ = economy2.transaction(from, to, avg_transaction); | ||
} | ||
|
||
economy.update(); | ||
economy.players.sort_by(|a, b| a.partial_cmp(b).unwrap()); | ||
economy2.update(); | ||
economy2.players.sort_by(|a, b| a.partial_cmp(b).unwrap()); | ||
}); | ||
} | ||
} | ||
|
||
fn draw_economy<G: Graphics>(economy: &Economy, c: &Context, g: &mut G) { | ||
let color = [1.0, 0.0, 0.0, 1.0]; | ||
let w: f64 = 1.0; | ||
for (i, p) in economy.players.iter().enumerate() { | ||
let rect = [i as f64 * w, 0.0, w, *p * 100.0]; | ||
rectangle(color, rect, c.transform, g); | ||
} | ||
rectangle([0.0, 1.0, 0.0, 1.0], [0.0, economy.start_fortune * 100.0 - 2.0, 1000.0, 2.0], | ||
c.transform, g); | ||
rectangle([0.0, 0.0, 1.0, 1.0], [0.0, 98.0, 1000.0, 2.0], | ||
c.transform, g); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#![deny(missing_docs)] | ||
|
||
//! A research project to mix-regulate economy in MMO worlds. | ||
//! | ||
//! A [virtual economy](https://en.wikipedia.org/wiki/Virtual_economy) | ||
//! is an emergent economy existing in a virtual persistent world, | ||
//! usually exchanging virtual goods in the context of an Internet game. | ||
//! | ||
//! One challenge is to balance gameplay to be fun for both causual and | ||
//! experienced players, which most small to medium MMO games do not have | ||
//! substantial resources to do. | ||
//! | ||
//! This research project studies a simple model that can be mixed with | ||
//! an existing economy model: | ||
//! | ||
//! 1. A normalized thresold sets a soft limit of the wealth of a player. | ||
//! 2. Money "burns in the pockets" of rich players, encouraging spending. | ||
//! 3. Controlled inflation charged by "total lack of money". | ||
//! 4. Rewards weighted as negative tax on fortune (more money = more rewards). | ||
//! | ||
//! At start of joining the game, each player gets a start fortune. | ||
//! Each player receive money rewards through regular time interval. | ||
//! | ||
//! The rewards increases with the amount of money, meaning that saving or | ||
//! earning money is beneficial to the player. | ||
//! | ||
//! Rewards are charged through the lack of money in circulation, | ||
//! by summing the difference from the soft limit of wealth. | ||
//! This means inviting new players to join is beneficial for all players. | ||
//! | ||
//! ### Text example 1 | ||
//! | ||
//! A game has an infinite resource reserve that requires a minimum amount | ||
//! of time to mine. By buying an expensive equipment, the resource can be | ||
//! mined faster. A player owning the expensive equipment can sell the resource | ||
//! to players that do not own it, for a cheaper price than these player | ||
//! earn during the same amount of time. This means a huge cash flow from | ||
//! many players to a few players, which they then invest in other equipment | ||
//! or spend on other goods or services to keep the value of that cash flow | ||
//! from disappearing. | ||
//! | ||
//! ### Text example 2 | ||
//! | ||
//! A player want to take on a mission that takes a long time. | ||
//! The reward for this mission could be an expensive equipment. | ||
//! By living off the saved fortune and regular rewards, the player can | ||
//! take on the mission without without worrying about running out of money. | ||
//! Other players take risks as well to get economic benefits in the long term. | ||
//! The game could allow items to be "programmed" to allow a greater flexibility. | ||
//! This will lead the players to find creative ways to make money. | ||
|
||
/// Represents the whole economy. | ||
pub struct Economy { | ||
/// The fortunes of the players. | ||
pub players: Vec<f64>, | ||
/// The progressive tax factor, as the square root of fortune above 1. | ||
pub tax: f64, | ||
/// The initial fortune. | ||
pub start_fortune: f64, | ||
} | ||
|
||
impl Economy { | ||
/// Creates a new economy. | ||
pub fn new(tax: f64, start_fortune: f64, players: usize) -> Economy { | ||
Economy { | ||
players: vec![start_fortune; players], | ||
tax: tax, | ||
start_fortune: start_fortune, | ||
} | ||
} | ||
|
||
/// Adds a player to the economy. | ||
pub fn add_player(&mut self) -> usize { | ||
self.players.push(self.start_fortune); | ||
self.players.len() - 1 | ||
} | ||
|
||
/// Finds the minimum and maximum fortune. | ||
pub fn min_max(&self) -> (f64, f64) { | ||
let mut min: Option<f64> = None; | ||
let mut max: Option<f64> = None; | ||
for &p in &self.players { | ||
min = Some(min.map(|v| if v < p { v } else { p }).unwrap_or(p)); | ||
max = Some(max.map(|v| if v > p { v } else { p }).unwrap_or(p)); | ||
} | ||
(min.unwrap_or(0.0), max.unwrap_or(0.0)) | ||
} | ||
|
||
/// Does a transaction between two people. | ||
pub fn transaction(&mut self, from: usize, to: usize, amount: f64) | ||
-> Result<(), ()> { | ||
let new_fortune = self.players[from] - amount; | ||
if new_fortune > 0.0 { | ||
self.players[to] = self.players[to] + amount; | ||
self.players[from] = new_fortune; | ||
Ok(()) | ||
} else { | ||
Err(()) | ||
} | ||
} | ||
|
||
/// Updates the economy. | ||
pub fn update(&mut self) { | ||
// Remove wealth from rich players. | ||
for p in &mut self.players { | ||
if *p >= 1.0 { | ||
let amount = (*p - 1.0).sqrt() * self.tax; | ||
*p = *p - amount; | ||
} | ||
} | ||
|
||
// Compute weights and how much to distribute. | ||
let mut sum_weights = 0.0; | ||
let mut distribute = 0.0; | ||
for p in &self.players { | ||
if *p < 1.0 { | ||
distribute = distribute + 1.0 - *p; | ||
if *p < self.start_fortune { | ||
sum_weights = sum_weights + self.start_fortune.sqrt(); | ||
} else { | ||
sum_weights = sum_weights + p.sqrt(); | ||
} | ||
} | ||
} | ||
|
||
// Distribute the wealth among poor players. | ||
for p in &mut self.players { | ||
if *p < 1.0 { | ||
if *p < self.start_fortune { | ||
*p = *p + self.start_fortune.sqrt() / sum_weights * | ||
distribute * self.tax; | ||
} else { | ||
*p = *p + p.sqrt() / sum_weights * distribute * self.tax; | ||
} | ||
} | ||
} | ||
} | ||
} |