Guest User

Untitled

a guest
Apr 24th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.69 KB | None | 0 0
  1. const e1 = {
  2. name: 'George',
  3. health: 1000,
  4. target: null,
  5. }
  6.  
  7. const e2 = {
  8. name: 'Phil',
  9. health: 1000,
  10. target: null,
  11. }
  12.  
  13.  
  14. e1.behave = iflatmap(agentBehaviour(e1))
  15. e2.behave = iflatmap(agentBehaviour(e2))
  16.  
  17. function *patrol(e) {
  18. console.log(e.name, 'patrolling for baddies...')
  19. while(true) {
  20. yield wait(10)
  21. console.log(e.name, 'continues to patrol')
  22. }
  23. }
  24.  
  25. function *attack(e, target) {
  26. console.log(e.name, 'engages', target.name)
  27. yield iwhile(() => target.health > 0, function *() {
  28. while (true) {
  29. if (Math.random() < 0.5) {
  30. // Cast fireball
  31. console.log(e.name, 'charges a fireball at', target.name)
  32. yield wait(10)
  33. if (e.health <= 0) throw Error('Impossible!!')
  34. const damage = 100 + (Math.random() * 10)|0
  35. target.health -= damage
  36. console.log(`${e.name}'s fireball hits ${target.name} for ${damage} damage, ${target.health} hp remaining`)
  37. } else {
  38. // Attack with sword
  39. const damage = 10 + (Math.random() * 10)|0
  40. target.health -= damage
  41. console.log(`${e.name}'s sword slices ${target.name} for ${damage} damage, ${target.health} hp remaining`)
  42. yield wait(3)
  43. }
  44.  
  45. yield wait(5)
  46. }
  47. })
  48. console.log(target.name, 'is dead!', e.name, 'cheers and hollers')
  49. e.target = null
  50. //while(true) yield
  51. }
  52.  
  53. function *agentBehaviour(e) {
  54. yield iwhile(() => e.health > 0, function *() {
  55. while (true) {
  56. // If we have no target, just patrol around.
  57. yield iwhile(() => e.target == null, patrol(e))
  58.  
  59. // ... Ok we have a target now. Attack!!
  60. yield attack(e, e.target)
  61. }
  62. })
  63. console.log('agent', e.name, 'is dead')
  64. }
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71. // *** Plumbing.
  72.  
  73. // The state is a stack of iterators. Each tick we'll take the top of the stack
  74. // (the stack's last element) and iterate it.
  75.  
  76.  
  77. // Grab a reference to GeneratorFunction so we can detect nested iterators.
  78. const GeneratorFunction = (function *(){})().constructor
  79.  
  80. // Run iterator so long as predicate remains true
  81. function *iwhile(pred, iter) {
  82. if (typeof iter === 'function') iter = iflatmap(iter()) // Avoids some awkward syntax
  83.  
  84. while (true) {
  85. if (!pred()) break
  86. const {value, done} = iter.next()
  87. if (done) break
  88. yield value
  89. }
  90. }
  91.  
  92.  
  93. // Helper to wait X frames
  94. function *wait(framecount) {
  95. while(--framecount) yield // Each call to yield will wait 1 frame
  96. }
  97.  
  98.  
  99. // Wrap an iterator, allowing it to yield other iterators.
  100. function *iflatmap(iter) {
  101. const stack = [iter]
  102.  
  103. // Used to get values out of nested generators
  104. let retval
  105.  
  106. while (stack.length) {
  107. const i = stack[stack.length - 1]
  108.  
  109. let {value, done} = i.next(retval)
  110. //console.log('iter next', value, done)
  111.  
  112. if (done) {
  113. // value is the return value of the function. We'll pass that back to the
  114. // yield statement of the caller. We could instead force the caller to
  115. // return or something.
  116. stack.pop()
  117. retval = value
  118. } else if (typeof value === 'object' && value.constructor === GeneratorFunction) {
  119. // Function yielded a generator. Recurse up.
  120. stack.push(value)
  121. lastVal = undefined
  122. // And recurse
  123.  
  124. } else yield value // Normal value. Yield out and iterate normally.
  125. }
  126.  
  127. return retval
  128. }
  129.  
  130.  
  131.  
  132. // *** Actual runtime code
  133.  
  134. const timer = setInterval(tick, 100)
  135.  
  136. function updateEntity(e) {
  137. if (e.dead) return
  138.  
  139. const {done} = e.behave.next()
  140. if (done) {
  141. console.log('Cleanup', e.name)
  142. e.dead = true
  143. }
  144. }
  145.  
  146. let framecount = 0
  147.  
  148. function tick() {
  149. framecount++
  150.  
  151. if (e1.target == null && framecount === 10) {
  152. console.log('Oh no! They saw each other')
  153. e1.target = e2
  154. e2.target = e1
  155. }
  156.  
  157.  
  158. updateEntity(e1)
  159. updateEntity(e2)
  160.  
  161. // Done!
  162. if (e1.dead || e2.dead) clearInterval(timer)
  163. }
Add Comment
Please, Sign In to add comment