2019-09-08 16:42:10 +00:00
# include "debug.h"
# include "heat.h"
2020-01-25 11:05:38 +00:00
# include "common.h"
2023-08-29 22:35:38 +00:00
# include "user.h"
2019-09-08 16:42:10 +00:00
# include <iostream>
# include <algorithm>
2020-09-06 17:44:34 +00:00
# include <numeric>
2019-09-08 16:42:10 +00:00
# include <unistd.h>
2021-01-03 04:51:33 +00:00
# include <cmath>
2019-09-11 17:48:03 +00:00
2019-11-04 20:34:29 +00:00
void show_usage ( ) {
2020-01-25 11:05:38 +00:00
std : : cout < < " Usage: geostat [options] \n " ;
2020-08-06 19:14:10 +00:00
std : : cout < < " Generate HTML stats from Opencaching data. \n \n " ;
2020-01-01 23:37:28 +00:00
std : : cout < < " * Data sources: \n " ;
std : : cout < < " \t -o[user] \t use Opencaching; if specified user will be a user name used for all OC instances \n " ;
std : : cout < < " \t -p user \t \t user for opencaching.pl \n " ;
std : : cout < < " \t -d user \t \t user for opencaching.de \n " ;
std : : cout < < " \t -u user \t \t user for opencaching.us \n " ;
std : : cout < < " \t -n user \t \t user for opencaching.nl \n " ;
std : : cout < < " \t -r user \t \t user for opencaching.ro \n " ;
std : : cout < < " \t -k user \t \t user for opencaching.uk \n " ;
2020-02-29 22:19:45 +00:00
// std::cout << "\t-g file\t\tuse specified gpx file\n";
2020-01-01 23:37:28 +00:00
std : : cout < < " \t -q \t \t use local SQLite file with dump of OC database \n " ;
2020-02-23 01:42:25 +00:00
std : : cout < < " \t -i timestamp \t start date \n " ;
std : : cout < < " \t -f timestamp \t finish date \n " ;
2019-11-04 20:34:29 +00:00
std : : cout < < " * Output: \n " ;
2020-08-28 15:35:19 +00:00
std : : cout < < " \t -N \t \t compute stats for unfound caches (works only with SQLite) \n " ;
std : : cout < < " \t -O \t \t compute stats for owned caches (works only with SQLite) \n " ;
2020-01-25 15:34:18 +00:00
std : : cout < < " \t -Q \t \t exclude quiz caches from unfound caches \n " ;
2020-01-01 23:37:28 +00:00
std : : cout < < " \t -H file \t \t render a heat map to a file \n " ;
std : : cout < < " \t -s n \t \t stamp size for a heat map (default = 15) \n " ;
std : : cout < < " \t -e \t \t use exponential to flatten the heat map \n " ;
2020-02-02 11:27:32 +00:00
std : : cout < < " \t -t \t \t draw trail instead of heat map \n " ;
2020-11-02 20:01:27 +00:00
std : : cout < < " \t -a \t \t draw animated map instead of heat map \n " ;
2020-01-25 11:37:00 +00:00
std : : cout < < " \t -m map \t \t chosen map: Poland, Poland_relief, Poland_big, Europe, World or a name of voivodeship (default = Poland) \n " ;
2020-01-01 23:37:28 +00:00
std : : cout < < " \t -h \t \t display this help screen \n " ;
2019-11-04 20:34:29 +00:00
std : : exit ( EXIT_FAILURE ) ;
}
2019-09-08 16:42:10 +00:00
int main ( int argc , char * * argv ) {
std : : string heat_file ;
int heat_stamp_size = 15 ;
2019-10-06 11:08:09 +00:00
std : : string heat_map = " Poland " ;
2023-08-29 22:35:38 +00:00
User user ;
2019-09-12 12:07:46 +00:00
bool heat_exp = 0 ;
2020-02-02 11:27:32 +00:00
bool trail = 0 ;
2020-11-02 20:01:27 +00:00
bool anim = 0 ;
2019-09-08 16:42:10 +00:00
2019-11-04 20:34:29 +00:00
if ( argc = = 1 ) show_usage ( ) ;
2023-08-29 22:35:38 +00:00
2019-09-08 16:42:10 +00:00
int o ;
2020-11-02 20:01:27 +00:00
while ( ( o = getopt ( argc , argv , " qNOQD:o::p:d:u:n:r:k:i:f:H:s:m:etah? " ) ) ! = - 1 )
2019-09-08 16:42:10 +00:00
switch ( o ) {
2020-04-03 00:18:57 +00:00
case ' D ' :
2020-08-06 21:58:14 +00:00
Debug : : set_debug_level ( get_num ( ' d ' , optarg ) ) ;
2020-04-03 00:18:57 +00:00
break ;
2020-02-29 22:19:45 +00:00
// case 'g':
// gpx_file = optarg;
// break;
2020-01-01 23:37:28 +00:00
case ' o ' :
2023-08-29 22:35:38 +00:00
user . use_oc = 1 ;
2020-01-01 23:37:28 +00:00
if ( optarg ) {
2023-08-29 22:35:38 +00:00
user . ocpl_user = optarg ;
user . ocde_user = optarg ;
user . ocus_user = optarg ;
user . ocnl_user = optarg ;
user . ocro_user = optarg ;
user . ocuk_user = optarg ;
2020-01-01 23:37:28 +00:00
}
break ;
2019-09-08 16:42:10 +00:00
case ' p ' :
2023-08-29 22:35:38 +00:00
user . ocpl_user = optarg ;
2020-01-01 23:37:28 +00:00
break ;
case ' d ' :
2023-08-29 22:35:38 +00:00
user . ocde_user = optarg ;
2019-09-08 16:42:10 +00:00
break ;
case ' u ' :
2023-08-29 22:35:38 +00:00
user . ocus_user = optarg ;
2020-01-01 23:37:28 +00:00
break ;
case ' n ' :
2023-08-29 22:35:38 +00:00
user . ocnl_user = optarg ;
2020-01-01 23:37:28 +00:00
break ;
case ' r ' :
2023-08-29 22:35:38 +00:00
user . ocro_user = optarg ;
2020-01-01 23:37:28 +00:00
break ;
case ' k ' :
2023-08-29 22:35:38 +00:00
user . ocuk_user = optarg ;
2019-09-08 16:42:10 +00:00
break ;
2019-10-04 00:30:17 +00:00
case ' q ' :
2023-08-29 22:35:38 +00:00
user . use_ocdb = 1 ;
2019-10-04 00:30:17 +00:00
break ;
2020-02-23 01:26:23 +00:00
case ' i ' :
2023-08-29 22:35:38 +00:00
user . start_time = get_num ( ' i ' , optarg ) ;
user . time_filter = 1 ;
2020-02-23 01:26:23 +00:00
break ;
case ' f ' :
2023-08-29 22:35:38 +00:00
user . end_time = get_num ( ' f ' , optarg ) ;
user . time_filter = 1 ;
2020-02-23 01:26:23 +00:00
break ;
2020-01-01 23:37:28 +00:00
case ' N ' :
2023-08-29 22:35:38 +00:00
user . get_not_found = 1 ;
2019-10-04 00:30:17 +00:00
break ;
2020-08-01 21:00:50 +00:00
case ' O ' :
2023-08-29 22:35:38 +00:00
user . get_owned = 1 ;
2020-08-01 21:00:50 +00:00
break ;
2020-01-25 15:34:18 +00:00
case ' Q ' :
2023-08-29 22:35:38 +00:00
user . exclude_quiz = 1 ;
2020-01-25 15:34:18 +00:00
break ;
2019-09-08 16:42:10 +00:00
case ' H ' :
heat_file = optarg ;
break ;
case ' s ' :
2020-08-06 21:58:14 +00:00
heat_stamp_size = get_num ( ' s ' , optarg ) ;
2019-09-08 16:42:10 +00:00
break ;
2019-09-08 20:18:13 +00:00
case ' m ' :
heat_map = optarg ;
2019-09-08 16:42:10 +00:00
break ;
2019-09-12 12:07:46 +00:00
case ' e ' :
heat_exp = 1 ;
break ;
2020-02-02 11:53:51 +00:00
case ' t ' :
trail = 1 ;
break ;
2020-11-02 20:01:27 +00:00
case ' a ' :
anim = 1 ;
break ;
2019-09-08 16:42:10 +00:00
case ' h ' :
case ' ? ' :
default :
2019-11-04 20:34:29 +00:00
show_usage ( ) ;
2019-09-08 16:42:10 +00:00
}
2023-08-29 22:35:38 +00:00
if ( user . get_not_found | | user . get_owned ) {
user . use_oc = 0 ;
user . use_ocdb = 1 ;
2020-02-16 23:37:03 +00:00
trail = 0 ;
2023-08-29 22:35:38 +00:00
if ( user . ocpl_user_uuid . empty ( ) & & user . ocpl_user . empty ( ) & & user . ocde_user_uuid . empty ( ) & & user . ocde_user . empty ( ) ) {
2021-01-03 02:21:11 +00:00
std : : cout < < " Options \" -N \" or \" -O \" work only with OCpl or OCde. \n " ;
2020-08-01 21:00:50 +00:00
std : : exit ( EXIT_FAILURE ) ;
}
2023-08-29 22:35:38 +00:00
if ( user . get_not_found & & user . get_owned ) {
2020-08-01 21:00:50 +00:00
std : : cout < < " Options \" -N \" and \" -O \" are mutually exclusive. \n " ;
2020-02-16 23:37:03 +00:00
std : : exit ( EXIT_FAILURE ) ;
}
}
2020-11-02 20:01:27 +00:00
if ( trail & & anim ) {
std : : cout < < " Options \" -a \" and \" -t \" are mutually exclusive. \n " ;
std : : exit ( EXIT_FAILURE ) ;
}
2023-08-29 22:35:38 +00:00
user . get_caches ( ) ;
2022-07-12 10:54:56 +00:00
2023-08-29 22:35:38 +00:00
if ( user . caches_count = = 0 ) {
2019-11-04 20:34:48 +00:00
std : : cout < < " No caches found, aborting. \n " ;
std : : exit ( EXIT_FAILURE ) ;
}
2019-09-08 16:42:10 +00:00
2023-08-29 22:35:38 +00:00
user . prepare_lists_of_caches ( ) ;
2020-01-25 10:40:56 +00:00
2020-08-06 19:13:40 +00:00
header_html ( ) ;
2023-08-30 14:40:12 +00:00
std : : cout < < " <header> \n " ;
std : : cout < < " <h1><a href= \" /geo \" >Geocaching stats</a> for user profiles:</h1> \n " ;
2023-08-29 22:35:38 +00:00
user . header ( ) ;
2020-08-06 19:13:40 +00:00
2023-08-29 22:35:38 +00:00
if ( user . time_filter ) {
std : : cout < < " for time range " < < std : : put_time ( std : : localtime ( & user . start_time ) , " %x " ) < < " — " < < std : : put_time ( std : : localtime ( & user . end_time ) , " %x " ) ;
2020-02-23 01:42:25 +00:00
}
2020-03-19 17:31:55 +00:00
std : : cout < < " </header> \n " ;
2019-11-10 20:03:11 +00:00
if ( ! heat_file . empty ( ) ) {
const Map * chosen_map ;
if ( maps . count ( heat_map ) > 0 )
chosen_map = & maps . at ( heat_map ) ;
else {
std : : cout < < " Map " < < heat_map < < " not found. \n " ;
std : : exit ( EXIT_FAILURE ) ;
}
2020-02-02 11:27:32 +00:00
Heat hmap ( chosen_map ) ;
2020-02-23 02:52:30 +00:00
if ( trail ) {
2023-08-29 22:35:38 +00:00
if ( user . sorted_fcaches . size ( ) < 2 ) {
2020-02-23 02:52:30 +00:00
std : : cout < < " You need at least 2 caches for a trail. \n " ;
std : : exit ( EXIT_FAILURE ) ;
}
2023-08-29 22:35:38 +00:00
hmap . generate_path ( heat_file , user . sorted_fcaches ) ;
2020-11-02 20:01:27 +00:00
} else if ( anim )
2023-08-29 22:35:38 +00:00
hmap . generate_anim ( heat_file , user . sorted_fcaches , heat_stamp_size ) ;
2020-11-02 20:01:27 +00:00
else
2023-08-29 22:35:38 +00:00
hmap . generate ( heat_file , user . fcc , heat_stamp_size , ( heat_exp = = 1 ? " exp " : " soft " ) ) ;
2020-11-13 18:51:09 +00:00
if ( ! anim )
std : : cout < < " <figure> \n <img class= \" heatmap \" src= \" " < < heat_file < < " \" alt= \" heat map \" > \n </figure> \n " ;
else {
std : : cout < < " <script src= \" components/webcomponentsjs/webcomponents-loader.js \" ></script> \n <script src= \" components/gif-player/dist/gif-player.es6.js \" defer async></script> " ;
2020-11-13 19:52:41 +00:00
std : : cout < < " <figure class= \" heatmap \" > \n <gif-player class= \" heatmap \" src= \" " < < heat_file < < " \" alt= \" heat map \" speed= \" 1 \" play prerender></gif-player> \n </figure> \n " ;
2020-11-13 18:51:09 +00:00
std : : cout < < " <noscript> \n " ;
std : : cout < < " <figure> \n <img class= \" heatmap \" src= \" " < < heat_file < < " \" alt= \" heat map \" > \n </figure> \n " ;
std : : cout < < " </noscript> \n " ;
}
2019-11-10 20:03:11 +00:00
}
2023-08-29 22:35:38 +00:00
if ( ! user . get_not_found & & ! user . get_owned ) {
2020-03-21 03:52:52 +00:00
short count ;
2021-04-20 18:20:19 +00:00
std : : string codes ;
2020-06-03 22:11:37 +00:00
int n ;
2020-03-21 03:52:52 +00:00
2019-11-10 19:59:21 +00:00
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Number of caches found: <span class= \" value \" > " < < user . cc . size ( ) < < " </span><br> \n " ;
2020-01-25 10:40:56 +00:00
2023-08-29 22:35:38 +00:00
auto best_day = std : : max_element ( user . dates . begin ( ) , user . dates . end ( ) , [ & ] ( const auto & a , const auto & b ) { return a . second < b . second ; } ) ;
std : : cout < < " Number of caching days: <span class= \" value \" > " < < user . dates . size ( ) < < " </span><br> \n " ;
std : : cout < < " Average caches per caching day: <span class= \" value \" > " < < std : : setprecision ( 3 ) < < ( 1.0 * user . cc . size ( ) ) / user . dates . size ( ) < < " </span><br> \n " ;
2020-03-13 19:53:17 +00:00
std : : cout < < std : : resetiosflags ( std : : cout . flags ( ) ) ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Number of caches that are now archived: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . status = = archived ; } ) < < " </span><br> \n " ;
2020-03-09 12:20:49 +00:00
std : : cout < < " <details class= \" days \" ><summary>Best caching day: <span class= \" value \" > " < < best_day - > first < < " </span>, found <span class= \" value \" > " < < best_day - > second < < " </span> caches</summary> \n " ;
std : : cout < < " <p> \n " ;
2023-08-29 22:35:38 +00:00
for ( const auto & i : user . dates )
2019-11-11 22:28:37 +00:00
std : : cout < < i . first < < " , found " < < i . second < < " caches<br> \n " ;
2020-03-09 12:20:49 +00:00
std : : cout < < " </p> \n </details> \n " ;
2019-11-10 19:59:21 +00:00
2020-07-06 16:29:23 +00:00
std : : time_t streak ;
2023-08-29 22:35:38 +00:00
int longest_str = find_streak ( user . sorted_caches , streak ) ;
2020-01-04 17:33:53 +00:00
char str_tmp [ 20 ] ;
2020-07-06 16:29:23 +00:00
std : : tm * str_tm = std : : localtime ( & streak ) ;
std : : strftime ( str_tmp , 20 , " %F " , str_tm ) ;
2020-01-04 17:41:15 +00:00
std : : cout < < " Longest caching streak: <span class= \" value \" > " < < longest_str < < " </span> starting on <span class= \" value \" > " < < str_tmp < < " </span><br> \n " ;
2020-01-04 17:33:53 +00:00
2020-03-09 19:36:08 +00:00
float tot_dist = 0 ;
2023-08-29 22:35:38 +00:00
for ( auto i = user . sorted_fcaches . begin ( ) ; i ! = std : : prev ( user . sorted_fcaches . end ( ) ) ; i + + ) {
2020-01-04 18:27:04 +00:00
//std::cout << "Distance between " << i->second->name << " and " << std::next(i)->second->name << " is " << cache_distance(*i->second, *std::next(i)->second) << "<br>";
2019-11-10 19:59:21 +00:00
tot_dist + = cache_distance ( * i - > second , * std : : next ( i ) - > second ) ;
}
2021-09-05 17:47:13 +00:00
std : : cout < < " Total distance between caches: <span class= \" value \" > " < < std : : fixed < < tot_dist < < " </span> km (equivalent to <span class= \" value \" > " < < tot_dist / ( 2 * M_PI * Earth_radius ) < < " x</span> trips around Earth or <span class= \" value \" > " < < tot_dist / Moon_dist < < " x</span> trips to the Moon)<br> \n " ;
2020-03-13 19:53:17 +00:00
std : : cout < < std : : resetiosflags ( std : : cout . flags ( ) ) ;
2023-08-29 22:35:38 +00:00
if ( user . sorted_fcaches . size ( ) > 1 )
std : : cout < < " Average distance between caches: <span class= \" value \" > " < < tot_dist / ( user . sorted_fcaches . size ( ) - 1 ) < < " </span> km<br> \n " ;
2019-11-10 20:03:11 +00:00
std : : cout < < " </div> \n " ;
2019-11-11 20:10:58 +00:00
2023-08-29 22:35:38 +00:00
short y_min = std : : min_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_tm . tm_year < b . date_tm . tm_year ; } ) - > date_tm . tm_year ;
short y_max = std : : max_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_tm . tm_year < b . date_tm . tm_year ; } ) - > date_tm . tm_year ;
2020-05-03 21:14:37 +00:00
2020-03-21 03:52:52 +00:00
long max = 0 ; // maximal value for histogram
for ( int i = y_min ; i < = y_max ; i + + )
for ( int j = 1 ; j < = 12 ; j + + )
2023-08-29 22:35:38 +00:00
max = std : : max ( max , std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ i , j ] ( Cache c ) { return ( c . date_tm . tm_year = = i & & c . date_tm . tm_mon = = j - 1 ) ; } ) ) ;
2020-03-21 03:52:52 +00:00
2020-08-05 00:25:06 +00:00
if ( max > 0 ) {
std : : cout < < " <h2>Caching timeline</h2> \n " ;
std : : cout < < " <table class= \" calendar_tab \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // print table month headers
std : : cout < < " <th> " < < j < < " </th> " ;
2020-03-21 03:52:52 +00:00
}
std : : cout < < " </tr> \n " ;
2020-08-05 00:25:06 +00:00
for ( int i = y_min ; i < = y_max ; i + + ) { // i -> years in rows
std : : cout < < " <tr><th> " < < i + 1900 < < " </th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // j -> months in cols
2023-08-29 22:35:38 +00:00
count = std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ i , j ] ( Cache c ) { return ( c . date_tm . tm_year = = i & & c . date_tm . tm_mon = = j - 1 ) ; } ) ;
2020-08-05 00:25:06 +00:00
std : : cout < < " <td style= \" --percent: " < < count * 100 / max < < " % \" ><span> " < < count < < " </span></td> " ;
}
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
2020-03-21 03:52:52 +00:00
}
2020-07-05 22:01:26 +00:00
std : : cout < < " <h2>Caching days per month</h2> \n " ;
std : : cout < < " <table class= \" calendar_tab \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // print table month headers
std : : cout < < " <th> " < < j < < " </th> " ;
}
std : : cout < < " </tr> \n " ;
max = 31 ; // maximal value for histogram
for ( int i = y_min ; i < = y_max ; i + + ) { // i -> years in rows
std : : cout < < " <tr><th> " < < i + 1900 < < " </th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // j -> months in cols
2020-08-06 22:02:11 +00:00
std : : map < int , int > days_count ;
2023-08-29 22:35:38 +00:00
for ( auto el : user . cc ) {
2020-07-05 22:01:26 +00:00
if ( el . date_tm . tm_mon = = j - 1 & & el . date_tm . tm_year = = i )
2020-08-06 22:02:11 +00:00
days_count [ el . date_tm . tm_mday ] + + ;
2020-07-05 22:01:26 +00:00
}
2020-08-06 22:02:11 +00:00
std : : cout < < " <td style= \" --percent: " < < days_count . size ( ) * 100 / max < < " % \" ><span> " < < days_count . size ( ) < < " </span></td> " ;
2020-07-05 22:01:26 +00:00
}
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
2020-01-25 11:05:38 +00:00
// auto far = std::max_element(fcc.begin(), fcc.end(), [&](const Cache& a, const Cache& b) { return a.distance() < b.distance(); });
// auto near = std::min_element(fcc.begin(), fcc.end(), [&](const Cache& a, const Cache& b) { return a.distance() < b.distance(); });
2020-08-06 21:58:14 +00:00
//
2020-01-25 11:05:38 +00:00
// std::cout << "Nearest cache: " << near->distance() << " km\n";
// near->show();
// std::cout << "Furthest cache: " << far->distance() << " km\n";
// far->show();
2020-03-20 02:28:20 +00:00
// show_histogram(cc, &Cache::year_month, "Caching timeline", 1, 0);
2023-08-29 22:35:38 +00:00
show_histogram ( user . cc , & Cache : : owner , " Cache owners " , 1 ) ;
show_histogram ( user . cc , & Cache : : type , " Cache types " , 1 ) ;
show_histogram ( user . cc , & Cache : : size , " Cache sizes " , 1 ) ;
2020-08-06 21:58:14 +00:00
// show_histogram(fcc, &Cache::region, "Regions", 1);
// show_histogram(fcc, &Cache::subregion, "Subregions", 1);
2023-08-29 22:35:38 +00:00
show_histogram ( user . fcc , & Cache : : country , " Countries " , 1 ) ;
show_nested_histogram ( user . fcc , & Cache : : region , & Cache : : subregion , " Regions " , 1 ) ;
show_histogram ( user . cc , & Cache : : day_of_week , " Days of the week " , 1 , 0 ) ;
show_histogram ( user . cc , & Cache : : mon , " Months " , 1 , 0 ) ;
show_histogram ( user . cc , & Cache : : year , " Years " , 1 , 0 ) ;
2019-09-08 16:42:10 +00:00
2023-08-29 22:35:38 +00:00
auto N = * std : : max_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lat < b - > pos . lat ; } ) ;
auto S = * std : : min_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lat < b - > pos . lat ; } ) ;
auto E = * std : : max_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lon < b - > pos . lon ; } ) ;
auto W = * std : : min_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lon < b - > pos . lon ; } ) ;
2020-01-25 12:51:22 +00:00
2020-05-03 21:14:37 +00:00
std : : cout < < " <h2>Geographically extreme caches</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr> \n " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>North:</th><td> " < < N - > link_name ( ) < < " </td><td> " < < N - > region < < " </td><td> " < < N - > pos . lat < < " </td> \n " ;
2020-05-03 21:14:37 +00:00
std : : cout < < " </tr><tr> \n " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>South:</th><td> " < < S - > link_name ( ) < < " </td><td> " < < S - > region < < " </td><td> " < < S - > pos . lat < < " </td> \n " ;
2020-05-03 21:14:37 +00:00
std : : cout < < " </tr><tr> \n " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>East:</th> <td> " < < E - > link_name ( ) < < " </td><td> " < < E - > region < < " </td><td> " < < E - > pos . lon < < " </td> \n " ;
2020-05-03 21:14:37 +00:00
std : : cout < < " </tr><tr> \n " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>West:</th> <td> " < < W - > link_name ( ) < < " </td><td> " < < W - > region < < " </td><td> " < < W - > pos . lon < < " </td> \n " ;
2020-01-25 12:51:22 +00:00
std : : cout < < " </tr> \n " ;
std : : cout < < " </table> \n " ;
2020-01-25 14:26:14 +00:00
const int LIST_MAX = 15 ;
n = 1 ;
std : : cout < < " <h2>Oldest caches found</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Date found</th> " ;
2020-01-25 14:26:14 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i = user . sorted_caches_by_hidden . begin ( ) ; i ! = user . sorted_caches_by_hidden . end ( ) ; i + + ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < i - > second - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > second - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > second - > region < < " </td> " ;
2020-01-25 14:26:14 +00:00
std : : cout < < " <td> " < < i - > second - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < i - > second - > date < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
n = 1 ;
std : : cout < < " <h2>Newest caches found</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Date found</th> " ;
2020-01-25 14:26:14 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i = user . sorted_caches_by_hidden . rbegin ( ) ; i ! = user . sorted_caches_by_hidden . rend ( ) ; i + + ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < i - > second - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > second - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > second - > region < < " </td> " ;
2020-01-25 14:26:14 +00:00
std : : cout < < " <td> " < < i - > second - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < i - > second - > date < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2020-01-25 14:36:29 +00:00
2020-07-05 21:30:51 +00:00
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Average age of cache at the moment of finding: <span class= \" value \" > " < < average ( user . cc , & Cache : : age_when_found ) / 365 * 12 < < " </span> months<br> \n " ;
std : : cout < < " Number of caches found within first 24h: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found = = 0 ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches found within first 48h: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found < = 1 ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches found during first week: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found < 7 ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches found during first month: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found < 30 ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches found after more than 5 years: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found > 365 * 5 ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches found after more than 10 years: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . age_when_found > 365 * 10 ; } ) < < " </span><br> \n " ;
2020-07-05 21:30:51 +00:00
std : : cout < < " </div> \n " ;
2020-01-25 15:12:29 +00:00
n = 1 ;
std : : cout < < " <h2>Caches with most recommendations</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Rec.</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " <th>%</th> " ;
2020-01-25 15:12:29 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_fav ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > region < < " </td> " ;
2020-01-25 15:12:29 +00:00
std : : cout < < " <td> " < < i - > fav < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " <td> " < < std : : setprecision ( 3 ) < < 100.0 * i - > fav / i - > founds < < " %</td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2023-08-29 22:35:38 +00:00
average_html ( user . cc , & Cache : : fav , " number of recommendations " ) ;
2020-07-05 21:30:51 +00:00
2020-01-25 15:12:29 +00:00
n = 1 ;
std : : cout < < " <h2>Caches with most recommendations (percentage)</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Rec.</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " <th>%</th> " ;
2020-01-25 15:12:29 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_fav_perc ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > region < < " </td> " ;
2020-01-25 15:12:29 +00:00
std : : cout < < " <td> " < < i - > fav < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " <td> " < < std : : setprecision ( 3 ) < < 100.0 * i - > fav / i - > founds < < " %</td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2022-07-14 12:47:15 +00:00
/*
2020-02-01 11:36:39 +00:00
n = 1 ;
2020-08-28 16:40:48 +00:00
std : : cout < < " <h2>Caches with highest rating</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-08-28 16:40:48 +00:00
std : : cout < < " <th>Rating</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " </tr> \n " ;
for ( auto i : caches_by_rating ) {
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > region < < " </td> " ;
2020-08-28 16:40:48 +00:00
std : : cout < < " <td> " < < i - > rating < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
average_html ( cc , & Cache : : rating , " rating " ) ;
2021-08-08 17:18:51 +00:00
*/
2020-08-28 16:40:48 +00:00
n = 1 ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <h2>Caches with most finds</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Finds</th> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_finds ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < i - > region < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < i - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2023-08-29 22:35:38 +00:00
average_html ( user . cc , & Cache : : founds , " number of finds " ) ;
2020-07-05 21:30:51 +00:00
2020-02-01 11:36:39 +00:00
n = 1 ;
std : : cout < < " <h2>Caches with least finds</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <th>Region</th> " ;
2020-02-07 14:20:38 +00:00
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Finds</th> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i = user . caches_by_finds . rbegin ( ) ; i ! = user . caches_by_finds . rend ( ) ; i + + ) {
2020-02-07 14:20:38 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
2020-02-29 01:26:43 +00:00
std : : cout < < " <td> " < < ( * i ) - > link_name ( ) < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < ( * i ) - > type < < " </td> " ;
2021-08-08 17:15:12 +00:00
std : : cout < < " <td> " < < ( * i ) - > region < < " </td> " ;
2020-02-01 11:36:39 +00:00
std : : cout < < " <td> " < < ( * i ) - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < ( * i ) - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2020-03-21 04:02:23 +00:00
2020-08-06 21:58:14 +00:00
// D/T matrix
2020-06-03 22:06:49 +00:00
n = 0 ;
2020-05-03 21:14:37 +00:00
std : : cout < < " <h2>Difficulty / terrain matrix</h2> \n " ;
std : : cout < < " <table class= \" dt \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 2 ; j < = 10 ; j + + ) { // print table terr headers
std : : cout < < " <th> " < < j / 2.0 < < " </th> " ;
}
std : : cout < < " </tr> \n " ;
for ( int i = 2 ; i < = 10 ; i + + ) { // i -> diff in rows
std : : cout < < " <tr><th> " < < i / 2.0 < < " </th> " ;
for ( int j = 2 ; j < = 10 ; j + + ) { // j -> terr in cols
2023-08-29 22:35:38 +00:00
count = count_caches ( user . cc , codes , [ i , j ] ( const Cache & c ) - > bool { return ( c . diff = = i / 2.0 & & c . terr = = j / 2.0 ) ; } ) ;
2020-05-03 21:14:37 +00:00
if ( count = = 0 )
std : : cout < < " <td class= \" dt_zero \" > " < < 0 < < " </td> " ;
else {
2021-04-20 18:20:19 +00:00
std : : cout < < " <td codes= \" " < < codes < < " \" > " < < count < < " </td> " ;
2020-05-03 21:14:37 +00:00
n + + ;
}
}
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2020-07-05 21:30:51 +00:00
std : : cout < < " Total <span class= \" value \" > " < < n < < " </span> combinations found out of 81 ( " < < std : : setprecision ( 3 ) < < n / 0.81 < < " %).<br> \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Average difficulty: <span class= \" value \" > " < < average ( user . cc , & Cache : : diff ) < < " </span><br> \n " ;
std : : cout < < " Average terrain: <span class= \" value \" > " < < average ( user . cc , & Cache : : terr ) < < " </span><br> \n " ;
2020-05-03 21:14:37 +00:00
std : : cout < < " </div> \n " ;
2020-08-06 21:58:14 +00:00
// Days matrix
2020-05-03 21:14:37 +00:00
n = 0 ;
std : : cout < < " <h2>Caching days matrix</h2> \n " ;
std : : cout < < " <table class= \" dt \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 1 ; j < = 31 ; j + + ) { // print table day headers
std : : cout < < " <th> " < < j < < " </th> " ;
}
2021-09-05 17:36:33 +00:00
std : : cout < < " <th></th></tr> \n " ;
2020-05-03 21:14:37 +00:00
for ( int i = 1 ; i < = 12 ; i + + ) { // i -> months in rows
2021-09-05 17:36:33 +00:00
int m = 0 ;
2020-05-03 21:14:37 +00:00
std : : cout < < " <tr><th> " < < i < < " </th> " ;
for ( int j = 1 ; j < = 31 ; j + + ) { // j -> days in cols
2023-08-29 22:35:38 +00:00
count = count_caches ( user . cc , codes , [ i , j ] ( const Cache & c ) - > bool { return ( c . date_tm . tm_mon = = i - 1 & & c . date_tm . tm_mday = = j ) ; } ) ;
2020-05-03 21:14:37 +00:00
if ( count = = 0 ) {
if ( ( j = = 31 & & ( i = = 2 | | i = = 4 | | i = = 6 | | i = = 9 | | i = = 11 ) ) | | ( j = = 30 & & i = = 2 ) )
std : : cout < < " <td class= \" dt_null \" ></td> " ;
else
std : : cout < < " <td class= \" dt_zero \" > " < < 0 < < " </td> " ;
} else {
2021-04-20 20:47:20 +00:00
std : : cout < < " <td codes= \" " < < codes < < " \" > " < < count < < " </td> " ;
2020-05-03 21:14:37 +00:00
n + + ;
2021-09-05 17:36:33 +00:00
m + + ;
2020-05-03 21:14:37 +00:00
}
}
2021-09-05 17:36:33 +00:00
float perc ;
2022-07-14 12:47:15 +00:00
switch ( i ) {
2021-09-05 17:36:33 +00:00
case 4 :
case 6 :
case 9 :
case 11 :
perc = m * 100.0 / 30 ;
break ;
case 2 :
perc = m * 100.0 / 29 ;
break ;
default :
perc = m * 100.0 / 31 ;
}
std : : cout < < " <th> " < < perc < < " %</th> " ;
2020-05-03 21:14:37 +00:00
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
std : : cout < < " <div class= \" basic_stats \" > \n " ;
std : : cout < < " Total <span class= \" value \" > " < < n < < " </span> days out of 366 ( " < < std : : setprecision ( 3 ) < < n / 3.66 < < " %). \n " ;
std : : cout < < " </div> \n " ;
2021-05-05 21:53:11 +00:00
// Hidden months matrix
n = 0 ;
2023-08-29 22:35:38 +00:00
y_min = std : : min_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_hidden_tm . tm_year < b . date_hidden_tm . tm_year ; } ) - > date_hidden_tm . tm_year ;
y_max = std : : max_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_hidden_tm . tm_year < b . date_hidden_tm . tm_year ; } ) - > date_hidden_tm . tm_year ;
2020-03-21 04:02:23 +00:00
2020-03-29 23:59:10 +00:00
std : : cout < < " <h2>Caches by hidden month matrix</h2> \n " ;
2020-03-21 04:02:23 +00:00
std : : cout < < " <table class= \" dt \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // print table month headers
std : : cout < < " <th> " < < j < < " </th> " ;
}
2021-09-05 17:36:33 +00:00
std : : cout < < " <th></th></tr> \n " ;
std : : time_t now = std : : time ( nullptr ) ;
std : : tm * now_tm = std : : localtime ( & now ) ;
2020-03-21 04:02:23 +00:00
for ( int i = y_min ; i < = y_max ; i + + ) { // i -> years in rows
2021-09-05 17:36:33 +00:00
int m = 0 ;
2020-03-21 04:02:23 +00:00
std : : cout < < " <tr><th> " < < i + 1900 < < " </th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // j -> months in cols
2023-08-29 22:35:38 +00:00
count = count_caches ( user . cc , codes , [ i , j ] ( const Cache & c ) - > bool { return ( c . date_hidden_tm . tm_year = = i & & c . date_hidden_tm . tm_mon = = j - 1 ) ; } ) ;
2021-05-05 22:54:34 +00:00
if ( count = = 0 ) {
2023-08-29 22:35:38 +00:00
if ( ( ! user . ocpl_user_uuid . empty ( ) & & user . ocde_user_uuid . empty ( ) & & i + 1900 = = 2006 & & j < 5 ) | |
( ! user . ocde_user_uuid . empty ( ) & & i + 1900 = = 2005 & & j < 8 ) )
2021-05-05 22:54:34 +00:00
std : : cout < < " <td class= \" dt_null \" ></td> " ;
else
std : : cout < < " <td class= \" dt_zero \" > " < < 0 < < " </td> " ;
2022-07-14 12:47:15 +00:00
} else {
2021-04-20 20:47:20 +00:00
std : : cout < < " <td codes= \" " < < codes < < " \" > " < < count < < " </td> " ;
2021-05-05 21:53:11 +00:00
n + + ;
2021-09-05 17:36:33 +00:00
m + + ;
2021-05-05 21:53:11 +00:00
}
2020-03-21 04:02:23 +00:00
}
2021-09-05 17:36:33 +00:00
if ( now_tm ) {
if ( i = = now_tm - > tm_year )
std : : cout < < " <th> " < < m * 100.0 / ( now_tm - > tm_mon + 1 ) < < " %</th> " ;
else
std : : cout < < " <th> " < < m * 100.0 / 12 < < " %</th> " ;
}
2020-03-21 04:02:23 +00:00
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
2020-01-25 14:36:29 +00:00
2021-05-05 21:53:11 +00:00
if ( now_tm ) {
2023-08-29 22:35:38 +00:00
if ( ! user . ocpl_user_uuid . empty ( ) & & user . ocde_user_uuid . empty ( ) ) {
2021-05-05 22:15:43 +00:00
int m_count = ( now_tm - > tm_year - 106 - 1 ) * 12 + 8 + now_tm - > tm_mon + 1 ; // 106 corresponds to 2006, 8 is no. of months since may till dec, +1 since tm_mon starts at 0
2021-05-05 21:53:11 +00:00
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2021-05-05 22:15:43 +00:00
std : : cout < < " Total <span class= \" value \" > " < < n < < " </span> months out of " < < m_count < < " ( " < < std : : setprecision ( 3 ) < < n * 100.0 / m_count < < " %). \n " ;
2022-07-14 12:47:15 +00:00
std : : cout < < " </div> \n " ;
2023-08-29 22:35:38 +00:00
} else if ( ! user . ocde_user_uuid . empty ( ) ) {
2021-05-05 22:15:43 +00:00
int m_count = ( now_tm - > tm_year - 105 - 1 ) * 12 + 5 + now_tm - > tm_mon + 1 ; // 106 corresponds to 2005, 8 is no. of months since aug till dec, +1 since tm_mon starts at 0
2021-05-05 21:53:11 +00:00
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2021-05-05 22:15:43 +00:00
std : : cout < < " Total <span class= \" value \" > " < < n < < " </span> months out of " < < m_count < < " ( " < < std : : setprecision ( 3 ) < < n * 100.0 / m_count < < " %). \n " ;
2022-07-14 12:47:15 +00:00
std : : cout < < " </div> \n " ;
2021-05-05 21:53:11 +00:00
}
}
2022-07-12 10:54:56 +00:00
2023-08-29 22:35:38 +00:00
if ( ! user . ocpl_user_uuid . empty ( ) ) {
2022-07-14 12:27:22 +00:00
n = 1 ;
2022-07-14 12:23:30 +00:00
2022-07-14 12:27:22 +00:00
std : : cout < < " <h2>Power trails (by completion percentage)</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Trail</th> " ;
2022-07-18 20:13:27 +00:00
std : : cout < < " <th>Type</th> " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " <th>Caches</th> " ;
std : : cout < < " <th>Found</th> " ;
std : : cout < < " <th>Treshold</th> " ;
2022-07-18 20:13:27 +00:00
std : : cout < < " <th>Needed</th> " ;
std : : cout < < " <th>Available</th> " ;
2022-07-14 12:23:30 +00:00
std : : cout < < " </tr> \n " ;
2022-07-12 10:54:56 +00:00
2023-08-29 22:35:38 +00:00
for ( auto & i : user . tt ) {
2022-07-18 20:13:27 +00:00
std : : cout < < " <tr> " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " <th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
2022-07-18 20:13:27 +00:00
std : : cout < < " <td> " < < i - > get_type ( ) < < " </td> " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " <td> " < < i - > caches . size ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > found < < " </td> " ;
2022-07-18 20:13:27 +00:00
if ( i - > completed )
std : : cout < < " <td class= \" good \" > " ;
else if ( i - > active_caches_not_found < i - > needed )
std : : cout < < " <td class= \" bad \" > " ;
else
std : : cout < < " <td> " ;
std : : cout < < i - > completed_perc < < " % / " < < i - > treshold_perc < < " %</td> " ;
std : : cout < < " <td> " ;
if ( ! i - > completed )
std : : cout < < i - > needed ;
std : : cout < < " </td> " ;
2023-03-27 18:50:40 +00:00
std : : cout < < " <td> " ;
2023-03-27 18:56:01 +00:00
if ( i - > active_caches_not_found & & i - > active_caches_not_found < UINT_MAX - 1024 )
2023-03-27 18:50:40 +00:00
std : : cout < < i - > active_caches_not_found ;
std : : cout < < " </td> " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " </tr> \n " ;
n + + ;
// if (n > LIST_MAX) break;
}
std : : cout < < " </table> \n " ;
2022-07-12 23:11:44 +00:00
2022-07-14 12:27:22 +00:00
// show_histogram(tt, "Power trails (completion percentage)", 1);
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Number of completed power trails: <span class= \" value \" > " < < std : : count_if ( user . tt . begin ( ) , user . tt . end ( ) , [ & ] ( const auto & a ) { return a - > completed ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of started power trails: <span class= \" value \" > " < < user . tt . size ( ) < < " </span><br> \n " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " </div> \n " ;
2022-07-12 23:11:44 +00:00
2022-07-14 12:27:22 +00:00
std : : cout < < " <h2>FTF</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Region</th> " ;
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Finds</th> " ;
2022-07-12 23:11:44 +00:00
std : : cout < < " </tr> \n " ;
2022-07-14 12:27:22 +00:00
n = 1 ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_ftf ) {
2022-07-14 12:27:22 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
std : : cout < < " <td> " < < i - > region < < " </td> " ;
std : : cout < < " <td> " < < i - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
// if (n > LIST_MAX) break;
}
std : : cout < < " </table> \n " ;
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Number of FTFs: <span class= \" value \" > " < < user . caches_ftf . size ( ) < < " </span><br> \n " ;
2022-07-14 12:27:22 +00:00
std : : cout < < " </div> \n " ;
2022-07-12 23:11:44 +00:00
}
2020-01-25 14:36:29 +00:00
} // end of main if
2019-11-04 20:13:20 +00:00
2023-08-29 22:35:38 +00:00
if ( user . get_not_found ) {
2020-02-16 23:37:03 +00:00
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Still <span class= \" value \" > " < < user . cc . size ( ) < < " </span> caches to be found...<br> \n " ;
2020-02-16 23:37:03 +00:00
std : : cout < < " </div> \n " ;
2020-05-24 14:56:10 +00:00
2023-08-29 22:35:38 +00:00
show_nested_histogram ( user . fcc , & Cache : : region , & Cache : : subregion , " Regions " , 1 ) ;
2020-09-06 17:51:14 +00:00
2020-06-02 22:30:05 +00:00
std : : map < std : : string , int > region_found_count ;
2023-08-29 22:35:38 +00:00
for ( auto el : user . fcc )
2020-09-06 17:51:14 +00:00
region_found_count [ el - > region ] + + ;
2023-08-29 22:35:38 +00:00
for ( auto & i : user . region_count )
2021-01-03 03:51:54 +00:00
if ( i . second ! = 0 ) i . second = region_found_count [ i . first ] * 100 / i . second ;
2023-08-29 22:35:38 +00:00
show_histogram ( user . region_count , " Percentage " , 1 ) ;
2021-05-05 21:53:11 +00:00
} // end of "not found" if
2020-02-16 23:37:03 +00:00
2023-08-29 22:35:38 +00:00
if ( user . get_owned ) {
2020-08-01 21:00:50 +00:00
short count ;
2021-04-20 20:41:20 +00:00
std : : string codes ;
2020-08-01 21:00:50 +00:00
int n ;
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Number of caches created: <span class= \" value \" > " < < user . cc . size ( ) < < " </span><br> \n " ;
std : : cout < < " Number of caches that are disabled: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . status = = disabled ; } ) < < " </span><br> \n " ;
std : : cout < < " Number of caches that are archived: <span class= \" value \" > " < < std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const auto & a ) { return a . status = = archived ; } ) < < " </span><br> \n " ;
std : : cout < < " Average finds per cache per day: <span class= \" value \" > " < < std : : setprecision ( 3 ) < < std : : accumulate ( user . cc . begin ( ) , user . cc . end ( ) , 0. , [ & ] ( const float & a , const Cache & b ) { return std : : move ( a ) + 1.0 * b . founds / std : : max ( b . age_now , 1 ) ; } ) / user . caches_count < < " </span><br> \n " ;
2020-09-06 17:44:34 +00:00
std : : cout < < std : : resetiosflags ( std : : cout . flags ( ) ) ;
2020-08-04 23:48:23 +00:00
std : : cout < < " </div> \n " ;
2020-08-01 21:00:50 +00:00
2023-08-29 22:35:38 +00:00
short y_min = std : : min_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_hidden_tm . tm_year < b . date_hidden_tm . tm_year ; } ) - > date_hidden_tm . tm_year ;
short y_max = std : : max_element ( user . cc . begin ( ) , user . cc . end ( ) , [ & ] ( const Cache & a , const Cache & b ) { return a . date_hidden_tm . tm_year < b . date_hidden_tm . tm_year ; } ) - > date_hidden_tm . tm_year ;
2020-08-05 00:27:17 +00:00
long max = 0 ; // maximal value for histogram
for ( int i = y_min ; i < = y_max ; i + + )
for ( int j = 1 ; j < = 12 ; j + + )
2023-08-29 22:35:38 +00:00
max = std : : max ( max , std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ i , j ] ( Cache c ) { return ( c . date_hidden_tm . tm_year = = i & & c . date_hidden_tm . tm_mon = = j - 1 ) ; } ) ) ;
2020-08-05 00:27:17 +00:00
if ( max > 0 ) {
std : : cout < < " <h2>Cache creation timeline</h2> \n " ;
std : : cout < < " <table class= \" calendar_tab \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // print table month headers
std : : cout < < " <th> " < < j < < " </th> " ;
}
std : : cout < < " </tr> \n " ;
for ( int i = y_min ; i < = y_max ; i + + ) { // i -> years in rows
std : : cout < < " <tr><th> " < < i + 1900 < < " </th> " ;
for ( int j = 1 ; j < = 12 ; j + + ) { // j -> months in cols
2023-08-29 22:35:38 +00:00
count = std : : count_if ( user . cc . begin ( ) , user . cc . end ( ) , [ i , j ] ( Cache c ) { return ( c . date_hidden_tm . tm_year = = i & & c . date_hidden_tm . tm_mon = = j - 1 ) ; } ) ;
2020-08-05 00:27:17 +00:00
std : : cout < < " <td style= \" --percent: " < < count * 100 / max < < " % \" ><span> " < < count < < " </span></td> " ;
}
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
}
2020-08-01 21:00:50 +00:00
// auto far = std::max_element(fcc.begin(), fcc.end(), [&](const Cache& a, const Cache& b) { return a.distance() < b.distance(); });
// auto near = std::min_element(fcc.begin(), fcc.end(), [&](const Cache& a, const Cache& b) { return a.distance() < b.distance(); });
2020-08-06 21:58:14 +00:00
//
2020-08-01 21:00:50 +00:00
// std::cout << "Nearest cache: " << near->distance() << " km\n";
// near->show();
// std::cout << "Furthest cache: " << far->distance() << " km\n";
// far->show();
2023-08-29 22:35:38 +00:00
show_histogram ( user . cc , & Cache : : type , " Cache types " , 1 ) ;
show_histogram ( user . cc , & Cache : : size , " Cache sizes " , 1 ) ;
show_nested_histogram ( user . fcc , & Cache : : region , & Cache : : subregion , " Regions " , 1 ) ;
2020-08-01 21:00:50 +00:00
2023-08-29 22:35:38 +00:00
auto N = * std : : max_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lat < b - > pos . lat ; } ) ;
auto S = * std : : min_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lat < b - > pos . lat ; } ) ;
auto E = * std : : max_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lon < b - > pos . lon ; } ) ;
auto W = * std : : min_element ( user . fcc . begin ( ) , user . fcc . end ( ) , [ & ] ( const Cache * a , const Cache * b ) { return a - > pos . lon < b - > pos . lon ; } ) ;
2020-08-01 21:00:50 +00:00
std : : cout < < " <h2>Geographically extreme caches</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr> \n " ;
std : : cout < < " <th>North:</th><td> " < < N - > link_name ( ) < < " </td><td> " < < N - > pos . lat < < " </td> \n " ;
std : : cout < < " </tr><tr> \n " ;
std : : cout < < " <th>South:</th><td> " < < S - > link_name ( ) < < " </td><td> " < < S - > pos . lat < < " </td> \n " ;
std : : cout < < " </tr><tr> \n " ;
std : : cout < < " <th>East:</th> <td> " < < E - > link_name ( ) < < " </td><td> " < < E - > pos . lon < < " </td> \n " ;
std : : cout < < " </tr><tr> \n " ;
std : : cout < < " <th>West:</th> <td> " < < W - > link_name ( ) < < " </td><td> " < < W - > pos . lon < < " </td> \n " ;
std : : cout < < " </tr> \n " ;
std : : cout < < " </table> \n " ;
2020-08-05 00:27:17 +00:00
const int LIST_MAX = 15 ;
n = 1 ;
std : : cout < < " <h2>Caches with most recommendations</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Rec.</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " <th>%</th> " ;
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_fav ) {
2020-08-05 00:27:17 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
std : : cout < < " <td> " < < i - > fav < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
2021-05-10 20:17:03 +00:00
if ( i - > founds > 0 )
std : : cout < < " <td> " < < std : : setprecision ( 3 ) < < 100.0 * i - > fav / i - > founds < < " %</td> " ;
else
std : : cout < < " <td>–</td> " ;
2020-08-05 00:27:17 +00:00
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2023-08-29 22:35:38 +00:00
average_html ( user . cc , & Cache : : fav , " number of recommendations " ) ;
sum_html ( user . cc , & Cache : : fav , " number of recommendations " ) ;
2020-08-05 00:27:17 +00:00
n = 1 ;
std : : cout < < " <h2>Caches with most recommendations (percentage)</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Rec.</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " <th>%</th> " ;
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_fav_perc ) {
2020-08-05 00:27:17 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
std : : cout < < " <td> " < < i - > fav < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
2021-05-10 20:17:03 +00:00
if ( i - > founds > 0 )
std : : cout < < " <td> " < < std : : setprecision ( 3 ) < < 100.0 * i - > fav / i - > founds < < " %</td> " ;
else
std : : cout < < " <td>–</td> " ;
2020-08-05 00:27:17 +00:00
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2022-07-14 12:47:15 +00:00
/*
2020-08-05 00:27:17 +00:00
n = 1 ;
2020-08-28 16:58:52 +00:00
std : : cout < < " <h2>Caches with highest rating</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Rating</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " </tr> \n " ;
2020-08-28 16:40:48 +00:00
for ( auto i : caches_by_rating ) {
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
std : : cout < < " <td> " < < i - > rating < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
average_html ( cc , & Cache : : rating , " rating " ) ;
2021-08-08 17:18:51 +00:00
*/
2020-08-28 16:40:48 +00:00
n = 1 ;
2020-08-05 00:27:17 +00:00
std : : cout < < " <h2>Caches with most finds</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i : user . caches_by_finds ) {
2020-08-05 00:27:17 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < i - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < i - > type < < " </td> " ;
std : : cout < < " <td> " < < i - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < i - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2023-08-29 22:35:38 +00:00
average_html ( user . cc , & Cache : : founds , " number of finds " ) ;
sum_html ( user . cc , & Cache : : founds , " number of finds " ) ;
2020-08-05 00:27:17 +00:00
n = 1 ;
std : : cout < < " <h2>Caches with least finds</h2> \n " ;
std : : cout < < " <table class= \" list \" > \n " ;
std : : cout < < " <tr><th></th> " ;
std : : cout < < " <th>Cache</th> " ;
std : : cout < < " <th>Type</th> " ;
std : : cout < < " <th>Date hidden</th> " ;
std : : cout < < " <th>Finds</th> " ;
std : : cout < < " </tr> \n " ;
2023-08-29 22:35:38 +00:00
for ( auto i = user . caches_by_finds . rbegin ( ) ; i ! = user . caches_by_finds . rend ( ) ; i + + ) {
2020-08-05 00:27:17 +00:00
std : : cout < < " <tr><th> " < < n < < " </th> " ;
std : : cout < < " <td> " < < ( * i ) - > link_name ( ) < < " </td> " ;
std : : cout < < " <td> " < < ( * i ) - > type < < " </td> " ;
std : : cout < < " <td> " < < ( * i ) - > date_hidden < < " </td> " ;
std : : cout < < " <td> " < < ( * i ) - > founds < < " </td> " ;
std : : cout < < " </tr> \n " ;
n + + ;
if ( n > LIST_MAX ) break ;
}
std : : cout < < " </table> \n " ;
2020-08-01 21:00:50 +00:00
// D/T matrix
n = 0 ;
std : : cout < < " <h2>Difficulty / terrain matrix</h2> \n " ;
std : : cout < < " <table class= \" dt \" > \n " ;
std : : cout < < " <tr><th></th> " ;
for ( int j = 2 ; j < = 10 ; j + + ) { // print table terr headers
std : : cout < < " <th> " < < j / 2.0 < < " </th> " ;
}
std : : cout < < " </tr> \n " ;
for ( int i = 2 ; i < = 10 ; i + + ) { // i -> diff in rows
std : : cout < < " <tr><th> " < < i / 2.0 < < " </th> " ;
for ( int j = 2 ; j < = 10 ; j + + ) { // j -> terr in cols
2023-08-29 22:35:38 +00:00
count = count_caches ( user . cc , codes , [ i , j ] ( const Cache & c ) - > bool { return ( c . diff = = i / 2.0 & & c . terr = = j / 2.0 ) ; } ) ;
2020-08-01 21:00:50 +00:00
if ( count = = 0 )
std : : cout < < " <td class= \" dt_zero \" > " < < 0 < < " </td> " ;
else {
2021-04-20 20:47:20 +00:00
std : : cout < < " <td codes= \" " < < codes < < " \" > " < < count < < " </td> " ;
2020-08-01 21:00:50 +00:00
n + + ;
}
}
std : : cout < < " </tr> \n " ;
}
std : : cout < < " </table> \n " ;
std : : cout < < " <div class= \" basic_stats \" > \n " ;
2021-05-10 20:17:03 +00:00
std : : cout < < " Total <span class= \" value \" > " < < n < < " </span> combinations created out of 81 ( " < < std : : setprecision ( 3 ) < < n / 0.81 < < " %).<br> \n " ;
2023-08-29 22:35:38 +00:00
std : : cout < < " Average difficulty: <span class= \" value \" > " < < average ( user . cc , & Cache : : diff ) < < " </span><br> \n " ;
std : : cout < < " Average terrain: <span class= \" value \" > " < < average ( user . cc , & Cache : : terr ) < < " </span><br> \n " ;
2020-08-01 21:00:50 +00:00
std : : cout < < " </div> \n " ;
} // end of "owned" if
2020-08-06 14:54:11 +00:00
footer_html ( ) ;
2019-09-08 16:42:10 +00:00
}