#!/usr/bin/ruby require 'libhttp' require 'libhtml' require 'sqlite3' class Cdm HTTPHST = 'nocmh.free.fr' GETURL = '/scripts/getCdm.php' DBFILE = '.mh_cache/cdmcoll.db' Seuil = %w[niv att esq deg arm vue mm rm dla].inject({'pv'=>200,'reg'=>10}) { |h, c| h.update c => 20 } # champs vides # * Blessures : l.utilisateur n.a pas souhaité communiquer cette information, # * Un champ minimum : la CdM comportait à cet endroit la clause « Supérieur à » sur cette donnée, # * Un champ maximum : la CdM comportait à cet endroit la clause « Inférieur à » sur cette donnée, # * Type de pouvoir : le monstre ne dispose pas de pouvoir particulier. def initialize(needupdate=false) @httpserver = HttpServer.new HTTPHST if File.exist? DBFILE @db = SQLite3::Database.new DBFILE update if needupdate else @db = SQLite3::Database.new DBFILE @db.execute_batch < min, :toId => max end def getlast(n) get :last => n end def update step = 2000 lastknown = @db.get_first_value('select max(cdmid) from cdm') || 999_999 lastknown = lastknown.to_i lastexist = getlast(1).first.to_i puts "have: #{lastknown}" puts "last: #{lastexist}" while lastexist > lastknown @db.transaction { @db.prepare('insert into cdm values (' + ['?'] * 40 * ', ' + ')') { |stmt| a = l = nil getrange(lastknown+1, lastknown+step).each { |l| a = l.chop.split(';', 40) Integer(a[0]) rescue break(p(l)) stmt.execute(*a) } } } lastknown = @db.get_first_value('select max(cdmid) from cdm').to_i puts "have: #{lastknown}" if lastexist > lastknown end puts "update finished" end def get_all(id, mincount=nil, &b) soup = 'and (select count(*) from cdm as cdm2 where cdm2.id == cdm.id) >= ' + mincount.to_s if mincount op = proc { |str| (str.count('_%') > 0) ? 'like' : '==' } case id when /(\d+) \[(.*)\]/ @db.execute("select * from cdm where id=? and age #{op[$2]} ? #{soup}", Integer($1), $2, &b) when /(\d+)/ @db.execute("select * from cdm where id=? #{soup}", Integer($1), &b) when /(.*) \[(.*)\]/ @db.execute("select * from cdm where nom #{op[$1]} ? and age #{op[$2]} ? #{soup}", $1, $2, &b) when /(.*)/ @db.execute("select * from cdm where nom #{op[$1]} ? #{soup}", $1, &b) end end end if $0 == __FILE__ mdelay = Time.now - File.stat(Cdm::DBFILE).mtime rescue nil cc = Cdm.new((true if not ARGV.delete('norefresh') and mdelay and (mdelay > 3600 or ARGV.delete('refresh') or ARGV.delete('update')))) if ARGV.first == 'query' cc.execute_sql(ARGV[1]) { |a| puts a.values.uniq.join(' | ') } exit end sums = {} unless ARGV.delete('nosum') onlyexact = true if not ARGV.delete('noexact') target = ARGV * ' ' onlyexact = (target.to_i.to_s != target and onlyexact) # compile most precise cdm by id/age cdmcount = 0 cc.get_all(target, 2) { |r| if sums cdmcount += 1 sum = sums[[r['id'],r['age']]] ||= {} %w[nom id age famille pouvoir blessures date vlc].each { |w| sum[w] = r[w] } %w[niv pv att esq deg reg arm vue].each { |w| wmax = w + '_max' wmin = w + '_min' next if not r[wmax] if r[wmax] == 0 next if r[wmin] == 0 seuil = Cdm::Seuil[w] if r[wmin] == 2 * seuil r[wmax] = 5000 elsif r[wmin] > seuil r[wmax] = 2 * seuil + 4 elsif r[wmin] == seuil r[wmax] = 4000 elsif r[wmin] < seuil r[wmax] = seuil+2 end end sum[wmin] = r[wmin] if not sum[wmin] or sum[wmin] < r[wmin] sum[wmax] = r[wmax] if not sum[wmax] or sum[wmax] > r[wmax] } else puts "#{Time.at(r['date']).strftime('%d/%m %H:%M')} #{r['nom']} [#{r['age']}] (#{r['id']}):", " famille: #{r['famille']}" puts %w[niv pv att esq deg reg arm vue].map { |c| " #{c.ljust(3)}: in #{r[c+'_min']}..#{r[c+'_max']}" } puts " blessures: #{r['blessures']}", " pouvoir: #{r['pouvoir']}", '' end } if sums puts "#{sums.length} monstres, #{cdmcount} cdm" total = {} exactcount = {} totalcount = {} # create range for name+age (precise) sums.each { |(id, age), r| name = "#{r['nom']} [#{r['age']}]" sum = total[name] ||= {} %w[pouvoir famille].each { |w| sum[w] = r[w] } %w[pv att esq deg reg arm vue].each { |w| next if not r[w+'_max'] if onlyexact totalcount[name] ||= Hash.new 0 exactcount[name] ||= Hash.new 0 totalcount[name][w] += 1 incert = r[w+'_max'] - r[w+'_min'] next if incert > (w == 'pv' ? 5 : 0) # ignore inexact exactcount[name][w] += 1 end sum[w+'_min'] ||= r[w+'_min'] sum[w+'_max'] ||= r[w+'_max'] sum[w+'_min'] = [r[w+'_min'], sum[w+'_min']].min sum[w+'_max'] = [r[w+'_max'], sum[w+'_max']].max } sum['niv_min'] ||= r['niv_min'] sum['niv_max'] ||= r['niv_max'] if r['niv_min'] == r['niv_max'] if r['niv_min'] >= sum['niv_min'] and r['niv_max'] <= sum['niv_max'] # wont work for niv changing less than most imprecise cdm incertitude (depending on the order) sum['niv_min'] = sum['niv_max'] = r['niv_min'] end end idcnt = {} sums.each { |(i_id, i_age), i_r| (idcnt["#{i_r['nom']} [#{i_r['age']}]"] ||= []) << i_id } if idcnt[name].uniq.length == 1 sum['blessures'] = r['blessures'] sum['date'] = r['date'] sum['id'] = r['id'] end } totalcount.each_key { |name| print " approx for #{name}:" totalcount[name].each_key { |w| ecount = exactcount[name][w] next if ecount > 100 or (ecount > 5 and ecount * 100 / totalcount[name][w] > 5) print " #{w}" sums.each { |(id, age), r| next if name != "#{r['nom']} [#{r['age']}]" next if not r[w+'_max'] sum = total[name] incert = r[w+'_max'] - r[w+'_min'] next unless incert > (w == 'pv' ? 5 : 0) # skip exact cdms if r[w+'_max'] == 4000 # cdm1 max seuil = Cdm::Seuil[w] r[w+'_max'] = seuil r[w+'_min'] = seuil*3 end sum[w+'_min'] ||= r[w+'_min'] sum[w+'_max'] ||= r[w+'_max'] sum[w+'_min'] = [r[w+'_min'], sum[w+'_min']].min sum[w+'_max'] = [r[w+'_max'], sum[w+'_max']].max } } puts } if onlyexact total.sort_by{|n, r| -r['niv_min']}.each { |n, r| puts "#{n}#{" (#{r['id']})" if r['id']}:", " famille: #{r['famille']}" #" puts %w[niv pv att esq deg reg arm vue].map { |c| " #{c.ljust(3)}: " + (r[c+'_min'] == r[c+'_max'] ? "#{r[c+'_min']}" : "in #{r[c+'_min']}..#{r[c+'_max']}") } puts " pouvoir: #{r['pouvoir']}" if r['blessures'] puts " blessures: #{r['blessures']}% le #{Time.at(r['date']).strftime('%d/%m %H:%M')}" puts " pv restant: #{r['pv_min'] * (95 - r['blessures']) / 100 - 1}..#{r['pv_max'] * (105 - r['blessures']) / 100 + 1}" end puts } end end