Permalink
Browse files

Turn slow mode into fast mode

This fixes several major UI inefficiencies:

 * playWeb.coffee triggered output updates that were being suppressed by play.html
   I removed these.  The output updates less frequently and is completely
   controlled by play.html.  Eventually, all of the CoffeeScript in play.html should
   be merged with playWeb.coffee, but that's a different issue.
 * We were calling zeroTimeout very frequently.  zeroTimeout is fast, but not
   free.  We now call it approximately 4 times a second, enough to keep the browser
   from timing out, but not enough to cause noticeable performance overhead.
 * We had released control back to the browser based on the number of games played.
   We also updated the graphs based on the number of games played.  Doing this
   way, we needed to be pessimistic about AI and browser performance.  We now
   release control when a game is over and we've had control for more than .25s.
 * We were updating the DOM whenever we added a page to the log, even when we
   updated "quietly" because we updated the paginator.  We now detect if the
   pagination has changed before updating it.

Combined, these changes allow the "slow mode" simulations to run nearly as fast
as the fast mode.  In Firefox, the UI updates in slow mode cause about 10%
runtime overhead.  Because of this, I removed the fast mode checkbox.

Fixes #23
  • Loading branch information...
1 parent a3e7855 commit b51bf28122c68fa5d759e2a9e15f6defabedf151 @bilts bilts committed Jan 20, 2012
Showing with 21 additions and 50 deletions.
  1. +0 −27 playWeb.coffee
  2. +9 −1 web/multiLog.coffee
  3. +12 −22 web/play.html
View
@@ -24,10 +24,6 @@ makeStrategy = (changes) ->
ai[key] = value
ai
-# Setting `fast` to true will takesome shortcuts to play the game
-# really quickly. These include
-# producing no output, and not returning control to the browser between
-# game steps.
playGame = (strategies, options, ret) ->
ais = (makeStrategy(item) for item in strategies)
@@ -38,30 +34,7 @@ playGame = (strategies, options, ret) ->
state = new State().setUpWithOptions(ais, options)
ret ?= options.log
- if options.fast
- options.log = () ->
- playFast(state, options, ret)
- else
- window.setZeroTimeout -> playStep(state, options, ret)
-playStep = (state, options, ret) ->
- if state.gameIsOver()
- ret(state)
- else
- try
- state.doPlay()
- if state.phase == 'buy' and (not state.extraturn) and options.grapher?
- options.grapher.recordMoney(state.current.ai.name, state.current.turnsTaken, state.current.coins)
- if state.phase == 'cleanup' and (not state.extraturn) and options.grapher?
- options.grapher.recordVP(state.current.ai.name, state.current.turnsTaken, state.current.getVP(state))
- window.setZeroTimeout -> playStep(state, options, ret)
- catch err
- errorHandler = options.errorHandler ? (alert ? console.log)
- errorHandler(err.message)
- window.donePlaying()
- throw err
-
-playFast = (state, options, ret) ->
until state.gameIsOver()
try
state.doPlay()
View
@@ -45,10 +45,16 @@ class MultiLog
"next page"
updatePaginator: ->
+ # Avoid updating the DOM if the new pages are the same as the old
+ pages = @pagesShown()
+ oldPages = @pagesRendered
+ if oldPages? and oldPages.length == pages.length and pages[0] == oldPages[0]
+ return if @currentPage == @renderedPage
+
prev = "<li class='#{this.prevButtonClass()}'><a href='#'>&larr; Previous</a></li>"
next = "<li class='#{this.nextButtonClass()}'><a href='#'>Next &rarr;</a></li>"
items = [prev]
- for pageNum in this.pagesShown()
+ for pageNum in pages
if pageNum == @currentPage
item = "<li class='active page'><a href='#'>#{pageNum}</a></li>"
else
@@ -57,6 +63,8 @@ class MultiLog
items.push(next)
@paginatorElt.html('<ul>' + items.join('') + '</ul>')
this.updateEvents()
+ @pagesRendered = pages
+ @renderedPage = @currentPage
updateEvents: ->
$('.page').click (event) =>
View
@@ -91,13 +91,6 @@ <h2 class="tagline">A simulator for Dominion strategies.</h2>
<span>Include Colony and Platinum</span>
</label>
</li>
- <li>
- <label>
- <input type="checkbox" name="optionsCheckboxes" value="fast"
- id="fast" />
- <span>Play fast (without much output)</span>
- </label>
- </li>
</ul>
<a id="playButton" href="#" class="btn success">
Start playing
@@ -236,7 +229,6 @@ <h2 class="tagline">A simulator for Dominion strategies.</h2>
log: log
colonies: $('#colonies').is(':checked')
randomizeOrder: $('#randomize').is(':checked')
- fast: $('#fast').is(':checked')
tracker: tracker
grapher: grapher
}
@@ -255,32 +247,30 @@ <h2 class="tagline">A simulator for Dominion strategies.</h2>
log: log
colonies: $('#colonies').is(':checked')
randomizeOrder: $('#randomize').is(':checked')
- fast: $('#fast').is(':checked')
tracker: tracker
grapher: grapher
}
playCount = 0
begunPlaying()
+ timeControlStarted = new Date()
playLoop = (result) ->
singleGameResult(result)
if condition() or (playCount >= count) or (not window.playing)
donePlaying(playCount)
else
- if (not options.fast) then multiLog.addPageQuietly('')
- nextIteration = ->
- playCount++
- playGame(compiled, options, playLoop)
- if (not options.fast) and (playCount % 10 == 0)
- grapher.updateGraphs()
- if (not options.fast) or (playCount % 20 == 0)
- tracker.updateScoresOnPage()
- if (not options.fast) or (playCount % 10) == 0
- window.setZeroTimeout(nextIteration)
+ multiLog.addPageQuietly('')
+ msWithControl = new Date() - timeControlStarted
+ playCount++
+ if msWithControl > 250
+ tracker.updateScoresOnPage()
+ grapher.updateGraphs()
+ window.setZeroTimeout ->
+ timeControlStarted = new Date()
+ playGame(compiled, options, playLoop)
else
- # no time to stop and give control to the Web browser!
- nextIteration()
+ playGame(compiled, options, playLoop)
- if (not options.fast) then multiLog.addPageQuietly('')
+ multiLog.addPageQuietly('')
playGame(compiled, options, playLoop)
$('#playButton').click (event) ->

0 comments on commit b51bf28

Please sign in to comment.