Some simulation and ladder fixes. Preparing Criss-Cross tournament.
This commit is contained in:
parent
51a831a2e7
commit
2c6fc67db2
11 changed files with 82 additions and 32 deletions
app
lib/simulator
locale
templates/play
views/play
|
@ -56,8 +56,8 @@ module.exports = class Simulator extends CocoClass
|
||||||
|
|
||||||
simulateSingleGame: ->
|
simulateSingleGame: ->
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
@trigger 'statusUpdate', 'Simulating...'
|
|
||||||
@assignWorldAndLevelFromLevelLoaderAndDestroyIt()
|
@assignWorldAndLevelFromLevelLoaderAndDestroyIt()
|
||||||
|
@trigger 'statusUpdate', 'Simulating...'
|
||||||
@setupGod()
|
@setupGod()
|
||||||
try
|
try
|
||||||
@commenceSingleSimulation()
|
@commenceSingleSimulation()
|
||||||
|
@ -174,8 +174,8 @@ module.exports = class Simulator extends CocoClass
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
info = 'All resources loaded, simulating!'
|
info = 'All resources loaded, simulating!'
|
||||||
console.log info
|
console.log info
|
||||||
@trigger 'statusUpdate', info, @task.getSessions()
|
|
||||||
@assignWorldAndLevelFromLevelLoaderAndDestroyIt()
|
@assignWorldAndLevelFromLevelLoaderAndDestroyIt()
|
||||||
|
@trigger 'statusUpdate', info, @task.getSessions()
|
||||||
@setupGod()
|
@setupGod()
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -227,6 +227,7 @@ module.exports = class Simulator extends CocoClass
|
||||||
@hd = new @memwatch.HeapDiff()
|
@hd = new @memwatch.HeapDiff()
|
||||||
|
|
||||||
onInfiniteLoop: ->
|
onInfiniteLoop: ->
|
||||||
|
return if @destroyed
|
||||||
console.warn 'Skipping infinitely looping game.'
|
console.warn 'Skipping infinitely looping game.'
|
||||||
@trigger 'statusUpdate', "Infinite loop detected; grabbing a new game in #{@retryDelayInSeconds} seconds."
|
@trigger 'statusUpdate', "Infinite loop detected; grabbing a new game in #{@retryDelayInSeconds} seconds."
|
||||||
_.delay @cleanupAndSimulateAnotherTask, @retryDelayInSeconds * 1000
|
_.delay @cleanupAndSimulateAnotherTask, @retryDelayInSeconds * 1000
|
||||||
|
@ -240,7 +241,11 @@ module.exports = class Simulator extends CocoClass
|
||||||
@sendResultsBackToServer taskResults
|
@sendResultsBackToServer taskResults
|
||||||
|
|
||||||
sendResultsBackToServer: (results) ->
|
sendResultsBackToServer: (results) ->
|
||||||
@trigger 'statusUpdate', 'Simulation completed, sending results back to server!'
|
status = 'Recording:'
|
||||||
|
for session in results.sessions
|
||||||
|
states = ['wins', if _.find(results.sessions, (s) -> s.metrics.rank is 0) then 'loses' else 'draws']
|
||||||
|
status += " #{session.name} #{states[session.metrics.rank]}"
|
||||||
|
@trigger 'statusUpdate', status
|
||||||
console.log 'Sending result back to server:'
|
console.log 'Sending result back to server:'
|
||||||
console.log JSON.stringify results
|
console.log JSON.stringify results
|
||||||
|
|
||||||
|
|
|
@ -874,6 +874,7 @@
|
||||||
tournament_ended: "Tournament ended"
|
tournament_ended: "Tournament ended"
|
||||||
tournament_rules: "Tournament Rules"
|
tournament_rules: "Tournament Rules"
|
||||||
tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details"
|
tournament_blurb: "Write code, collect gold, build armies, crush foes, win prizes, and upgrade your career in our $40,000 Greed tournament! Check out the details"
|
||||||
|
tournament_blurb_criss_cross: "Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details"
|
||||||
tournament_blurb_blog: "on our blog"
|
tournament_blurb_blog: "on our blog"
|
||||||
rules: "Rules"
|
rules: "Rules"
|
||||||
winners: "Winners"
|
winners: "Winners"
|
||||||
|
|
|
@ -11,7 +11,6 @@ block content
|
||||||
if level.get('name') == 'Greed'
|
if level.get('name') == 'Greed'
|
||||||
.tournament-blurb
|
.tournament-blurb
|
||||||
h2
|
h2
|
||||||
//span(data-i18n="ladder.tournament_ends") Tournament ends
|
|
||||||
span(data-i18n="ladder.tournament_ended") Tournament ended
|
span(data-i18n="ladder.tournament_ended") Tournament ended
|
||||||
| #{tournamentTimeLeft}
|
| #{tournamentTimeLeft}
|
||||||
p
|
p
|
||||||
|
@ -46,6 +45,17 @@ block content
|
||||||
a(href="http://aws.amazon.com/")
|
a(href="http://aws.amazon.com/")
|
||||||
img(src=base + "aws.png")
|
img(src=base + "aws.png")
|
||||||
|
|
||||||
|
if level.get('name') == 'Criss-Cross'
|
||||||
|
.tournament-blurb
|
||||||
|
h2
|
||||||
|
span(data-i18n="ladder.tournament_ends") Tournament ends
|
||||||
|
| #{tournamentTimeLeft}
|
||||||
|
p
|
||||||
|
span(data-i18n="ladder.tournament_blurb_criss_cross") Win bids, construct paths, outwit opponents, grab gems, and upgrade your career in our Criss-Cross tournament! Check out the details
|
||||||
|
|
|
||||||
|
a(href="http://blog.codecombat.com/6-programming-languages-one-victor-codecombats-newest-tournament", data-i18n="ladder.tournament_blurb_blog") on our blog
|
||||||
|
| .
|
||||||
|
|
||||||
div#columns.row
|
div#columns.row
|
||||||
div.column.col-md-2
|
div.column.col-md-2
|
||||||
for team in teams
|
for team in teams
|
||||||
|
@ -73,8 +83,10 @@ block content
|
||||||
if level.get('name') == 'Greed'
|
if level.get('name') == 'Greed'
|
||||||
li
|
li
|
||||||
a(href="#prizes", data-toggle="tab", data-i18n="ladder_prizes.prizes") Prizes
|
a(href="#prizes", data-toggle="tab", data-i18n="ladder_prizes.prizes") Prizes
|
||||||
|
if level.get('name') == 'Greed'
|
||||||
li
|
li
|
||||||
a(href="#rules", data-toggle="tab", data-i18n="ladder.rules") Rules
|
a(href="#rules", data-toggle="tab", data-i18n="ladder.rules") Rules
|
||||||
|
if level.get('name') == 'Greed' || (level.get('name') == 'Criss-Cross!!!')
|
||||||
li
|
li
|
||||||
a(href="#winners", data-toggle="tab", data-i18n="ladder.winners") Winners
|
a(href="#winners", data-toggle="tab", data-i18n="ladder.winners") Winners
|
||||||
|
|
||||||
|
@ -651,6 +663,7 @@ block content
|
||||||
| - $50
|
| - $50
|
||||||
td $50
|
td $50
|
||||||
|
|
||||||
|
if level.get('name') == 'Greed'
|
||||||
.tab-pane.well#rules
|
.tab-pane.well#rules
|
||||||
h1(data-i18n="ladder.tournament_rules") Tournament Rules
|
h1(data-i18n="ladder.tournament_rules") Tournament Rules
|
||||||
h2 General
|
h2 General
|
||||||
|
@ -712,6 +725,7 @@ block content
|
||||||
a(href="http://discourse.codecombat.com/") Discourse forum
|
a(href="http://discourse.codecombat.com/") Discourse forum
|
||||||
| .
|
| .
|
||||||
|
|
||||||
|
if level.get('name') == 'Greed' || level.get('name') == 'Criss-Cross!!!'
|
||||||
.tab-pane.well#winners
|
.tab-pane.well#winners
|
||||||
h1(data-i18n="ladder.winners") Winners
|
h1(data-i18n="ladder.winners") Winners
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ div#columns.row
|
||||||
th(colspan=2)
|
th(colspan=2)
|
||||||
th(colspan=3, style="color: #{team.primaryColor}")
|
th(colspan=3, style="color: #{team.primaryColor}")
|
||||||
span= team.name
|
span= team.name
|
||||||
span
|
span.spl(data-i18n="ladder.leaderboard") Leaderboard
|
||||||
span(data-i18n="ladder.leaderboard") Leaderboard
|
|
||||||
tr
|
tr
|
||||||
th(colspan=2)
|
th(colspan=2)
|
||||||
th(data-i18n="general.score") Score
|
th(data-i18n="general.score") Score
|
||||||
|
|
|
@ -4,7 +4,10 @@ h4.home
|
||||||
i.icon-home.icon-white
|
i.icon-home.icon-white
|
||||||
span(data-i18n="play_level.home") Home
|
span(data-i18n="play_level.home") Home
|
||||||
|
|
||||||
h4.title #{worldName}
|
h4.title
|
||||||
|
| #{worldName}
|
||||||
|
| -
|
||||||
|
a(href=editorLink, data-i18n="nav.editor", title="Open " + worldName + " in the Level Editor") Editor
|
||||||
|
|
||||||
button.btn.btn-xs.btn-inverse.banner#game-menu-button(title="Show game menu", data-i18n="play_level.game_menu") Game Menu
|
button.btn.btn-xs.btn-inverse.banner#game-menu-button(title="Show game menu", data-i18n="play_level.game_menu") Game Menu
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
strong.tip(data-i18n='play_level.tip_open_source') CodeCombat is 100% open source!
|
strong.tip(data-i18n='play_level.tip_open_source') CodeCombat is 100% open source!
|
||||||
strong.tip(data-i18n='play_level.tip_beta_launch') CodeCombat launched its beta in October, 2013.
|
strong.tip(data-i18n='play_level.tip_beta_launch') CodeCombat launched its beta in October, 2013.
|
||||||
strong.tip(data-i18n='play_level.tip_js_beginning') JavaScript is just the beginning.
|
strong.tip(data-i18n='play_level.tip_js_beginning') JavaScript is just the beginning.
|
||||||
strong.tip(data-i18n='play_level.tip_autocast_setting') Adjust autocast settings by clicking the gear on the cast button.
|
|
||||||
strong.tip(data-i18n='play_level.tip_think_solution') Think of the solution, not the problem.
|
strong.tip(data-i18n='play_level.tip_think_solution') Think of the solution, not the problem.
|
||||||
strong.tip(data-i18n='play_level.tip_theory_practice') In theory there is no difference between theory and practice; in practice there is. - Yogi Berra
|
strong.tip(data-i18n='play_level.tip_theory_practice') In theory there is no difference between theory and practice; in practice there is. - Yogi Berra
|
||||||
strong.tip(data-i18n='play_level.tip_error_free') There are two ways to write error-free programs; only the third one works. - Alan Perlis
|
strong.tip(data-i18n='play_level.tip_error_free') There are two ways to write error-free programs; only the third one works. - Alan Perlis
|
||||||
|
|
|
@ -143,14 +143,14 @@ module.exports = class MainPlayView extends RootView
|
||||||
]
|
]
|
||||||
|
|
||||||
arenas = [
|
arenas = [
|
||||||
#{
|
{
|
||||||
# name: 'Criss-Cross'
|
name: 'Criss-Cross'
|
||||||
# difficulty: 4
|
difficulty: 5
|
||||||
# id: 'criss-cross'
|
id: 'criss-cross'
|
||||||
# image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
|
image: '/file/db/level/528aea2d7f37fc4e0700016b/its_a_trap_icon.png'
|
||||||
# description: 'Participate in a bidding war with opponents to reach the other side!'
|
description: 'Participate in a bidding war with opponents to reach the other side!'
|
||||||
# levelPath: 'ladder'
|
levelPath: 'ladder'
|
||||||
#}
|
}
|
||||||
{
|
{
|
||||||
name: 'Greed'
|
name: 'Greed'
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
|
@ -192,7 +192,7 @@ module.exports = class MainPlayView extends RootView
|
||||||
levelPath: 'ladder'
|
levelPath: 'ladder'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
classicAlgorithms = [
|
classicAlgorithms = [
|
||||||
{
|
{
|
||||||
name: 'Bubble Sort Bootcamp Battle'
|
name: 'Bubble Sort Bootcamp Battle'
|
||||||
|
|
|
@ -52,13 +52,13 @@ module.exports = class LadderView extends RootView
|
||||||
ctx.levelID = @levelID
|
ctx.levelID = @levelID
|
||||||
ctx.levelDescription = marked(@level.get('description')) if @level.get('description')
|
ctx.levelDescription = marked(@level.get('description')) if @level.get('description')
|
||||||
ctx._ = _
|
ctx._ = _
|
||||||
ctx.tournamentTimeLeft = moment(new Date(1402444800000)).fromNow()
|
if tournamentDate = {greed: 1402444800000, 'criss-cross': 1410912000000}[@levelID]
|
||||||
|
ctx.tournamentTimeLeft = moment(new Date(tournamentDate)).fromNow()
|
||||||
ctx.winners = require('views/play/ladder/tournament_results')[@levelID]
|
ctx.winners = require('views/play/ladder/tournament_results')[@levelID]
|
||||||
ctx
|
ctx
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
# console.debug 'gintau', 'ladder_view-afterRender', @supermodel.finished()
|
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
|
@insertSubView(@ladderTab = new LadderTabView({}, @level, @sessions))
|
||||||
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
|
@insertSubView(@myMatchesTab = new MyMatchesTabView({}, @level, @sessions))
|
||||||
|
|
|
@ -30,6 +30,13 @@ module.exports = class LadderHomeView extends RootView
|
||||||
getRenderData: (context={}) ->
|
getRenderData: (context={}) ->
|
||||||
context = super(context)
|
context = super(context)
|
||||||
arenas = [
|
arenas = [
|
||||||
|
{
|
||||||
|
name: 'Criss-Cross'
|
||||||
|
difficulty: 5
|
||||||
|
id: 'criss-cross'
|
||||||
|
image: '/file/db/level/5391f3d519dc22b8082159b2/banner2.png'
|
||||||
|
description: 'Participate in a bidding war with opponents to reach the other side!'
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name: 'Greed'
|
name: 'Greed'
|
||||||
difficulty: 4
|
difficulty: 4
|
||||||
|
@ -37,6 +44,13 @@ module.exports = class LadderHomeView extends RootView
|
||||||
image: '/file/db/level/53558b5a9914f5a90d7ccddb/greed_banner.jpg'
|
image: '/file/db/level/53558b5a9914f5a90d7ccddb/greed_banner.jpg'
|
||||||
description: 'Liked Dungeon Arena and Gold Rush? Put them together in this economic arena!'
|
description: 'Liked Dungeon Arena and Gold Rush? Put them together in this economic arena!'
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name: 'Sky Span (Testing)'
|
||||||
|
difficulty: 3
|
||||||
|
id: 'sky-span'
|
||||||
|
image: '/file/db/level/53c80fce0ddbef000084c667/sky-Span-banner.jpg'
|
||||||
|
description: 'Preview version of an upgraded Dungeon Arena. Help us with hero balance before release!'
|
||||||
|
}
|
||||||
{
|
{
|
||||||
name: 'Dungeon Arena'
|
name: 'Dungeon Arena'
|
||||||
difficulty: 3
|
difficulty: 3
|
||||||
|
|
|
@ -18,9 +18,6 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
@simulatorsLeaderboardDataRes = @supermodel.addModelResource(@simulatorsLeaderboardData, 'top_simulators')
|
@simulatorsLeaderboardDataRes = @supermodel.addModelResource(@simulatorsLeaderboardData, 'top_simulators')
|
||||||
@simulatorsLeaderboardDataRes.load()
|
@simulatorsLeaderboardDataRes.load()
|
||||||
|
|
||||||
@simulator = new Simulator()
|
|
||||||
@listenTo(@simulator, 'statusUpdate', @updateSimulationStatus)
|
|
||||||
|
|
||||||
onLoaded: ->
|
onLoaded: ->
|
||||||
super()
|
super()
|
||||||
@render()
|
@render()
|
||||||
|
@ -42,7 +39,21 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
application.tracker?.trackEvent 'Simulate Button Click', {}
|
application.tracker?.trackEvent 'Simulate Button Click', {}
|
||||||
$('#simulate-button').prop 'disabled', true
|
$('#simulate-button').prop 'disabled', true
|
||||||
$('#simulate-button').text 'Simulating...'
|
$('#simulate-button').text 'Simulating...'
|
||||||
|
@simulateNextGame()
|
||||||
|
|
||||||
|
simulateNextGame: ->
|
||||||
|
unless @simulator
|
||||||
|
@simulator = new Simulator()
|
||||||
|
@listenTo @simulator, 'statusUpdate', @updateSimulationStatus
|
||||||
|
# Work around simulator getting super slow on Chrome
|
||||||
|
fetchAndSimulateTaskOriginal = @simulator.fetchAndSimulateTask
|
||||||
|
@simulator.fetchAndSimulateTask = =>
|
||||||
|
if @simulator.simulatedByYou >= 5
|
||||||
|
@simulator.destroy()
|
||||||
|
@simulator = null
|
||||||
|
@simulateNextGame()
|
||||||
|
else
|
||||||
|
fetchAndSimulateTaskOriginal.apply @simulator
|
||||||
@simulator.fetchAndSimulateTask()
|
@simulator.fetchAndSimulateTask()
|
||||||
|
|
||||||
refresh: ->
|
refresh: ->
|
||||||
|
@ -51,20 +62,23 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
$.ajax '/queue/messagesInQueueCount', {success}
|
$.ajax '/queue/messagesInQueueCount', {success}
|
||||||
|
|
||||||
updateSimulationStatus: (simulationStatus, sessions) ->
|
updateSimulationStatus: (simulationStatus, sessions) ->
|
||||||
|
if simulationStatus is 'Fetching simulation data!'
|
||||||
|
@simulationMatchDescription = ''
|
||||||
|
@simulationSpectateLink = ''
|
||||||
@simulationStatus = simulationStatus
|
@simulationStatus = simulationStatus
|
||||||
try
|
try
|
||||||
if sessions?
|
if sessions?
|
||||||
#TODO: Fetch names from Redis, the creatorName is denormalized
|
@simulationMatchDescription = ''
|
||||||
creatorNames = (session.creatorName for session in sessions)
|
@simulationSpectateLink = "/play/spectate/#{@simulator.level.get('slug')}?"
|
||||||
@simulationStatus = 'Simulating game between '
|
for session, index in sessions
|
||||||
for index in [0...creatorNames.length]
|
# TODO: Fetch names from Redis, the creatorName is denormalized
|
||||||
unless creatorNames[index]
|
@simulationMatchDescription += "#{if index then ' vs ' else ''}#{session.creatorName or 'Anonymous'} (#{sessions[index].team})"
|
||||||
creatorNames[index] = 'Anonymous'
|
@simulationSpectateLink += "session-#{if index then 'two' else 'one'}=#{session.sessionID}"
|
||||||
@simulationStatus += (if index != 0 then ' and ' else '') + creatorNames[index]
|
@simulationMatchDescription += " on #{@simulator.level.get('name')}"
|
||||||
@simulationStatus += '...'
|
|
||||||
catch e
|
catch e
|
||||||
console.log "There was a problem with the named simulation status: #{e}"
|
console.log "There was a problem with the named simulation status: #{e}"
|
||||||
$('#simulation-status-text').text @simulationStatus
|
link = if @simulationSpectateLink then "<a href=#{@simulationSpectateLink}>#{_.string.escapeHTML(@simulationMatchDescription)}</a>" else ''
|
||||||
|
$('#simulation-status-text').html "<h3>#{@simulationStatus}</h3>#{link}"
|
||||||
|
|
||||||
resimulateAllSessions: ->
|
resimulateAllSessions: ->
|
||||||
postData =
|
postData =
|
||||||
|
@ -81,7 +95,7 @@ module.exports = class SimulateTabView extends CocoView
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
clearInterval @refreshInterval
|
clearInterval @refreshInterval
|
||||||
@simulator.destroy()
|
@simulator?.destroy()
|
||||||
super()
|
super()
|
||||||
|
|
||||||
class SimulatorsLeaderboardData extends CocoClass
|
class SimulatorsLeaderboardData extends CocoClass
|
||||||
|
|
|
@ -54,6 +54,7 @@ module.exports = class ControlBarView extends CocoView
|
||||||
c.homeLink = '/play/ladder/' + @level.get('slug').replace /\-tutorial$/, ''
|
c.homeLink = '/play/ladder/' + @level.get('slug').replace /\-tutorial$/, ''
|
||||||
else
|
else
|
||||||
c.homeLink = '/'
|
c.homeLink = '/'
|
||||||
|
c.editorLink = "/editor/level/#{@level.get('slug')}"
|
||||||
c
|
c
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
|
Reference in a new issue