snusp.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. """
  2. This program is a complete Windows Bloated SNUSP interpreter.
  3. Copyright (C) 2004 John Bauman
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. """
  16. import fileinput
  17. import sys
  18. import random
  19. import msvcrt
  20. try:
  21. import psyco #greatly speeds it up
  22. psyco.full()
  23. except:
  24. pass
  25. #0 = core, 1 = modular, 2 = bloated
  26. version = 2
  27. class Thread:
  28. """Store data (instruction pointer, etc.) for a thread)"""
  29. def __init__(self, insp, dire, memindex, memlevel, callstack):
  30. self.insp = insp
  31. self.dire = dire
  32. self.memindex = memindex
  33. self.memlevel = memlevel
  34. self.callstack = callstack
  35. def findnext(dire, x, y):
  36. """Find where to go to next."""
  37. if dire == 0:
  38. return x + 1, y
  39. if dire == 1:
  40. return x, y + 1
  41. if dire == 2:
  42. return x - 1, y
  43. if dire == 3:
  44. return x, y - 1
  45. print "Invalid direction"
  46. def gotonext():
  47. """Go to the next location."""
  48. global currx, curry, dire
  49. currx, curry = findnext(dire, currx, curry)
  50. program = []
  51. currx = curry = 0
  52. maxlen = 0
  53. for line in fileinput.input():
  54. n = [c for c in line]
  55. if currx == 0 and curry == 0 and line.find("$") >= 0:
  56. currx = line.index("$")
  57. curry = len(program)
  58. program.append(n)
  59. if maxlen < len(n):
  60. maxlen = len(n)
  61. for line in range(len(program)): #pad the lines out
  62. program[line] += " " * (maxlen - len(program[line]))
  63. dire = 0
  64. stack = [[0]]
  65. currindex = 0
  66. currlevel = 0
  67. callstack = []
  68. threads = [Thread((currx, curry), dire, currindex, currlevel, callstack)]
  69. currthread = 0
  70. def savethreaddata():
  71. """Save all of the exposed thread data into the thread object."""
  72. threads[currthread].insp = (currx, curry)
  73. threads[currthread].dire = dire
  74. threads[currthread].memindex = currindex
  75. threads[currthread].memlevel = currlevel
  76. threads[currthread].callstack = callstack
  77. def loadnextthread():
  78. """Load all of a thread's data from its associated object."""
  79. global currthread, currx, curry, dire, currindex, callstack, currlevel
  80. if not threads:
  81. return
  82. currthread = (currthread + 1) % len(threads)
  83. currx = threads[currthread].insp[0]
  84. curry = threads[currthread].insp[1]
  85. dire = threads[currthread].dire
  86. currindex = threads[currthread].memindex
  87. currlevel = threads[currthread].memlevel
  88. callstack = threads[currthread].callstack
  89. while threads:
  90. loadnextthread()
  91. if curry < 0 or curry >= len(program) or currx < 0 or currx >= len(program[curry]):
  92. del(threads[currthread])
  93. continue
  94. currchar = program[curry][currx]
  95. #print currx, curry, stack[currindex]
  96. blocked = 0
  97. if currchar == ">":
  98. currindex += 1
  99. if len(stack[currlevel]) <= currindex: #lengthen the stack if it's not long enough
  100. stack[currlevel].append(0)
  101. elif currchar == "<":
  102. currindex -= 1
  103. elif currchar == "+":
  104. stack[currlevel][currindex] += 1
  105. elif currchar == "-":
  106. stack[currlevel][currindex] -= 1
  107. elif currchar == "/":
  108. dire = 3 - dire #rotate
  109. elif currchar == "\\":
  110. dire = dire ^ 1 #rotate a different way
  111. elif currchar == "!": #skip a space
  112. gotonext()
  113. elif currchar == "?": #skip a space if the current space has a zero
  114. if not stack[currlevel][currindex]:
  115. gotonext()
  116. elif currchar == ",": #read input
  117. if msvcrt.kbhit():
  118. stack[currlevel][currindex] = ord(msvcrt.getche())
  119. else:
  120. blocked = 1
  121. elif currchar == ".": #write output
  122. sys.stdout.write(chr(stack[currlevel][currindex]))
  123. elif currchar == "@" and version >= 1: #append the current location
  124. callstack.append((dire, currx, curry))
  125. elif currchar == "#" and version >= 1: #pop off the current location and move there
  126. if len(callstack) == 0:
  127. del(threads[currthread])
  128. continue
  129. dire, currx, curry = callstack.pop()
  130. gotonext()
  131. elif currchar == "&" and version >= 2: #make a new thread
  132. gotonext()
  133. threads.append(Thread((currx, curry), dire, currindex, currlevel, []))
  134. elif currchar == "%" and version >= 2: #get a random number
  135. stack[currlevel][currindex] = random.randrange(stack[currlevel][currindex])
  136. elif currchar == ":": #move up a memory level
  137. currlevel += 1
  138. if len(stack) <= currlevel:
  139. stack.append([0] * (currindex + 1))
  140. if len(stack[currlevel]) <= currindex:
  141. stack[currlevel].extend([0] * (currindex + 1 - len(stack[currlevel])))
  142. elif currchar == ";": #move down a memory level
  143. currlevel -= 1
  144. if len(stack[currlevel]) <= currindex:
  145. stack[currlevel].extend([0] * (currindex + 1 - len(stack[currlevel])))
  146. if not blocked:
  147. gotonext()
  148. savethreaddata()