La strategia A, dai numeri dei dossier: 5410 aste, 2,08 milioni di puntate. Bidoo dichiara per ogni puntata se e' automatica o manuale. Le automatiche sono il 75,3% del totale ma vincono il 46,0% delle aste; le manuali sono il 24,7% e ne vincono il 53,9%. Una puntata manuale vale 3,6 volte una automatica: 178 puntate per vittoria contro 634. Il meccanismo del duello e' stato ricostruito esattamente. L'intervallo mediano fra due puntate consecutive e' 6,0 s su 2.799.681 intervalli: il timer si azzera a ~8 s e l'autopuntata scatta a 2 s, quindi 8-2=6. Il ciclo da 13,0 s osservato nelle prove reali era la somma di 7 s di attesa nostra e 6 s della sua risposta. Puntare tardi non evita l'autopuntata avversaria: la sveglia, perche' si riarma quando il suo padrone perde la testa della classifica, non a un orario fisso. Contro una macchina cosi' non esiste attrito vincibile. Adesso il motore conta le risposte con la firma dei 6+/-2,5 s e dopo cinque di fila smette di puntare su quell'asta. Una risposta fuori firma azzera il conteggio invece di scalarlo: l'errore costoso e' ritirarsi da un'asta che si poteva vincere, non spendere cinque puntate di troppo. Rigiocato sui dossier veri in cui il bot ha puntato: 366 puntate spese, 13 aste, zero vittorie. Con la regola a soglia 3 sarebbero state 31 puntate, 335 risparmiate (91,5%), nessuna vittoria persa. L'anticipo passa da 1000 a 500 ms. Le due ragioni per stare larghi sono cadute: il p99,9 del ping a 444 ms era misurato col tetto di 40 richieste al secondo che accodava le chiamate, e senza tetto il ping sta fra 47 e 78 ms; e la concorrenza sotto i due secondi non e' fitta ma rada, visto che tre quarti degli avversari sono autopuntate che hanno gia' sparato. Il tipo di puntata non viene piu' inventato. In due punti il motore ricostruiva una puntata da un cambio di prezzo fra due interrogazioni e la marcava "Auto" comunque: adesso quelle portano un trattino, perche' il tipo non lo ha detto nessuno. La colonna in cronologia mostra quindi solo tipi dichiarati dal server. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
81 lines
4.4 KiB
C#
81 lines
4.4 KiB
C#
using System;
|
||
|
||
namespace AutoBidder.Utilities
|
||
{
|
||
/// <summary>
|
||
/// Riconosce l'avversario che ha l'autopuntata di Bidoo armata, e dice quando smettere.
|
||
///
|
||
/// <para><b>Il meccanismo.</b> L'autopuntata del sito scatta a 2 secondi dalla chiusura,
|
||
/// e si riarma ogni volta che il suo padrone non è più in testa. Il timer si azzera
|
||
/// intorno agli 8 secondi, quindi la risposta arriva circa 6 secondi dopo la puntata che
|
||
/// l'ha svegliata. Misurato su 2.799.681 intervalli fra puntate consecutive in 5037 aste:
|
||
/// mediana <b>6,0 s</b>, primo quartile 5,3 s, terzo quartile 7,1 s.</para>
|
||
///
|
||
/// <para><b>Perché serve ritirarsi.</b> Contro un'autopuntata armata non esiste attrito
|
||
/// che si possa vincere: risponde sempre, risponde in sei secondi, non dorme e non si
|
||
/// distrae. Puntare di nuovo significa comprare un altro giro di sei secondi al prezzo
|
||
/// di una puntata a testa, all'infinito, finché uno dei due esaurisce il credito. Nelle
|
||
/// prove reali sono state 191 puntate su tre aste per zero vittorie, con un ciclo
|
||
/// perfettamente regolare da 13,0 secondi: 7 di attesa nostra più 6 della loro risposta.</para>
|
||
///
|
||
/// <para><b>Perché non basta puntare tardi.</b> Puntare a un secondo dalla chiusura non
|
||
/// evita l'autopuntata avversaria: la sveglia. Lei scatta quando il suo padrone perde la
|
||
/// testa della classifica, non a un orario fisso, quindi ogni nostra puntata tardiva è
|
||
/// esattamente ciò che la fa ripartire.</para>
|
||
///
|
||
/// <para>Classe pura, senza stato e senza orologio: prende i numeri e restituisce un
|
||
/// giudizio. Così la stessa identica logica serve il motore dal vivo e la rigiocata sui
|
||
/// dossier, senza due versioni che divergono.</para>
|
||
/// </summary>
|
||
public static class AutoBidDuel
|
||
{
|
||
/// <summary>Ritardo tipico della risposta automatica, in secondi.</summary>
|
||
public const double RispostaTipicaSecondi = 6.0;
|
||
|
||
/// <summary>
|
||
/// Quanto ci si allontana dai 6 secondi continuando a chiamarla automatica.
|
||
/// Coincide grosso modo con l'intervallo fra primo e terzo quartile misurati
|
||
/// (5,3–7,1 s), allargato per la latenza di rete e per l'imprecisione del polling.
|
||
/// </summary>
|
||
public const double TolleranzaSecondi = 2.5;
|
||
|
||
/// <summary>
|
||
/// Risposte automatiche di fila oltre le quali si smette. Cinque perché è il punto in
|
||
/// cui la coincidenza smette di essere credibile: cinque intervalli indipendenti
|
||
/// dentro la finestra dei 6±2,5 s non capitano per caso, e cinque puntate sono un
|
||
/// prezzo che si può pagare per avere la certezza.
|
||
/// </summary>
|
||
public const int RispostePerConcludere = 5;
|
||
|
||
/// <summary>
|
||
/// Questo intervallo ha la firma della risposta automatica?
|
||
/// </summary>
|
||
public static bool ERispostaAutomatica(double secondiDopoLaMiaPuntata) =>
|
||
secondiDopoLaMiaPuntata > 0 &&
|
||
Math.Abs(secondiDopoLaMiaPuntata - RispostaTipicaSecondi) <= TolleranzaSecondi;
|
||
|
||
/// <summary>
|
||
/// Il conteggio aggiornato dopo aver visto una risposta avversaria.
|
||
///
|
||
/// <para>Una risposta che <b>non</b> ha la firma azzera il conteggio invece di
|
||
/// scalarlo: serve una sequenza pulita per concludere che c'è una macchina
|
||
/// dall'altra parte, e un solo intervallo umano in mezzo basta a rimettere tutto in
|
||
/// discussione. È la scelta prudente, perché l'errore costoso è ritirarsi da
|
||
/// un'asta che si poteva vincere.</para>
|
||
/// </summary>
|
||
public static int Aggiorna(int consecutiveFinora, double secondiDopoLaMiaPuntata) =>
|
||
ERispostaAutomatica(secondiDopoLaMiaPuntata) ? consecutiveFinora + 1 : 0;
|
||
|
||
/// <summary>
|
||
/// Si è capito che dall'altra parte c'è un'autopuntata armata?
|
||
/// </summary>
|
||
public static bool DuelloRiconosciuto(int consecutive, int soglia = RispostePerConcludere) =>
|
||
consecutive >= Math.Max(1, soglia);
|
||
|
||
/// <summary>Come spiegarlo nel registro, in una riga.</summary>
|
||
public static string Spiegazione(int consecutive) =>
|
||
$"autopuntata avversaria riconosciuta: {consecutive} risposte di fila a ~{RispostaTipicaSecondi:N0}s. " +
|
||
"Continuare significa scambiare puntate una a una con una macchina che non si stanca.";
|
||
}
|
||
}
|