diff --git a/src/main.rs b/src/main.rs index 6111ec6..8a28e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,12 +46,9 @@ use std::io::{self, BufRead, Write}; use std::env; //use std::collections::HashMap; use std::cmp::Ordering; -use std::rc::Rc; -use std::cell::RefCell; use rand::prelude::*; use rand::rngs::StdRng; use hashbrown::HashMap; -use std::collections::HashSet; mod finum; use finum::FiNum; @@ -61,7 +58,7 @@ struct Trader { password: String, // hash(name..salt..password) id: usize, balances: HashMap, // Maps Currency to Amount - orders: HashSet, + order_finder: HashMap, } #[derive(Clone)] @@ -92,7 +89,7 @@ impl Trader { password: String::from(""), id: id, balances: HashMap::new(), - orders: HashSet::new(), + order_finder: HashMap::new(), } } fn add_balance(&mut self, cur:usize, delta:FiNum) { @@ -114,30 +111,32 @@ struct Order { royalty_remain: FiNum, // Based on royalty1 commission_remain: FiNum, // Based on commission1 owner: usize, - id: usize, + order_id: usize, } struct RoyaltyTree { tree: Vec, next_entry: usize, spare_change: FiNum, // Waiting to be distributed + order_finder: HashMap, } struct Royalty { weight: FiNum, // Here and below lazy: FiNum, // To be distributed to here and to below based on weights acc: FiNum, // Accumulated here + order_id: usize, } impl Royalty { fn new() -> Self { - Royalty { weight:FiNum::zero(), lazy:FiNum::zero(), acc:FiNum::zero() } + Royalty { weight:FiNum::zero(), lazy:FiNum::zero(), acc:FiNum::zero(), order_id:0, } } } impl RoyaltyTree { fn new() -> Self { - RoyaltyTree { tree:Vec::new(), next_entry:0, spare_change:FiNum::zero() } + RoyaltyTree { tree:Vec::new(), next_entry:0, spare_change:FiNum::zero(), order_finder:HashMap::new() } } fn acc_total(&self) -> FiNum { let mut rval=FiNum::zero(); @@ -206,6 +205,12 @@ impl RoyaltyTree { if self.weight_here_below(ff).is_zero() { self.spare_change+=amount } else { self.tree[ff].lazy+=amount }; } } + fn remove_order_id(&mut self, id: usize) { + self.order_finder.remove(&id); + } + fn set_location(&mut self, id: usize, index: usize) { + self.order_finder.insert(id,index); + } fn add_weight(&mut self, index: usize, weight: FiNum) { if self.tree.len()>0 { let mut ff0=self.forefather(); @@ -250,24 +255,12 @@ impl Dumpable for usize { } -impl Dumpable for Rc> { - fn dump(&self) { - } - } - - impl Dumpable for Order { fn dump(&self) { println!("Giving {}/{} to get {}",self.sell_remain,self.sell_qty,self.buy_qty); } } -struct OrderFinder { - asset0: usize, - asset1: usize, - pq_loc: usize, - rt_loc: usize, - } struct Market { asset_name2num: HashMap, @@ -278,7 +271,7 @@ struct Market { orders: HashMap<(usize,usize),OrderQueue>, royalties: HashMap, // Active orders that are accepting asset X. They receive royalties when someone makes an order to sell X royalty_rate: HashMap, - order_finder: HashMap, // To find an order, look in Orders.get(usize,usize) at position usize + order_finder: HashMap, // To find an order, look in Orders.get(usize,usize) at position usize next_order_id: usize, } @@ -369,8 +362,8 @@ impl Market { off.sell_remain, // off.buy_qty*off.sell_remain/off.sell_qty, (off.buy_qty/off.sell_qty).fmt_recip(), self.traders[off.owner as usize].name, - off.id, - self.royalties.get_mut(&ap.1).unwrap().get_royalty(off.rt_loc)); + off.order_id, + "GetRoyalties Code absent"); } } println!("Royalties accumulated but not captured:"); @@ -475,43 +468,53 @@ impl Market { top_order.royalty_remain-=rq2; top_order.commission_remain-=cq2; self.traders[0].add_balance(buy_type,cq2); - self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(rq2); if elt.sell_remain==0.into() { // deal with pennies stored in royalty_remain and commission_remain self.traders[0].add_balance(buy_type,top_order.commission_remain); self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(top_order.royalty_remain); - self.orders.get_mut(&ap).unwrap().pop(); + self.royalties.get_mut(&sell_type).unwrap().remove_order_id(top_order.order_id); + self.order_finder.remove(&top_order.order_id); + self.traders[top_order.owner].order_finder.remove(&top_order.order_id); + self.orders.get_mut(&ap).unwrap().pop(); // This removes id (which is stored as part of the Order) from self.order's finder } else { top_order.sell_remain-=qty; } } else { break; } } + let mut id=0; if buy_qty>0.into() { let ap=(sell_type,buy_type); if let None=self.orders.get_mut(&ap) { self.orders.insert(ap,OrderQueue::new()); } let bids=self.orders.get_mut(&ap).unwrap(); let sell_qty_remain=sell_qty*buy_qty/buy_qty_initial; - if sell_qty_remain>0.into() { - self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(royalty0_qty); - let rt=self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()); - let rt_loc=rt.next_entry; - rt.add_weight(rt_loc,buy_qty); // Weight should really be the quantity you would be able to immediately transact rather than how much you wish for. - let neworder=Order { owner:owner, sell_qty:sell_qty_remain, sell_remain:sell_qty_remain, buy_qty:buy_qty, royalty_remain:royalty1_qty, commission_remain:commission1_qty, id:self.next_order_id }; - new_order_id=self.next_order_id; + if sell_qty_remain>0.into() { // This block can not fail + // Allocate the id for this new order + id=self.next_order_id; self.next_order_id+=1; + + // Pay royalties to existing orders on the sell size + self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(royalty0_qty); + + // Create a new entry in the RoyaltyTree to accumulate for this Order + let rt=self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()); + rt.add_weight(rt.next_entry,buy_qty); // Weight should really be the quantity you would be able to immediately transact rather than how much you wish for. + rt.set_location(id,rt.next_entry); rt.next_entry+=1; - let pq_loc=bids.insert(neworder); + + // Insert the new order in the priority queue (OrderQueue) + let neworder=Order { owner:owner, sell_qty:sell_qty_remain, sell_remain:sell_qty_remain, buy_qty:buy_qty, royalty_remain:royalty1_qty, commission_remain:commission1_qty, order_id:id }; + bids.insert(neworder); + self.order_finder.insert(id,(sell_type,buy_type)); self.traders[owner].sub_balance(sell_type,sell_qty_remain); self.traders[0].add_balance(sell_type,commission0_qty); - self.traders[owner].orders.insert(new_order_id); - self.order_finder.insert(new_order_id,OrderFinder { asset0:sell_type, asset1:buy_type, pq_loc: pq_loc, rt_loc: rt_loc }); + self.traders[owner].order_finder.insert(id,(sell_type,buy_type)); log.push(format!("Moved {} {} ({}) to market",sell_qty_remain,self.number_to_name(sell_type),self.traders[owner].name)); - } else { new_order_id=0; } - } else { new_order_id=0; } + } + } self.traders[0].add_balance(sell_type,commission_acc); self.traders[owner].sub_balance(sell_type,royalty_acc+commission_acc); log.push(format!("Paid {} {} in royalties and {} {} ({}) in commissions",royalty_acc ,self.number_to_name(sell_type), commission_acc,self.number_to_name(sell_type),self.traders[owner].name)); - Result::PlacedOrder(new_order_id,log) + Result::PlacedOrder(id,log) } } @@ -536,12 +539,14 @@ impl PartialEq for Order { struct OrderQueue { v: Vec, + order_finder: HashMap, // Maps IDs to locations in v } impl OrderQueue { fn new()->Self { OrderQueue { - v: Vec::new() + v: Vec::new(), + order_finder:HashMap::new(), } } fn peek(&mut self) -> &mut Order { @@ -550,18 +555,19 @@ impl OrderQueue { fn empty(&self) -> bool { self.v.len()==0 } - fn bubble_up(&mut self, pos: usize) -> usize { + fn bubble_up(&mut self, pos: usize) { if pos>0 { let parent=(pos-1)/2; if self.v[parent] usize { - item.pq_loc=self.v.len(); + fn insert(&mut self, item: Order) { + let id=item.order_id; self.v.push(item); - self.bubble_up(self.v.len()-1) + self.order_finder.insert(id,self.v.len()-1); + self.bubble_up(self.v.len()-1); } fn pop(&mut self) -> Option { if self.v.len()==0 { None } else { let end=self.v.len()-1; self.v.swap(0,end); + self.order_finder.remove(&self.v[end].order_id); let rval=self.v.pop(); self.trickle_down(0); rval