chiark / gitweb /
where-vessels: disable "Show" for smash ownership when no notes
[ypp-sc-tools.db-live.git] / yarrg / rsvalue.c
index d2190dc289a9a3cc4879333da794b4c9c5f1b691..b469378303de295f3c12d17b20cc9b65f44ac772 100644 (file)
@@ -1,10 +1,36 @@
-/**/
+/*
+ * Route searcher - route evaluation
+ */
+/*
+ *  This is part of the YARRG website, a tool for assisting
+ *  players of Yohoho Puzzle Pirates.
+ * 
+ *  Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as
+ *  published by the Free Software Foundation, either version 3 of the
+ *  License, or (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *  
+ *  Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
+ *  are used without permission.  This program is not endorsed or
+ *  sponsored by Three Rings.
+ */
 
 #include <glpk.h>
 
 #include "rscommon.h"
 
 DEBUG_DEFINE_DEBUGF(value);
+DEBUG_DEFINE_SOME_DEBUGF(value2,debug2f);
 
 typedef struct { int mass, volu; } CommodInfo;
 static int commodstabsz;
@@ -13,6 +39,7 @@ static CommodInfo *commodstab;
 static sqlite3_stmt *ss_ipair_dist;
 static sqlite3_stmt *ss_ite_buy, *ss_ite_sell;
 
+
 #define MAX_LEGS (MAX_ROUTELEN-1)
 
 typedef struct {
@@ -60,18 +87,22 @@ static void add_constraint(int row, double coefficient) {
   constraint_coeffs[nconstraint_rows]= coefficient;
 }
 
-static void avail_c(const Trade *t, IslandTradeEnd **trades,
-                   int price, const char *srcdst,
-                   int islandid, sqlite3_stmt *ss_ite) {
-  /* find row number of trade availability constraint */
+static IslandTradeEnd *get_ite(const Trade *t, IslandTradeEnd **trades,
+                              int price) {
   IslandTradeEnd *search;
-
+  
   for (search= *trades; search; search=search->next)
     if (search->commodid==t->commodid && search->price==price)
-      goto found;
+      return search;
   abort();
-  
- found:;
+}
+
+static void avail_c(const Trade *t, IslandTradeEnd *ite,
+                   int price, const char *srcdst,
+                   int islandid, sqlite3_stmt *ss_ite) {
+  /* find row number of trade availability constraint */
+  IslandTradeEnd *search= ite;
+
   if (search->generation != generation) {
     search->rownum= lpx_add_rows(lp, 1);
     lpx_set_row_bnds(lp, search->rownum, LPX_UP, 0, search->qty);
@@ -135,16 +166,19 @@ static IslandPair *ipair_get_create(int si, int di) {
   assert(di < islandtablesz);
 
   if (!(ipa= ipairs[si])) {
-    ipa= ipairs[si]= mcalloc(sizeof(*ipa) * islandtablesz);
+    ipairs[si]= MCALLOC(ipa, islandtablesz);
   }
   if ((ip= ipa[di]))
     return ip;
 
-  ipa[di]= ip= mmalloc(sizeof(*ip));
+  ipa[di]= NEW(ip);
   ip->trades= 0;
   ip->route_tail_value= -1;
 
-  debugf("VALUE ipair_get(i%d,i%d) running...\n", si,di);
+  if (si==di) ctr_islands_arbitrage++;
+  else ctr_ipairs_relevant++;
+
+  debug2f("VALUE ipair_get(i%d,i%d) running...\n", si,di);
   SQL_MUST( sqlite3_bind_int(ss_ipair_dist, 1, si) );
   SQL_MUST( sqlite3_bind_int(ss_ipair_dist, 2, di) );
   assert(SQL_STEP(ss_ipair_dist));
@@ -158,6 +192,8 @@ static IslandPair *ipair_get_create(int si, int di) {
 double value_route(int nislands, const int *islands, int exclude_arbitrage) {
   int s,d;
 
+  ctr_subroutes_valued++;
+
   /* We need to construct the LP problem.  GLPK talks
    * about rows and columns, which are numbered from 1.
    *
@@ -195,6 +231,7 @@ double value_route(int nislands, const int *islands, int exclude_arbitrage) {
   lp= lpx_create_prob();
   lpx_set_obj_dir(lp, LPX_MAX);
   lpx_set_int_parm(lp, LPX_K_MSGLEV, DEBUGP(lp) ? 3 : 1);
+  lpx_set_int_parm(lp, LPX_K_PRESOL, 1);
 
   if (DEBUGP(value)) {
     lpx_set_prob_name(lp,(char*)"value_route");
@@ -247,10 +284,22 @@ double value_route(int nislands, const int *islands, int exclude_arbitrage) {
          debugf("  TRADE i%d#%d..i%d#%d c%d %d-%d  ",
                 si,s, di,d, t->commodid, t->src_price, t->dst_price);
 
+         IslandTradeEnd
+           *src_ite= get_ite(t, &itradeends[si].src, t->src_price),
+           *dst_ite= get_ite(t, &itradeends[di].dst, t->dst_price);
+
+         int qty= src_ite->qty < dst_ite->qty ? src_ite->qty : dst_ite->qty;
+         int maxprofit= qty * (t->dst_price - t->src_price);
+         debugf("maxprofit=%d ",maxprofit);
+         if (maxprofit < min_trade_maxprofit) {
+           debugf("trivial\n");
+           continue;
+         }
+
          nconstraint_rows=0;
 
-         avail_c(t, &itradeends[si].src, t->src_price, "src", si,ss_ite_sell);
-         avail_c(t, &itradeends[di].dst, t->dst_price, "dst", di,ss_ite_buy);
+         avail_c(t, src_ite, t->src_price, "src", si,ss_ite_sell);
+         avail_c(t, dst_ite, t->dst_price, "dst", di,ss_ite_buy);
 
          int leg;
          for (leg=s; leg<d; leg++) {
@@ -288,6 +337,8 @@ double value_route(int nislands, const int *islands, int exclude_arbitrage) {
   double profit= 0;
 
   if (lpx_get_num_cols(lp)) {
+    ctr_subroutes_nonempty++;
+    
     if (DEBUGP(lp))
       lpx_write_cpxlp(lp, (char*)DEBUG_DEV);
 
@@ -305,6 +356,9 @@ double value_route(int nislands, const int *islands, int exclude_arbitrage) {
   lpx_delete_prob(lp);
   lp= 0;
 
+  debugf("    %s %f\n",
+        exclude_arbitrage ? "base value" : "route value",
+        profit);
   return profit;
 }
 
@@ -327,10 +381,11 @@ static void read_trades(void) {
 
   SQL_DISTINCT_DECL(cols,5);
   while (SQL_DISTINCT_STEP(ss_trades,cols,5)) {    
+    ctr_trades_loaded++;
     IslandPair *ip= ipair_get_create(cols[1], cols[3]);
     TradesBlock *block= ip->trades;
     if (!block || ip->trades->ntrades >= TRADES_PER_BLOCK) {
-      block= mmalloc(sizeof(*block));
+      NEW(block);
       block->next= ip->trades;
       ip->trades= block;
       block->ntrades= 0;
@@ -357,6 +412,7 @@ static void read_islandtradeends(const char *bs, int srcdstoff) {
 
   SQL_DISTINCT_DECL(cols,5);
   while (SQL_DISTINCT_STEP(ss,cols,3)) {
+    ctr_quantities_loaded++;
     IslandTradeEnd *search;
 
     int commodid= cols[0];
@@ -371,7 +427,7 @@ static void read_islandtradeends(const char *bs, int srcdstoff) {
        goto found;
     /* not found, add new end */
 
-    search= mmalloc(sizeof(*search));
+    NEW(search);
     search->commodid= commodid;
     search->price= price;
     search->next= *trades;
@@ -387,16 +443,16 @@ static void read_islandtradeends(const char *bs, int srcdstoff) {
 
 void setup_value(void) {
   sqlite3_stmt *sst;
-  int i;
 
   commodstabsz= sql_single_int("SELECT max(commodid) FROM commods") + 1;
-  commodstab= mmalloc(sizeof(*commodstab)*commodstabsz);
-  for (i=0; i<commodstabsz; i++)
-    commodstab[i].mass= commodstab[i].volu= -1;
+  MCALLOC_INITEACH(commodstab, commodstabsz,
+                  this->mass= this->volu= -1
+                  );
 
   SQL_PREPARE(sst,
              "SELECT commodid,unitmass,unitvolume FROM commods");
   while (SQL_STEP(sst)) {
+    ctr_commodities_loaded++;
     int id= sqlite3_column_int(sst,0);
     assert(id>=0 && id<commodstabsz);
     commodstab[id].mass= sqlite3_column_int(sst,1);
@@ -404,8 +460,8 @@ void setup_value(void) {
   }
   sqlite3_finalize(sst);
 
-  ipairs= mcalloc(sizeof(*ipairs) * islandtablesz);
-  itradeends= mcalloc(sizeof(*itradeends) * islandtablesz);
+  MCALLOC(ipairs, islandtablesz);
+  MCALLOC(itradeends, islandtablesz);
 
   SQL_PREPARE(ss_ipair_dist,
              " SELECT dist FROM dists\n"