mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			124 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
#!/usr/bin/env rune
 | 
						|
pragma.syntax("0.9")
 | 
						|
 | 
						|
def pi := (-1.0).acos()
 | 
						|
def makeEPainter := <unsafe:com.zooko.tray.makeEPainter>
 | 
						|
def colors := <awt:makeColor>
 | 
						|
 | 
						|
# --------------------------------------------------------------
 | 
						|
# --- Definitions
 | 
						|
 | 
						|
/** Execute 'task' repeatedly as long 'indicator' is unresolved. */
 | 
						|
def doWhileUnresolved(indicator, task) {
 | 
						|
  def loop() {
 | 
						|
    if (!Ref.isResolved(indicator)) {
 | 
						|
      task()
 | 
						|
      loop <- ()
 | 
						|
    }
 | 
						|
  }
 | 
						|
  loop <- ()
 | 
						|
}
 | 
						|
 | 
						|
/** The data structure specified for the task. */
 | 
						|
def makeBuckets(size) {
 | 
						|
    def values := ([100] * size).diverge() # storage
 | 
						|
    def buckets {
 | 
						|
        to size() :int { return size }
 | 
						|
        /** get current quantity in bucket 'i' */
 | 
						|
        to get(i :int) { return values[i] }
 | 
						|
        /** transfer 'amount' units, as much as possible, from bucket 'i' to bucket 'j'
 | 
						|
            or vice versa if 'amount' is negative */
 | 
						|
        to transfer(i :int, j :int, amount :int) {
 | 
						|
            def amountLim := amount.min(values[i]).max(-(values[j]))
 | 
						|
            values[i] -= amountLim
 | 
						|
            values[j] += amountLim
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return buckets
 | 
						|
}
 | 
						|
 | 
						|
/** A view of the current state of the buckets. */
 | 
						|
def makeDisplayComponent(buckets) {
 | 
						|
  def c := makeEPainter(def paintCallback {
 | 
						|
    to paintComponent(g) {
 | 
						|
      def pixelsW := c.getWidth()
 | 
						|
      def pixelsH := c.getHeight()
 | 
						|
      def bucketsW := buckets.size()
 | 
						|
 | 
						|
      g.setColor(colors.getWhite())
 | 
						|
      g.fillRect(0, 0, pixelsW, pixelsH)
 | 
						|
 | 
						|
      g.setColor(colors.getDarkGray())
 | 
						|
      var sum := 0
 | 
						|
      for i in 0..!bucketsW {
 | 
						|
        sum += def value := buckets[i]
 | 
						|
        def x0 := (i       * pixelsW / bucketsW).floor()
 | 
						|
        def x1 := ((i + 1) * pixelsW / bucketsW).floor()
 | 
						|
        g.fillRect(x0 + 1, pixelsH - value,
 | 
						|
                   x1 - x0 - 1, value)
 | 
						|
      }
 | 
						|
 | 
						|
      g.setColor(colors.getBlack())
 | 
						|
      g."drawString(String, int, int)"(`Total: $sum`, 2, 20)
 | 
						|
    }
 | 
						|
  })
 | 
						|
  c.setPreferredSize(<awt:makeDimension>(500, 300))
 | 
						|
  return c
 | 
						|
}
 | 
						|
 | 
						|
# --------------------------------------------------------------
 | 
						|
# --- Application setup
 | 
						|
 | 
						|
def buckets := makeBuckets(100)
 | 
						|
def done # Promise indicating when the window is closed
 | 
						|
 | 
						|
# Create the window
 | 
						|
def frame := <unsafe:javax.swing.makeJFrame>("Atomic transfers")
 | 
						|
frame.setContentPane(def display := makeDisplayComponent(buckets))
 | 
						|
frame.addWindowListener(def mainWindowListener {
 | 
						|
  to windowClosing(event) :void {
 | 
						|
    bind done := null
 | 
						|
  }
 | 
						|
  match _ {}
 | 
						|
})
 | 
						|
frame.setLocation(50, 50)
 | 
						|
frame.pack()
 | 
						|
 | 
						|
# --------------------------------------------------------------
 | 
						|
# --- Tasks
 | 
						|
 | 
						|
# Neatens up buckets
 | 
						|
var ni := 0
 | 
						|
doWhileUnresolved(done, fn {
 | 
						|
  def i := ni
 | 
						|
  def j := (ni + 1) %% buckets.size()
 | 
						|
  buckets.transfer(i, j, (buckets[i] - buckets[j]) // 4)
 | 
						|
  ni := j
 | 
						|
})
 | 
						|
 | 
						|
# Messes up buckets
 | 
						|
var mi := 0
 | 
						|
doWhileUnresolved(done, fn {
 | 
						|
    def i := (mi + entropy.nextInt(3)) %% buckets.size()
 | 
						|
    def j := (i + entropy.nextInt(3)) %% buckets.size() #entropy.nextInt(buckets.size())
 | 
						|
    buckets.transfer(i, j, (buckets[i] / pi).floor())
 | 
						|
    mi := j
 | 
						|
})
 | 
						|
 | 
						|
# Updates display at fixed 10 Hz
 | 
						|
# (Note: tries to catch up; on slow systems slow this down or it will starve the other tasks)
 | 
						|
def clock := timer.every(100, def _(_) {
 | 
						|
  if (Ref.isResolved(done)) {
 | 
						|
    clock.stop()
 | 
						|
  } else {
 | 
						|
    display.repaint()
 | 
						|
  }
 | 
						|
})
 | 
						|
clock.start()
 | 
						|
 | 
						|
# --------------------------------------------------------------
 | 
						|
# --- All ready, go visible and wait
 | 
						|
 | 
						|
frame.show()
 | 
						|
interp.waitAtTop(done)
 |