Chrome, Firefox, Opera 15+

Email: al_d@online.ua

Skype: dying_escape

This is random pointless page with league simulation. Games are based on Iterated prisoner's dilemma. One team uses strategy which may be updated via Editor tab.

Project is made in JavaScript (jQuery). Scripts:

Main functions in file sport.js are next: initWorld, createTeamList, runSeason, runGame.

Idea is next

Note Objects in other objects are stored via pointers. Thus, for example, League[0].games[0].team[0] and League[0].standings[0].team do not store separate copies of items from teams array.

Project can be stored and modified locally (attention to the template elements in HTML-code).

Variable Value
Number of leagues leagueLevelQ
Number of teams in league leagueTeamQ
Number of teams in promotion/relegation zone exchangeTeamQ

League points

Variable Value
Win points.w
Draw points.d

Points per decision pairs

Defection (D) Cooperation (C)
Defection (D) ipdPoints[0][0] ipdPoints[0][1]
Cooperation (C) ipdPoints[1][0] ipdPoints[1][1]

Other settings


Team sorting parameters for league standings

points — points, w — wins, gd — goal difference, gf — goals for.


    Write the function userfunc which returns 0 (defect) or 1 (cooperate). This function will be used by one of the teams as strategy in game (userfunc in righthand column in standings). this.memory stores the decisions of opponent. Each new decision of an opponent is always added to the beginning of this.memory array. See strategy.js for examples of strategies and usage of this.memory.
    
    				

    (Put it in work and in local storage.)
    Team Strategy Level
    // al_d@ukr.net
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    
    var cooperate = 1
    var defect = 0
    
    // Array of strategies
    // StrategyName: Function which must set tactics of a given team in its next game
    // "this" in strategy functions refers to a team which calls it
    var strategies = {
    	userfunc: userfunc,
    	random: function() {
    		// Random decision to cooperate or defect
    		return Math.floor(Math.random() * 2)
    	},
    	sucker: function() {
    		// Always cooperate
    		return cooperate
    	},
    	evil: function() {
    		// Always defect
    		return defect
    	},
    	tit4tat: function() {
    		// Start from cooperate. Then copy the last decision of the opponent
    		var m = typeof this.memory[0] === 'undefined' ? cooperate : this.memory[0]
    		return m // ? cooperate : defect
    	},
    	tit4twotats: function() {
    		// Start from cooperate. Then cooperate if the last two decisions of the opponent were not defect
    		var m1 = typeof this.memory[0] === 'undefined' ? cooperate : this.memory[0]
    		var m2 = typeof this.memory[1] === 'undefined' ? cooperate : this.memory[1]
    		return (m1 + m2) ? cooperate : defect
    	},
    }
    // Author: Oleksa Vyshnivsky a.k.a ODE
    // al_d@ukr.net
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // GLOBAL VARIABLES AND SETTINGS
    var seasonCalculationOn = false // Shows if the calculation of season is currently running
    var season = 0			// Current season
    var teams = []			// Holder of teams
    var League = []			// Holder of all Association data (except teams)
    var leagueLevelQ = 3	// Number of levels in Association
    var leagueTeamQ = 10 	// Number of teams in league
    var exchangeTeamQ = 2 	// Number of teams in one promotion or relagation zone
    
    // Points
    var points = {
    	w: 3,
    	ow: 2,
    	d: 1,
    	ol: 1,
    	l: 0
    }
    
    // Parameters for sorting the teams in league
    var leagueSortingParameters = [
    	'points',
    	'gd',
    	'gf',
    	'w',
    ]
    
    // Points per decision [[DD, DC, CD, CC]]
    var ipdPoints = [[1, 3], [0, 2]]
    
    // Number of rounds in game
    var roundsMin = 50
    var roundsMax = 99
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // GENERAL LEAGUE ACTIONS
    function createTeamList() {
    	// Used for setting
    	var strategiesKeys = Object.keys(strategies)
    	// Total number of teams
    	var teamQ = leagueLevelQ * leagueTeamQ
    	// Array of teams
    	teams = []
    	// Basic team data
    	for (var t = 0; t < teamQ; t++) {
    		// Random strategy for the given team
    		var strategyKey = strategiesKeys[getRandomInt(1, strategiesKeys.length - 1)]
    
    		teams.push({
    			name: 'Team ' + (t + 1),			// Generic team names
    			strategyName: strategyKey,			// Just a key for easier reference to the name of used strategy
    			decision: strategies[strategyKey], // Strategy for setting a tactic before each game
    			memory: [],
    			titles: 0,							// Just the number of titles (1st places in League 1 only at this moment)
    			level: 0
    		})
    	}
    	teams[teamQ - 1].strategyName = strategiesKeys[0]
    	teams[teamQ - 1].decision = strategies[strategiesKeys[0]]
    	// Downloading a bit more interesting team names
    	$.ajax({
    		async: false,
    		method: 'GET',
    		url: $('#birdnames').attr('href'),
    		data: {n: teamQ}
    	}).done(function(response) {
    		// Response is in json format if requested via jquery ajax. Otherwise it's in plain text format (which is not used here)
    		try {
    			var names = JSON.parse(response)
    			for (var t = 0; t < teamQ; t++) {
    				teams[t].name = names[t]
    			}
    		} catch (e) {}
    	})
    }
    
    function createLeagueStructure() {
    	League = []
    	for (var level = 0; level < leagueLevelQ; level++) {
    		// Create league level
    		var league = {
    			level: level + 1,
    			teams: [],
    			games: [],
    			standings: []
    		}
    		// Select teams for this league
    		for (var t = 0; t < leagueTeamQ; t++) {
    			league.teams.push(teams[level * leagueTeamQ + t])
    		}
    
    		League.push(league)
    	}
    }
    
    function makeLeagueSchedule(league) {
    	// Round up a number of teams in league to a closest even number
    	var pseudoTeamsQ = leagueTeamQ + leagueTeamQ % 2
    
    	// Number of rounds (game days) in one round-robin go
    	var roundQ = Math.ceil(leagueTeamQ / 2) * 2 - 1
    
    	// List of numbers which correspond to teams in league
    	// Means: Flat list of teams which will be separated into team pairs in the second part of this function
    	var teamRoundList = []
    
    	// First round — the simpliest list of teams: 0, 1, 2, ..., LastTeamN
    	// This means next matches: Team 0 — Team 1; 2 — 3; ...; (LastTeamN - 1) — LastTeamN
    	// Note: LastTeamN = pseudoTeamsQ - 1
    	var round = 1
    	teamRoundList[round] = []
    	for (var i = 0; i < pseudoTeamsQ; i++) teamRoundList[round].push(i)
    
    	// Next rounds
    	for (var round = 2; round < roundQ + 1; round++) {
    		teamRoundList[round] = []
    		// First team is fixed
    		teamRoundList[round].push(0)
    		// Next teams are moved like clockwise in the game list
    		// Example: If the games of previous round are these:
    		//  0 — 1; 2 — 3; 4 — 5; 6 — 7
    		// than the games of given round will be these:
    		//  0 — 2; 4 — 1; 6 — 3; 7 — 5
    		// where team 0 is fixed team, team 2 goes to position 1, team LastTeamN goes to position (LastTeamN - 1),
    		// team Even goes to position (Even – 2), team Odd goes to position (Odd + 2)
    		for (var i = 1; i < pseudoTeamsQ; i++) {
    			var iOld = teamRoundList[round - 1][i]
    			if (iOld == pseudoTeamsQ - 1) iNew = pseudoTeamsQ - 2
    			else if (iOld == 2) iNew = 1
    			else iNew = iOld % 2 ? iOld + 2 : iOld - 2
    			teamRoundList[round].push(iNew)
    		}
    	}
    
    	// Game list
    	league.games = []
    	for (var round = 1; round < roundQ + 1; round++) {
    		for (var i = 0; i < pseudoTeamsQ; i += 2) {
    			// Pairs of teams in flat list — teamRoundList[round] — are separated into matches
    			// In odd rounds, first team in pair is host, and the second one is guest
    			// In even rounds, second team in pair is host, and the first one is guest
    			var homeTeamId = teamRoundList[round][i + 1 - round % 2]
    			var awayTeamId = teamRoundList[round][i + round % 2]
    
    			// Check if this is not a bye (in case of odd number of teams in league)
    			if (homeTeamId < leagueTeamQ && awayTeamId < leagueTeamQ) {
    				league.games.push({
    					round: round,
    					// Home and away teams
    					team: [league.teams[homeTeamId], league.teams[awayTeamId]],
    					// Goals of home and away teams
    					score: [0, 0],
    					// Status: played — 0 (no) or 1 (yes)
    					played: 0,
    					// Status: overtime — 0 (no) or 1 (yes)
    					overtime: 0,
    				})
    			}
    		}
    	}
    }
    
    function playLeagueGames(league) {
    	league.games.forEach(runGame)
    }
    
    function makeLeagueStandings(league) {
    	// Initial standings
    	league.standings = []
    
    	// Going through all teams in league
    	league.teams.forEach(function(team, t) {
    		team.level = league.level
    		// Datarow of the given team in league table
    		var standingsRow = {
    			team: team,
    			w: 0,
    			ow: 0,
    			ol: 0,
    			d: 0,
    			l: 0,
    			gf: 0,
    			ga: 0,
    			points: 0
    		}
    		// Look through home and away games
    		for (var isAway = 0; isAway < 2; isAway++) {
    			league.games.filter(function(a) { return a.team[isAway] == team }).forEach(function(game, g) {
    				// Wins and losses
    				if (game.score[isAway] > game.score[1 - isAway]) {
    					if (game.overtime) standingsRow.ow++
    					else standingsRow.w++
    				} else if (game.score[isAway] < game.score[1 - isAway]) {
    					if (game.overtime) standingsRow.ol++
    					else standingsRow.l++
    				} else standingsRow.d++
    				// Goals
    				standingsRow.gf += game.score[isAway]
    				standingsRow.ga += game.score[1 - isAway]
    			})
    		}
    		// Goal difference
    		standingsRow.gd = standingsRow.gf - standingsRow.ga
    		// Points
    		standingsRow.points = points.w * standingsRow.w + points.ow * standingsRow.ow + points.d * standingsRow.d + points.ol * standingsRow.ol
    
    		// Adding the team datarow to the league table
    		league.standings.push(standingsRow)
    	})
    
    	// Sorting of league table
    	league.standings.sort(sortStandings)
    }
    
    function sortStandings(a, b) {
    	// Sort the teams in league standings by leagueSortingParameters:
    	var response = 0
    	$.each(leagueSortingParameters, function(i, f) {
    		response = b[f] - a[f]
    		if (response) return false
    	})
    
    	return response
    }
    
    function doPromotionsRelegations() {
    	for (var level = 0; level < leagueLevelQ; level++) {
    		// Empty list of teams at a given level
    		League[level].teams = []
    		// Teams relegated from a league above
    		for (var i = 0; i < (level ? exchangeTeamQ : 0); i++) {
    			League[level].teams.push(
    				League[level - 1].standings[leagueTeamQ - exchangeTeamQ + i].team
    			)
    		}
    		// Middle zone of a given league
    		for (var i = (level ? exchangeTeamQ : 0); i < (level == leagueLevelQ - 1 ? leagueTeamQ : leagueTeamQ - exchangeTeamQ); i++) {
    			League[level].teams.push(
    				League[level].standings[i].team
    			)
    		}
    		// Teams promoted from a league below
    		for (var i = (level == leagueLevelQ - 1 ? exchangeTeamQ : 0); i < exchangeTeamQ; i++) {
    			League[level].teams.push(
    				League[level + 1].standings[i].team
    			)
    		}
    		// Shuffle the teams in league 
    		// Though, it's not the most needed action, as an order of team in standings is already not like an original order of teams in league
    		// League[level].teams.sort(shuffle)
    	}
    }
    
    function seasonReset() {
    	var strategiesKeys = Object.keys(strategies)
    
    	// Teams (except teams with "user function") from relegation zone of the lowest league change their strategies
    	for (var t = leagueTeamQ - 1; t > leagueTeamQ - 1 - exchangeTeamQ; t--) {
    		var strategyKey = strategiesKeys[getRandomInt(1, strategiesKeys.length - 1)]
    
    		if (League[leagueLevelQ - 1].standings[t].team.strategyName !== 'userfunc') {
    			League[leagueLevelQ - 1].standings[t].team.strategyName = strategyKey
    			League[leagueLevelQ - 1].standings[t].team.decision = strategies[strategyKey]
    		}
    	}
    
    	// Renew teams editor
    	makeTeamControls()
    }
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // DISPLAY THE RESULTS
    function showSeasonStatistics() {
    	// General season wrapper
    	var html = $('#tpl-season').html().replace(/%season%/g, season)
    	$('#seasonalStatistics').prepend(html)
    
    	// Deleting old history
    	if ($('#seasonalStatistics .season-wrapper').length > 100) {
    		$('#seasonalStatistics .season-wrapper').slice(50).remove()
    	}
    
    	// League wrapper
    	for (var league = 1; league < leagueLevelQ + 1; league++) {
    		var html = $('#tpl-league').html().replace(/%season%/g, season).replace(/%league%/g, league)
    		$('#S' + season).append(html)
    
    		// Games wrapper
    		showLeagueGames(League[league - 1])
    		
    		// Standings wrapper
    		showLeagueStandings(League[league - 1])
    	}
    
    	// Refreshing jQuery UI accordion, activation of the panel of last season
    	$('#seasonalStatistics').accordion('refresh')
    	$('#seasonalStatistics').accordion('option', 'active', 0)
    
    	showGames()
    	showStandings()
    }
    
    function showLeagueGames(league) {
    	// Show the table of games of the given league
    	var tpl = $('#tpl-game').html()
    	var tplSeparator = $('#tpl-round-separator').html()
    	var html = ''
    	var prevRound = 0 // For round separator
    	league.games.forEach(function(game, g) {
    		if (prevRound != game.round) html += tplSeparator.replace(/%round%/g, game.round)
    
    		var teamdata = ['', '']
    		for (var i = 0; i < 2; i++) teamdata[i] = game.stat.t[i] + '\n'
    
    		var gamedata = 'DD: ' + game.stat.s[0][0]
    			+ '; DC: ' + game.stat.s[0][1]
    			+ '; CD: ' + game.stat.s[1][0]
    			+ '; CC: ' + game.stat.s[1][1]
    
    		html += tpl.replace(/%round%/g, game.round)
    			.replace(/%hometeam%/g, game.team[0].name)
    			.replace(/%awayteam%/g, game.team[1].name)
    			.replace(/%homegoals%/g, game.score[0])
    			.replace(/%awaygoals%/g, game.score[1])
    			.replace(/%ot%/g, game.overtime ? 'OT' : '')
    			.replace(/%hometeamdata%/g, teamdata[0])
    			.replace(/%awayteamdata%/g, teamdata[1])
    			.replace(/%gamedata%/g, gamedata)
    
    		prevRound = game.round
    	})
    	$('#S' + season + '-L' + league.level + '-games tbody').html(html)
    }
    
    function showLeagueStandings(league) {
    	// Show the standings of the given league
    	var tpl = $('#tpl-standings').html()
    	var html = ''
    	league.standings.forEach(function(row, r) {
    		var trClass = r == 0 ? 'promotion champion' 
    			: r < exchangeTeamQ ? 'promotion'
    			: r >= leagueTeamQ - exchangeTeamQ ? 'relegation' : ''
    
    		html += tpl.replace(/%trClass%/g, trClass)
    			.replace(/%pos%/g, r + 1)
    			.replace(/%team%/g, row.team.name + (row.team.titles ? ' ' + row.team.titles + "Ψ" : ''))
    			.replace(/%w%/g, row.w)
    			.replace(/%ow%/g, row.ow)
    			.replace(/%d%/g, row.d)
    			.replace(/%ol%/g, row.ol)
    			.replace(/%l%/g, row.l)
    			.replace(/%gf%/g, row.gf)
    			.replace(/%ga%/g, row.ga)
    			.replace(/%gd%/g, row.gf - row.ga)
    			.replace(/%pts%/g, row.points)
    			.replace(/%other%/g, row.team.strategyName)
    	})
    	$('#S' + season + '-L' + league.level + '-standings tbody').html(html)
    }
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // WORLD AND SEASONS
    function initWorld() {
    	// Season 0 — team list and league structure have to be created
    	season = 0
    	createTeamList()
    	createLeagueStructure()
    	// Previous results have to be deleted
    	$('#seasonalStatistics').html('')
    }
    function runSeason() {
    	// Just in case of parallel run
    	if (seasonCalculationOn) return false
    	seasonCalculationOn = true
    
    	season++
    	for (var level = 0; level < leagueLevelQ; level++) {
    		// Actions inside each league: Schedule, games, standings
    		var league = League[level]
    		makeLeagueSchedule(league)
    		playLeagueGames(league)
    		makeLeagueStandings(league)
    	}
    	// Title counter
    	League[0].standings[0].team.titles++
    
    	// Statistics and team exchange
    	showSeasonStatistics()
    	doPromotionsRelegations()
    
    	seasonReset()
    
    	seasonCalculationOn = false
    }
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // WHEN THE DOCUMENT IS READY
    // $(function() {
    // 	initWorld()
    // 	runSeason()
    // })
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // MINI FUNCTIONS
    // For array shuffling
    function shuffle(){
        return 0.5 - Math.random()
    }
    // Random integer within the range [min, max] (range includes both limits)
    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min
    }
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // TEAM CONTROLS
    function makeTeamControls() {
    	var tpl = $('#tpl-team-strategy').html()
    	var html = ''
    	teams.forEach(function(team, t) {
    		var options = ''
    		Object.keys(strategies).forEach(function(key) {
    			var selected = key == team.strategyName ? 'selected' : ''
    			options += ''
    		})
    
    		html += tpl.replace(/%team-name%/g, team.name)
    			.replace(/%team-id%/g, t)
    			.replace(/%options%/g, options)
    			.replace(/%level%/g, team.level)
    	})
    	$('#teams tbody').html(html)
    }
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // GAME FUNCTION 
    function runGame(game) {
    	// Statistics — preparation
    	game.stat = {
    		s: [[0, 0], [0, 0]], // number of decisions of each type
    		t: [game.team[0].strategyName, game.team[1].strategyName]
    	}
    	// "Fight" starts with empty memories of both opponents
    	game.team[0].memory = []
    	game.team[1].memory = []
    	var rounds = getRandomInt(roundsMin, roundsMax)
    	for (var r = 0; r < rounds; r++) {
    		var d1 = game.team[0].decision()
    		var d2 = game.team[1].decision()
    		if (d1 !== 0 && d1 !== 1) d1 = getRandomInt(0, 1)
    		if (d2 !== 0 && d2 !== 1) d2 = getRandomInt(0, 1)
    		game.score[0] += ipdPoints[d1][d2]
    		game.score[1] += ipdPoints[d2][d1]
    		game.team[0].memory.unshift(d2)
    		game.team[1].memory.unshift(d1)
    		// Statistics
    		game.stat.s[d1][d2]++
    	}
    
    	// Status "game is played"
    	game.played = 1
    }
    // Author: Oleksa Vyshnivsky a.k.a ODE
    // al_d@ukr.net
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    
    // Iterational calculation
    var intervalId = null
    var timeStep = 60
    
    // ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
    // Active correction of variables
    function makeControlForm() {
    	$('#points-w').val(points.w)
    	// $('#points-ow').val(points.ow)
    	$('#points-d').val(points.d)
    	// $('#points-ol').val(points.ol)
    	// $('#points-l').val(points.l)
    
    	$('#ipdPoints-0-0').val(ipdPoints[0][0])
    	$('#ipdPoints-0-1').val(ipdPoints[0][1])
    	$('#ipdPoints-1-0').val(ipdPoints[1][0])
    	$('#ipdPoints-1-1').val(ipdPoints[1][1])
    
    	$('#roundsMin').val(roundsMin)
    	$('#roundsMax').val(roundsMax)
    
    	$.each(leagueSortingParameters, function(i, parameter) {
    		$('#leagueSortingParameters').append('
  • ' + parameter + '
  • ') }) $('#timeStep').val(timeStep) } function readControlForm() { points.w = parseInt($('#points-w').val()) // points.ow = parseInt($('#points-ow').val()) points.d = parseInt($('#points-d').val()) // points.ol = parseInt($('#points-ol').val()) // points.l = parseInt($('#points-l').val()) ipdPoints[0][0] = parseInt($('#ipdPoints-0-0').val()) ipdPoints[0][1] = parseInt($('#ipdPoints-0-1').val()) ipdPoints[1][0] = parseInt($('#ipdPoints-1-0').val()) ipdPoints[1][1] = parseInt($('#ipdPoints-1-1').val()) roundsMin = parseInt($('#roundsMin').val()) roundsMax = parseInt($('#roundsMax').val()) } function readleagueSortingParameters() { leagueSortingParameters = [] $('#leagueSortingParameters li').each(function() { leagueSortingParameters.push($(this).text().trim()) }) } function readTimeStep() { timeStep = parseInt($('#timeStep').val()) // clearInterval(intervalId) // intervalId = setInterval(runSeason, timeStep * 1000) } // ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— // Simulation controls function initSimulationControls() { $('#simulation-new').attr('disabled', false) $('#simulation-season').attr('disabled', true) $('#simulation-auto').attr('disabled', true) $('#simulation-stop').attr('disabled', false) $('#simulation-new').click(initWorldWrapper) $('#simulation-season').click(runSeason) $('#simulation-auto').click(autoRun) $('#simulation-stop').click(stopAutoRun) } function initWorldWrapper() { readWorldSettings() initWorld() runSeason() makeTeamControls() $('#simulation-new').attr('disabled', false) $('#simulation-season').attr('disabled', false) $('#simulation-auto').attr('disabled', false) $('#simulation-stop').attr('disabled', true) } function autoRun() { runSeason() intervalId = setInterval(runSeason, timeStep * 1000) $('#simulation-new').attr('disabled', true) $('#simulation-season').attr('disabled', true) $('#simulation-auto').attr('disabled', true) $('#simulation-stop').attr('disabled', false) } function stopAutoRun() { clearInterval(intervalId) $('#simulation-new').attr('disabled', false) $('#simulation-season').attr('disabled', false) $('#simulation-auto').attr('disabled', false) $('#simulation-stop').attr('disabled', true) } // ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— function makeWorldSettingsControlForm() { $('#leagueLevelQ').val(leagueLevelQ) $('#leagueTeamQ').val(leagueTeamQ) $('#exchangeTeamQ').val(exchangeTeamQ) } function readWorldSettings() { leagueLevelQ = parseInt($('#leagueLevelQ').val()) leagueTeamQ = parseInt($('#leagueTeamQ').val()) exchangeTeamQ = parseInt($('#exchangeTeamQ').val()) if (leagueLevelQ < 1 || leagueLevelQ > 10) leagueLevelQ = 3 if (leagueTeamQ < 2 || leagueTeamQ > 24) leagueTeamQ = 10 if (exchangeTeamQ < 1 || exchangeTeamQ > Math.floor(leagueTeamQ / 2)) exchangeTeamQ = Math.min(2, Math.floor(leagueTeamQ / 2)) $('#exchangeTeamQ').val(exchangeTeamQ) } function readTeamName(e) { var team_id = parseInt($(e.target).attr('data-ode-team')) teams[team_id].name = $(e.target).val().trim() } function readTeamStrategy(e) { var team_id = parseInt($(e.target).attr('data-ode-team')) var key = $(e.target).val().trim() teams[team_id].strategyName = key teams[team_id].decision = strategies[key] } // ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— function showGames() { $('.season-league-games table').toggle($('#showGames').is(':checked')) } function showStandings() { $('.season-league-standings table').toggle($('#showStandings').is(':checked')) } // ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— // When the page is loaded $(function() { // Tabulation $('.tabs').tabs({ active: 2 // Default tab is "World settings" }) // Sort the league sorting parameters $("#leagueSortingParameters").sortable({ stop: readleagueSortingParameters }) $("#leagueSortingParameters").disableSelection() // Accordion $('#seasonalStatistics').accordion({ collapsible: true }) // Controls $('[data-ode-settings]').change(readControlForm) $('#timeStep').change(readTimeStep) $('#makeTeamControls').click(makeTeamControls) $(document).on('change', 'input[name="team-name"][data-ode-team]', readTeamName) $(document).on('change', 'select[name="team-strategy"][data-ode-team]', readTeamStrategy) $('#showGames').click(showGames) $('#showStandings').click(showStandings) makeControlForm() makeWorldSettingsControlForm() initSimulationControls() initWorldWrapper() })

    Simulation

    Display