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)
 |