forest_fire.sf 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/ruby
  2. define RED = "\e[1;31m";
  3. define YELLOW = "\e[1;33m";
  4. define GREEN = "\e[1;32m";
  5. define DIRS = [
  6. [-1, -1], [0, -1], [1, -1],
  7. [-1, 0], [1, 0],
  8. [-1, 1], [0, 1], [1, 1],
  9. ]
  10. enum (Empty, Tree, Heating, Burning);
  11. define pix = [' ', GREEN + "*", YELLOW + "*", RED + "*"];
  12. class Forest(p=0.01f, f=0.001f, height, width) {
  13. has rw = ^width
  14. has rh = ^height
  15. has spot = []
  16. has neighbors = []
  17. method init {
  18. spot = height.of { width.of { [true, false].pick ? Tree : Empty } }
  19. self.init_neighbors
  20. }
  21. method init_neighbors {
  22. for i=rh, j=rw {
  23. neighbors[i][j] = gather {
  24. for dir in DIRS {
  25. take(\(spot[i + dir[0]][j + dir[1]] \\ next));
  26. }
  27. }
  28. }
  29. }
  30. method step {
  31. var heat = []
  32. for i=rh, j=rw {
  33. given (spot[i][j]) {
  34. when Empty { spot[i][j] = Tree if (1.rand < p) }
  35. when Tree { spot[i][j] = Heating if (1.rand < f) }
  36. when Heating { spot[i][j] = Burning; heat << [i, j] }
  37. when Burning { spot[i][j] = Empty }
  38. }
  39. }
  40. for i,j in heat {
  41. neighbors[i][j].each { |ref|
  42. *ref = Heating if (*ref == Tree)
  43. }
  44. }
  45. }
  46. method show {
  47. print spot.map {|row|
  48. join('', pix[row...])
  49. }.join("\n")
  50. }
  51. }
  52. STDOUT.autoflush(true)
  53. var width = Num(`tput cols` || 80)-1
  54. var height = Num(`tput lines` || 24)-1
  55. var forest = Forest(height: height, width: width)
  56. print "\e[2J"
  57. loop {
  58. print "\e[H"
  59. forest.show
  60. forest.step
  61. }