import * as tko from 'tko' ; import type { Observable } from 'tko' ; import { displayDialogMessage } from './records' ; import { MatchRecord , Updater , Character } from './records' ; import { Strategy , Lunatic , CoinToss , Chromosome , Scientist , Cowboy } from './strategy' ; import { Settings } from './settings' ; $ ( function ( ) { $ ( "body" ) . on ( "click" , "a" , function ( ) { chrome . tabs . create ( { url : $ ( this ) . attr ( "href" ) } ) ; return false ; } ) ; } ) ; $ ( function ( ) { document . querySelector < HTMLElement > ( "#bic" ) . onclick = function ( ) : void { document . querySelector < HTMLElement > ( "#upload_c" ) . click ( ) ; } ; document . querySelector < HTMLElement > ( "#bir" ) . onclick = function ( ) : void { document . querySelector < HTMLElement > ( "#upload_r" ) . click ( ) ; } ; } ) ; function btnClicked ( clicktype , data = null ) { data = data || null ; chrome . tabs . query ( { active : true , currentWindow : true , } , function ( tabs ) { chrome . tabs . sendMessage ( tabs [ 0 ] . id , { text : data , type : clicktype , } , function ( response ) { if ( response && response . farewell ) { console . log ( response . farewell ) ; } } ) ; } ) ; } function elementChanged ( changetype , data ) { btnClicked ( changetype , data ) ; } class ViewModel extends Settings { erClick ( ) { btnClicked ( "er" ) ; } ecClick ( ) { btnClicked ( "ec" ) ; } tvClick ( ) { btnClicked ( "tv" ) ; } taChange ( ) { const talimit = document . querySelector < HTMLInputElement > ( "#talimit" ) . value ; elementChanged ( "talimit_" + ( document . querySelector < HTMLInputElement > ( "#ta" ) . checked ? "enable" : "disable" ) , talimit ) ; } tmChange ( ) { const tmlimit = document . querySelector < HTMLInputElement > ( "#tmlimit" ) . value ; elementChanged ( "maximumBetAmount_" + ( document . querySelector < HTMLInputElement > ( "#tm" ) . checked ? "enable" : "disable" ) , tmlimit ) ; } limitChange ( ) { const limit = + document . querySelector < HTMLInputElement > ( "#limit" ) . value ; if ( ! limit ) { return ; } if ( limit < 1000 ) { return ; } elementChanged ( "limit_" + ( ( document . querySelector < HTMLInputElement > ( "#tl" ) . checked ) ? "enable" : "disable" ) , limit ) ; } multiplierChange ( ) { const multiplierValue = document . querySelector < HTMLInputElement > ( "#multiplierSlider" ) . value ; ( this . multiplier as Observable ) ( Number ( multiplierValue ) ) ; elementChanged ( "multiplier" , multiplierValue ) ; } setButtonActive ( identifier ) { document . querySelector ( "#cs_o" ) . classList . remove ( "active" ) ; document . querySelector ( "#cs_rc" ) . classList . remove ( "active" ) ; document . querySelector ( "#cs_cs" ) . classList . remove ( "active" ) ; document . querySelector ( "#cs_ipu" ) . classList . remove ( "active" ) ; $ ( identifier ) . addClass ( "active" ) ; } changeStrategyClickO ( ) { btnClicked ( "cs_o" ) ; this . setButtonActive ( "#cs_o" ) ; } changeStrategyClickCS ( ) { chrome . storage . local . get ( [ "chromosomes_v1" ] , results => { console . log ( results ) ; if ( Object . keys ( results ) . length === 0 ) { displayDialogMessage ( "Cannot change mode to Scientist without initializing chromosome pool\nPlease click 'Reset Pool'" ) ; } else { const data = JSON . stringify ( results . chromosomes_v1 [ 0 ] ) ; btnClicked ( "cs_cs" , data ) ; this . setButtonActive ( "#cs_cs" ) ; } } ) ; } changeStrategyClickRC ( ) { btnClicked ( "cs_rc" ) ; this . setButtonActive ( "#cs_rc" ) ; } changeStrategyClickIPU ( ) { btnClicked ( "cs_ipu" ) ; this . setButtonActive ( "#cs_ipu" ) ; } irClick ( ) { console . log ( "Attempting records import..." ) ; const files = document . querySelector < HTMLInputElement > ( "#upload_r" ) . files ; if ( files . length > 0 ) { console . log ( "Upload successful." ) ; } else { console . log ( "Upload canceled." ) ; } console . log ( "Attempting to read file..." ) ; const file = files [ 0 ] ; document . querySelector < HTMLInputElement > ( "#upload_r" ) . value = "" ; const reader = new FileReader ( ) ; reader . onload = onFileReadRecord ; reader . readAsText ( file ) ; } icClick ( ) { console . log ( "Attempting chromosome import..." ) ; const files = document . querySelector < HTMLInputElement > ( "#upload_c" ) . files ; if ( files . length > 0 ) { console . log ( "Upload successful." ) ; } else { console . log ( "Upload canceled." ) ; } console . log ( "Attempting to read file..." ) ; const file = files [ 0 ] ; document . querySelector < HTMLInputElement > ( "#upload_c" ) . value = "" ; const reader = new FileReader ( ) ; reader . onload = onFileReadChromosome ; reader . readAsText ( file ) ; } updateGeneticWeightsClick ( ) { simulator . evalMutations ( ) ; } resetPoolClick ( ) { simulator . initializePool ( ) ; } } function onFileReadRecord ( e ) { console . log ( "File read successful." ) ; const t = e . target . result ; btnClicked ( "ir" , t ) ; } function onFileReadChromosome ( e ) { console . log ( "File read successful." ) ; const t = e . target . result ; btnClicked ( "ic" , t ) ; } class Order { type : string ; chromosome : Chromosome ; constructor ( typeStr , chromosome ) { this . type = typeStr ; this . chromosome = chromosome ; } } class Simulator { private roundsOfEvolution = 0 ; money : number [ ] = [ ] ; minimum = 100 ; public evalMutations ( ) { chrome . storage . local . get ( [ "characters_v1" , "chromosomes_v1" ] , ( results ) => { let matches = [ ] ; chrome . runtime . sendMessage ( { query : "getMatchRecords" } , ( queryResult ) => { matches = queryResult ; if ( matches . length === 0 ) { console . log ( "No matches have been recorded yet." ) ; return ; } const data = [ ] ; const correct = [ ] ; const totalBettedOn = [ ] ; const strategies = [ ] ; const totalPercentCorrect = [ ] ; this . money = [ ] ; const updater = new Updater ( ) ; const orders = [ ] ; const chromosomes = results . chromosomes_v1 ; if ( chromosomes ) { for ( const cIt of chromosomes ) { const c = new Chromosome ( ) ; orders . push ( new Order ( "cs" , c . loadFromObject ( cIt ) ) ) ; } } else { const msg = "Pool not initialized." ; document . querySelector < HTMLInputElement > ( "#msgbox" ) . value = msg ; throw msg ; } for ( const order of orders ) { let strategy ; switch ( order . type ) { case "ct" : strategy = new CoinToss ( ) ; break ; case "cs" : strategy = new Scientist ( order . chromosome ) ; break ; case "rc" : strategy = new Cowboy ( ) ; break ; case "ipu" : strategy = new Lunatic ( ) ; break ; } strategy . debug = false ; data . push ( [ 0 , 0 ] ) ; correct . push ( 0 ) ; totalBettedOn . push ( 0 ) ; strategies . push ( strategy ) ; totalPercentCorrect . push ( 0 ) ; this . money . push ( 0 ) ; } const characterRecords = [ ] ; const namesOfCharactersWhoAlreadyHaveRecords = [ ] ; for ( const match of matches ) { const info = { character1 : updater . getCharacter ( match . c1 , characterRecords , namesOfCharactersWhoAlreadyHaveRecords ) , character2 : updater . getCharacter ( match . c2 , characterRecords , namesOfCharactersWhoAlreadyHaveRecords ) , matches , } ; const predictions = [ ] ; for ( const strategy of strategies ) { strategy . abstain = false ; predictions . push ( strategy . execute ( info ) ) ; } const actualWinner = ( match . w === 0 ) ? match . c1 : match . c2 ; updater . updateCharactersFromMatch ( match , info . character1 , info . character2 ) ; if ( strategies . length !== predictions . length ) { throw new Error ( "Strategies and predictions are not the same length." ) ; } for ( let k = 0 ; k < strategies . length ; k ++ ) { const prediction = predictions [ k ] ; const strategy = strategies [ k ] ; const predictionWasCorrect = prediction === actualWinner ; if ( ! strategy . abstain ) { correct [ k ] += ( predictionWasCorrect ) ? 1 : 0 ; totalBettedOn [ k ] += 1 ; totalPercentCorrect [ k ] = correct [ k ] / totalBettedOn [ k ] * 100 ; data [ k ] = [ totalBettedOn [ k ] , totalPercentCorrect [ k ] ] ; } if ( match . o !== "U" ) { strategy . adjustLevel ( 10000 ) ; const betAmount = this . getBetAmount ( strategy ) ; this . updateMoney ( k , match . o , prediction === match . c1 ? 0 : 1 , betAmount , predictionWasCorrect ) ; } } } const sortingArray = [ ] ; const parents = [ ] ; const nextGeneration = [ ] ; const money = true ; const accuracy = true ; const unshackle = true ; const weightAccToMoney = 0.75 ; for ( let l = 0 ; l < orders . length ; l ++ ) { let penalty = 1 ; if ( ! unshackle ) { penalty = this . applyPenalties ( orders [ l ] . chromosome ) ; } sortingArray . push ( [ orders [ l ] . chromosome , totalPercentCorrect [ l ] , this . money [ l ] , penalty ] ) ; } sortingArray . sort ( function ( a , b ) { if ( ! money && accuracy ) { return ( b [ 1 ] * b [ 3 ] ) - ( a [ 1 ] * a [ 3 ] ) ; } else if ( money && ! accuracy ) { return ( b [ 2 ] * b [ 3 ] ) - ( a [ 2 ] * a [ 3 ] ) ; } else { return ( ( ( weightAccToMoney * b [ 1 ] ) + ( ( 1 - weightAccToMoney ) * b [ 2 ] ) ) * b [ 3 ] ) - ( ( ( weightAccToMoney * a [ 1 ] ) + ( ( 1 - weightAccToMoney ) * a [ 2 ] ) ) * a [ 3 ] ) ; } } ) ; if ( sortingArray . length > 1 ) { for ( let o = 0 ; o < 10 ; o ++ ) { parents . push ( sortingArray [ o ] [ 0 ] ) ; sortingArray [ o ] [ 0 ] . rank = o + 1 ; nextGeneration . push ( sortingArray [ o ] [ 0 ] ) ; } for ( let o = 0 ; o < 10 ; o ++ ) { nextGeneration . push ( parents [ 0 ] . mate ( parents [ 0 ] ) ) ; } for ( let mf = 0 ; mf < 10 ; mf ++ ) { let parent1 = null ; let parent2 = null ; let child = null ; if ( mf === 0 ) { parent1 = parents [ 0 ] ; parent2 = parents [ parents . length - 1 ] ; } else if ( mf <= 4 ) { parent1 = parents [ 0 ] ; parent2 = parents [ mf ] ; } else { parent1 = parents [ mf - 1 ] ; parent2 = parents [ mf ] ; } child = parent1 . mate ( parent2 ) ; nextGeneration . push ( child ) ; } for ( let o = 0 ; o < 10 ; o ++ ) { nextGeneration . push ( new Chromosome ( ) . randomize ( ) ) ; } } else { nextGeneration . push ( sortingArray [ 0 ] [ 0 ] ) ; while ( nextGeneration . length < 40 ) { nextGeneration . push ( new Chromosome ( ) . randomize ( ) ) ; } } console . log ( sortingArray [ 0 ] [ 0 ] . toDisplayString ( ) + " -> " + sortingArray [ 0 ] [ 1 ] . toFixed ( 4 ) + "%,  $" + sortingArray [ 0 ] [ 2 ] . toString ( ) . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) ) ; const bestPercent = sortingArray [ 0 ] [ 1 ] ; const bestMoney = sortingArray [ 0 ] [ 2 ] ; chrome . storage . local . set ( { best_chromosome : sortingArray [ 0 ] [ 0 ] , chromosomes_v1 : nextGeneration , } , ( ) => { this . roundsOfEvolution += 1 ; console . log ( `\n\n-------- end of gen${ nextGeneration . length }  ${ this . roundsOfEvolution }, m proc'd w/ CS ` + `${ totalBettedOn [ 0 ] }/${ matches . length }=${ ( totalBettedOn [ 0 ] / matches . length * 100 ) . toFixed ( 2 ) }%m -> ` + `${ bestPercent . toFixed ( 1 ) }%c, $${ sortingArray [ 0 ] . toString ( ) . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) }   -----------------\n\n` ) ; document . querySelector < HTMLInputElement > ( "#msgbox" ) . value = `g(${ this . roundsOfEvolution }), best: ${ bestPercent . toFixed ( 1 ) }%, $${ bestMoney . toFixed ( 0 ) }` ; setTimeout ( ( ) => { this . evalMutations ( ) ; } , 5000 ) ; } ) ; } ) ; } ) ; } public initializePool ( ) { const populationSize = 32 ; const pool = [ ] ; while ( pool . length < populationSize ) { pool . push ( new Chromosome ( ) . randomize ( ) ) ; } const newPool = [ ] ; for ( let i = 0 ; i < pool . length ; i ++ ) { if ( i % 1 === 0 ) { console . log ( `:: ${ i }\n${ pool [ i ] . toDisplayString ( ) }` ) ; } newPool . push ( pool [ i ] ) ; } chrome . storage . local . set ( { chromosomes_v1 : newPool , } , function ( ) { const msgBox = document . querySelector ( "#msgbox" ) ; msgBox . value = "initial pool population complete" ; } ) ; } private updateMoney ( index , odds , selection , amount , correct ) { const oddsArr = odds . split ( ":" ) ; if ( ! correct ) { this . money [ index ] -= amount ; } else { if ( selection === 0 ) { this . money [ index ] += amount * Number ( oddsArr [ 1 ] ) / Number ( oddsArr [ 0 ] ) ; } else if ( selection === 1 ) { this . money [ index ] += amount * Number ( oddsArr [ 0 ] ) / Number ( oddsArr [ 1 ] ) ; } } } private getBetAmount ( strategy ) { let amountToBet ; const tournament = false ; const debug = true ; const balance = 10000 ; if ( ! strategy . confidence ) { amountToBet = Math . ceil ( balance * .1 ) ; } else { amountToBet = strategy . getBetAmount ( balance , tournament , debug ) ; } return amountToBet ; } private applyPenalties ( _c ) { console . log ( "called: applyPenalties. Is undefined." ) ; return 1 ; } } const simulator = new Simulator ( ) ; const settings = new ViewModel ( ) ; document . addEventListener ( "DOMContentLoaded" , function ( ) { chrome . storage . local . get ( "settings_v1" , function ( result ) { if ( result . settings_v1 ) { for ( const prop in result . settings_v1 ) { if ( settings . hasOwnProperty ( prop ) ) { settings [ prop ] = tko . observable ( result . settings_v1 [ prop ] ) ; } } tko . applyBindings ( settings ) ; settings . setButtonActive ( "#cs_" + result . settings_v1 . nextStrategy ) ; } } ) ; chrome . alarms . create ( "chromosome update" , { delayInMinutes : 0.1 , periodInMinutes : 1.0 , } ) ; } ) ;