View difference between Paste ID: e5DASDRE and x6C7yG1k
SHOW: | | - or go back to the newest paste.
1-
'''
1+
2-
Created on Jun 13, 2013
2+
3
4-
@author: RSHELDON
4+
5
    def __init__(self,a=[]):
6-
NOTE: currently windows only because of the msvcrt module
6+
7-
linux solution for immediate command line interpretation should be implemented
7+
8
        self.list.append(val)
9-
import sys
9+
10-
import tty
10+
11-
tty.setcbreak(sys.stdin)
11+
12-
while True:
12+
13-
    print ord(sys.stdin.read(1))
13+
14-
'''
14+
15
        else:
16
            self.list.pop(n)#will error if you try to pop something that doesnt exist. good idea?
17
    def __getitem__(self,i):
18
        return self.list[i]
19
    def __repr__(self):
20
        return str(self.list)
21
22
class BefungeInterpreter:
23
    def __init__(self):
24
        self.program = {}
25
        self.tick = 0
26
        self.stack = deque([Stack()])
27
        self.exitStateFound = False
28
        self.pointerPosition = (0,0)
29
        self.exitValue = 0
30
        self.storageOffset = (0,0)
31
        self.stringMode = False;
32
        self.stringCharacter = '"'
33
        self.jumpOverMode = False;
34
        self.jumpOverCharacter = ';'
35
        self.functionDictionary = {\
36
                                   '+' : self.add, '-' : self.subtract, '*' : self.multiply, '/' : self.divide,\
37
                                   '%' : self.modulus, '!' : self.logicalNot, '`' : self.greaterThan,\
38
                                   '>' : self.east, '<' : self.west, '^' : self.north, 'V' : self.south, 'v' : self.south, '?' : self.randomDirection,\
39
                                   '_' : self.westOrEast, '|' : self.northOrSouth,\
40
                                   ':' : self.duplicate, '\\' : self.swap, '$' : self.pop, '.' : self.intPrint, ',' : self.strPrint,\
41
                                   '#' : self.jump, 'p' : self.put, 'g' : self.get,\
42
                                   '&' : self.inputNumber, '~' : self.inputChar, '@' : self.end, "noop" : self.noop,\
43
                                   self.stringCharacter : self.string, 'r' : self.reverse, 'x' : self.popVector,\
44
                                   'j' : self.jumpForward, 'q' : self.quit, 'k' : self.iterate,\
45
                                   '[' : self.turnLeft, ']' : self.turnRight, 'w' : self.compare,
46
                                   '{' : self.beginBlock, '}' : self.endBlock, "'" : self.fetchCharacter,
47
                                   'n' : self.clearStack, 'u' : self.stackUnderStack
48
                                   }
49
        self.EAST = (1,0)
50
        self.WEST = (-1,0)
51
        self.NORTH = (0,1)
52
        self.SOUTH = (0,-1)
53
        
54
        self.delta = self.EAST
55
        
56
        if __name__ == "__main__":
57
            if '-f' in sys.argv:
58
                self.loadASCIIFile(sys.argv[sys.argv.index('-f')+1])
59
            if '-c' in sys.argv:
60
                self.loadCSVFile(sys.argv[sys.argv.index('-c')+1])
61
            
62
            if '-v' in sys.argv:
63
                self.verbose = True
64
            
65
            if len(self.program):
66
                self.run()
67
    
68
    def clearProgram(self):
69
        self.program = {}
70
        
71
    def loadASCIIFile(self,filePath):
72
        file = open(filePath)
73
        charinput = file.readlines()
74
        self.clearProgram()
75
        for y in range(0,len(charinput)):
76
            for x in range(0,len(charinput[y])-1):#1 to cut off newlines! check spec on this, we might need to account for /r/n
77
                self.program[(x,y)] = charinput[y][x]
78
    
79
    def loadCSVFile(self,filePath):
80
        self.clearProgram()
81
        y = 0
82
        width = 0
83
        with open(filePath, newline='') as csvfile:
84
            reader = csv.reader(csvfile, delimiter="\t", quotechar='"')
85
            for row in reader:
86
                if self.verbose:
87
                    print(row)
88
                width = max(len(row),width)
89
                for x in range(0,len(row)):
90
                    char = row[x]
91
                    if char == '':
92
                        char = ' '
93
                    self.program[(x,y)] = char
94
                y += 1
95
        
96
            
97
    def run(self):
98
        self.pointerPosition = (0,0)
99
        
100
        while not self.exitStateFound:# and self.tick < 300:
101
            self.tick +=1
102
            if self.verbose:
103
                currentCommand = self.getCommand()
104
                print(self.stack)
105
                #print("pointer position: " + str(self.pointerPosition))
106
                #print("direction: " +str(self.delta))
107
                print("current command: " + currentCommand)
108
                #print('tick: '+ str(self.tick))
109
                print('-'*20)
110
            self.processCommand()
111
        
112
        return self.exitValue
113
            
114
    def getCommand(self):
115
        if self.stringMode:
116
            if self.program.get(self.pointerPosition," ") == " ":
117
                #return space and set program counter to place before the next value
118
                while self.program.get(self.pointerPosition," ") == " ":
119
                    self.advance()
120
                self.retreat()
121
                return " "
122
            else:
123
                return self.program[self.pointerPosition]
124
        else:
125
            if self.program.get(self.pointerPosition," ") == ";":
126
                self.advance()
127
                while self.program.get(self.pointerPosition," ") != ";":
128
                    self.advance()
129
                self.advance()
130
                return self.getCommand()
131
            elif self.program.get(self.pointerPosition," ") == " ":
132
                while self.program.get(self.pointerPosition," ") == " ":
133
                    self.advance()
134
                return self.getCommand()
135
            else:
136
                return self.program[self.pointerPosition]
137
    
138
    def processCommand(self):
139
        currentCommand = self.getCommand()
140
        if self.stringMode:
141
            self.string()    
142
        elif currentCommand in set("1234567890abcdef"):#TODO: make these into functions cuz its faster
143
            self.push(int(currentCommand,16))#pretty sure we should do int here
144
        else:
145
            self.functionDictionary.get(currentCommand,self.error)()     
146
        self.advance()
147
        
148
    def error(self):
149
        print("unexpected character encountered, '" + str(self.getCommand()) + "' at " + str(self.pointerPosition))
150
        exit()
151
    
152
    def advance(self):#TODO: implement lahey-space wraparound
153
        screenspaceDelta = (self.delta[0],-self.delta[1])#delta is stored as coordinate delta. in screenspace positive y is flipped. this affects the turning functions
154
        self.pointerPosition = tuple(map(lambda x,y: x+y,self.pointerPosition,screenspaceDelta))
155
    
156
    def retreat(self):#technically I dont have to implement the wraparound for this function because its internal
157
        self.pointerPosition = tuple(map(lambda x,y: x-y,self.pointerPosition,self.delta))
158
159
    def pop(self,n=""):#TODO: figure out how they do default n
160
        return self.stack[0].pop(n)
161
    def push(self,value):
162
        self.stack[0].push(value)
163
164
    #command functions    
165
    def add(self):
166
        a,b = self.pop(),self.pop()
167
        self.push(a+b)
168
    def subtract(self):
169
        a,b = self.pop(),self.pop()
170
        self.push(b-a)
171
    def multiply(self):
172
        a,b = self.pop(),self.pop()
173
        self.push(a*b)
174
    def divide(self):
175
        a,b = self.pop(),self.pop()
176
        self.push(b//a)#will error on 0 currently
177
    def modulus(self):
178
        a,b = self.pop(),self.pop()
179
        self.push(b%a)#will error on 0 currently
180
    def logicalNot(self):#not is reserved lol
181
        a = self.pop()
182
        if a==0:
183
            a = 1
184
        else:
185
            a = 0
186
        self.push(a)
187
    def greaterThan(self):
188
        a,b = self.pop(),self.pop()
189
        if b>a:
190
            self.push(1)
191
        else:
192
            self.push(0)
193
    def west(self):
194
        self.delta = self.WEST
195
    def east(self):
196
        self.delta = self.EAST
197
    def north(self):
198
        self.delta = self.NORTH
199
    def south(self):
200
        self.delta = self.SOUTH
201
    def randomDirection(self):
202
        self.delta = random.choice([self.WEST,self.EAST,self.NORTH,self.SOUTH])
203
    def westOrEast(self):
204
        a = self.pop()
205
        if a==0:
206
            self.delta = self.EAST
207
        else:
208
            self.delta = self.WEST
209
    def northOrSouth(self):
210
        a = self.pop()
211
        if a==0:
212
            self.delta = self.SOUTH
213
        else:
214
            self.delta = self.NORTH
215
    def string(self):
216
        if not self.stringMode:
217
            self.stringMode = True;
218
        else:
219
            currentCommand = self.getCommand()
220
            if currentCommand == self.stringCharacter:
221
                self.stringMode = False;
222
            else:
223
                self.push(ord(currentCommand))
224
    def duplicate(self):
225
        a = self.pop()
226
        self.push(a)
227
        self.push(a)
228
    def swap(self):
229
        x,y = self.pop(),self.pop()
230
        self.push(x)
231
        self.push(y)
232
    def intPrint(self):
233
        print(self.pop(),end="")
234
    def strPrint(self):
235
        print(chr(self.pop()),end="")
236
    def jump(self):
237
        self.advance()
238
    def put(self):
239
        y,x,v = self.pop(),self.pop(),self.pop()
240
        x,y = x+self.storageOffset[0],y+self.storageOffset[1]
241
        
242
        self.program[(x,y)] = chr(v)
243
    def get(self):
244
        y,x = self.pop(),self.pop()
245
        x,y = x+self.storageOffset[0],y+self.storageOffset[1]
246
        
247
        self.push(ord(self.program[(x,y)]))
248
    def inputNumber(self):#spec says to extract first contiguous base 10 number from input
249
        #msvcrt.getch() #wai wont u work
250
        m = re.search('\d+',input())
251
        self.push(int(m.group(0)))#currently errors if not found. maybe reflect()?
252
        
253
    def inputChar(self):
254
        #self.push(ord(msvcrt.getch()))
255
        self.push(ord(input()))
256
    def end(self):
257
        self.exitStateFound = True
258
    def noop(self):
259
        ""
260
    
261
    def turnLeft(self):
262
        x,y = self.delta
263
        y *= -1
264
        self.delta = (y,x)
265
    def turnRight(self):
266
        x,y = self.delta
267
        x *= -1
268
        self.delta = (y,x)
269
            
270
    def reverse(self):#todo: hooray, I can do lambdas. they'll be the first to go when I start optomizing
271
        self.delta = tuple(map(lambda x: x*-1,self.delta))
272
    
273
    def popVector(self):
274
        y,x = self.pop(),self.pop()
275
        self.delta = (x,y)
276
    
277
    def jumpOver(self):#TODO: incorporate this and space into getCommand. they take 0 ticks, and certain instructions require getCommand to return the next actual valid character
278
        if not self.jumpOverMode:
279
            self.jumpOverMode = True
280
        else:
281
            if self.getCommand() == self.jumpOverCharacter:
282
                self.jumpOverMode = False
283
    
284
    def jumpForward(self):
285
        num = self.pop()
286
        if num > 0:
287
            for i in range(0,num):
288
                self.advance()
289
        else:
290
            for i in range(0,num*-1):
291
                self.retreat()
292
    
293
    def quit(self):
294
        self.exitStateFound = True
295
        self.exitValue = self.pop()
296
        
297
    def iterate(self):
298
        num = self.pop()
299
        self.advance()
300
        command = self.getCommand()
301
        for i in range(0,num):
302
            self.functionDictionary[command]()
303
    
304
    def compare(self):
305
        b,a = self.pop(),self.pop()
306
        if a < b:
307
            self.turnLeft()
308
        elif a == b:
309
            self.noop()
310
        else:
311
            self.turnRight()
312
    
313
    #TODO: do pushthrough functions. 0-9 and a-f
314
    #TODO: in string mode, spaces are NOT ignored, but are truncated to a single space
315
    def fetchCharacter(self):
316
        self.advance()
317
        self.push(ord(self.getCommand()))
318
        
319
    def store(self):
320
        self.advance()
321
        self.program[self.pointerPosition] = chr(self.pop())
322
        
323
    def clearStack(self):
324
        self.stack[0]= Stack()
325
        
326
    def beginBlock(self):
327
        n = self.pop()
328
        if n < 0:
329
            self.stack.prepend(Stack([0]*n))
330
        else:
331
            self.stack.appendleft(Stack(self.stack[0].list[-n:]))#have to use list here for now
332
        self.stack[1].push(self.storageOffset[0])
333
        self.stack[1].push(self.storageOffset[1])
334
        self.storageOffset = tuple(map(lambda x,y: x+y,self.pointerPosition,self.delta))
335
        
336
    def endBlock(self):
337
        if len(self.stack) > 1:
338
            n = self.pop()
339
            y,x = self.stack[1].pop(),self.stack[1].pop()
340
            self.storageOffset = (x,y)
341
            if n < 0:
342
                for i in range(0,n):
343
                    self.stack[1].pop()
344
            else:
345
                self.stack[1].list += self.stack[0].list[-n:]#using list here too
346
            self.stack.popleft()
347
        else:
348
            self.reverse();
349
            
350
    def stackUnderStack(self):
351
        if len(self.stack) == 1:
352
            self.reverse()
353
        else:
354
            n = self.pop()
355
            if n > 0:
356
                for i in range(0,n):
357
                    self.push(self.stack[1].pop())
358
            elif n < 0:
359
                for i in range(0,-n):
360
                    self.stack[1].push(self.pop())#TODO: check if push is valid for python lists and get rid of all appends
361
                    #more TODO: need to create class for stacks. pop() needs to return 0 if nothing is on the stack, which it wont right now
362
                    
363
                  
364
    #TO BE CONTINUED
365
        
366
        
367
b = BefungeInterpreter()
368
b.verbose = False#True
369
b.loadCSVFile('dice.csv')
370
#b.loadASCIIFile('befunge.txt')
371
372
b.run()