- changed the comments, giving the interface for cmp and swap
- added a reminder about what is supposed to be the pivot
- it works. with my approch without any troubles on the way, so looks good on user's side
- error messages seem ok. I'd still prefer the errors to be caught and transformed into a
test.fail(...)
- when scanning the tests, it seems very weird to have
swap_allowed
anddisallowed_swap
=> maybe rename one? unless they are actually opposite of each others, meaning only one should survive?
I didn't try to break it because I'm very bad at this (and mostly "not interested in that"). Seems mostly fine, from what I grab of it.
import random # Rules: # - no need to return anything # - the pivot is always the first value in the list # - `cmp(i,j)`: return -1,0 or 1 depending on element at index i being (resp) lower, equal or bigger than the element at index j. May be used `length` times # - `swap(i,j)`: exchange elements at index i and j. May be used at most one time, only after a call to `cmp` def one_quicksort_pass(n, cmp, swap): l,i,r = 0,0,n while i<r: match cmp(i,l): case 0: i+=1 case -1: swap(i,l) ; l,i = l+1,i+1 case 1: swap(i,r-1) ; r-=1
- import random
# enforced rules:# - `cmp` may be used `length` times# - `swap` may be used at most one times after `cmp`## ... thoughts?- # Rules:
- # - no need to return anything
- # - the pivot is always the first value in the list
- # - `cmp(i,j)`: return -1,0 or 1 depending on element at index i being (resp) lower, equal or bigger than the element at index j. May be used `length` times
- # - `swap(i,j)`: exchange elements at index i and j. May be used at most one time, only after a call to `cmp`
# this is :carrot:'s solution used as demo# don't comment on the kumite since then this shows up on the front page with solutiondef one_quicksort_pass(length, cmp, swap):e, i, w = length - 1, 1, 1while i <= e:c = cmp(i-w, i)if c > 0:swap(i-w, i)i += 1elif c < 0:if random.randrange(5): # 20% chance to behave wrong, remove condition for correct solutionswap(i, e)e -= 1else:w += 1i += 1- def one_quicksort_pass(n, cmp, swap):
- l,i,r = 0,0,n
- while i<r:
- match cmp(i,l):
- case 0: i+=1
- case -1: swap(i,l) ; l,i = l+1,i+1
- case 1: swap(i,r-1) ; r-=1
note that it's not a position
, but a move
. Otherwise none of the answers are meaningful.
function* powerfulGen(n) { let i = 0; while (++i<n) yield i & -i; } const powerfulArray = n => [...powerfulGen(2**n)];
- function* powerfulGen(n) {
- let i = 0;
while (++i<n) yield parseInt(i.toString(2).match(/10*$/), 2);- while (++i<n) yield i & -i;
- }
- const powerfulArray = n => [...powerfulGen(2**n)];
man, you didn't call the functions! x)
def purple(): return 'purple' def red(): raise ZeroDivisionError() def blue(): return (1/3) * 3
- def purple():
- return 'purple'
- def red():
raise ZeroDivisionError- raise ZeroDivisionError()
- def blue():
- return (1/3) * 3
from preloaded import describe, it import codewars_test as test import solution with describe("Testing Assertions"): with it("unexcpected raised exception on user side"): print("if __exit__ returns True: no error detected, if not, tests are stopped") test.assert_equals(solution.red(), "purple") with it("Equality"): test.assert_equals(solution.purple(), "purple") test.assert_equals(solution.purple(), "red") test.assert_equals(solution.purple(), "blue", "This test failed because you are dumb") # test.assert_equals(solution.purple(), "red", allow_raise=True) test.assert_equals(solution.purple(), "purple", "This test failed because you are dumb") with it("Non Equality"): test.assert_not_equals(solution.purple(), "purple") test.assert_not_equals(solution.purple(), "red") test.assert_not_equals(solution.purple(), "blue", "This test failed because you are dumb") test.assert_not_equals(solution.purple(), "purple", "This test failed because you are dumb") with it("Approx Equality"): test.assert_approx_equals(solution.blue(), 1) test.assert_approx_equals(solution.blue(), 1, margin=1e-9) test.assert_approx_equals(solution.blue(), 2, message="This test failed because you are dumb") test.assert_approx_equals(solution.blue(), 1, message="This test failed because you are dumb") with it("Truthiness"): test.expect(1) test.expect(0) test.expect(1, message="Really though?") test.expect(0, message="Failure. Abort mission.") with it("Pass/Fail"): test.pass_() test.fail("FAILURE!") with it("Expecting Errors"): test.expect_error("is there an error1?", solution.purple) test.expect_error("is there an error2?", solution.red) test.expect_error("is there an error3?", solution.red, exception=TypeError) test.expect_error("is there an error4?", solution.red, exception=ZeroDivisionError) with it("Expecting No Errors"): test.expect_no_error("is there an error1?", solution.purple) test.expect_no_error("is there an error2?", solution.red) test.expect_no_error("is there an error3?", solution.red, exception=TypeError) test.expect_no_error("is there an error4?", solution.red, exception=ZeroDivisionError) with describe("Nested describe"): with it("yes."): test.expect(True) with describe("Really nested."): with it("There you go."): test.expect(False)
- from preloaded import describe, it
- import codewars_test as test
- import solution
- with describe("Testing Assertions"):
- with it("unexcpected raised exception on user side"):
- print("if __exit__ returns True: no error detected, if not, tests are stopped")
- test.assert_equals(solution.red(), "purple")
- with it("Equality"):
- test.assert_equals(solution.purple(), "purple")
- test.assert_equals(solution.purple(), "red")
- test.assert_equals(solution.purple(), "blue", "This test failed because you are dumb")
- # test.assert_equals(solution.purple(), "red", allow_raise=True)
- test.assert_equals(solution.purple(), "purple", "This test failed because you are dumb")
- with it("Non Equality"):
- test.assert_not_equals(solution.purple(), "purple")
- test.assert_not_equals(solution.purple(), "red")
- test.assert_not_equals(solution.purple(), "blue", "This test failed because you are dumb")
- test.assert_not_equals(solution.purple(), "purple", "This test failed because you are dumb")
- with it("Approx Equality"):
- test.assert_approx_equals(solution.blue(), 1)
- test.assert_approx_equals(solution.blue(), 1, margin=1e-9)
- test.assert_approx_equals(solution.blue(), 2, message="This test failed because you are dumb")
- test.assert_approx_equals(solution.blue(), 1, message="This test failed because you are dumb")
- with it("Truthiness"):
- test.expect(1)
- test.expect(0)
- test.expect(1, message="Really though?")
- test.expect(0, message="Failure. Abort mission.")
- with it("Pass/Fail"):
- test.pass_()
- test.fail("FAILURE!")
- with it("Expecting Errors"):
test.expect_error("is there an error?", solution.purple)test.expect_error("is there an error?", solution.red)test.expect_error("is there an error?", solution.red, exception=TypeError)test.expect_error("is there an error?", solution.red, exception=ZeroDivisionError)- test.expect_error("is there an error1?", solution.purple)
- test.expect_error("is there an error2?", solution.red)
- test.expect_error("is there an error3?", solution.red, exception=TypeError)
- test.expect_error("is there an error4?", solution.red, exception=ZeroDivisionError)
- with it("Expecting No Errors"):
test.expect_no_error("is there an error?", solution.purple)test.expect_no_error("is there an error?", solution.red)test.expect_no_error("is there an error?", solution.red, exception=TypeError)test.expect_no_error("is there an error?", solution.red, exception=ZeroDivisionError)- test.expect_no_error("is there an error1?", solution.purple)
- test.expect_no_error("is there an error2?", solution.red)
- test.expect_no_error("is there an error3?", solution.red, exception=TypeError)
- test.expect_no_error("is there an error4?", solution.red, exception=ZeroDivisionError)
- with describe("Nested describe"):
- with it("yes."):
- test.expect(True)
- with describe("Really nested."):
- with it("There you go."):
- test.expect(False)
nice. You forgot to handle errors, tho
import codewars_test as test import threading import queue class itCatcher: def __init__(self, title): self.title = title def __enter__(self, *_whatever): # I'm sure there's a more suitable sync primitive, but, hey, queues. self.wait = queue.Queue() entered = queue.Queue() self.exited = queue.Queue() def hold(): @test.it(self.title) def impostor(): entered.put(()) self.wait.get() self.exited.put(()) threading.Thread(target=hold).start() entered.get() def __exit__(self, *_whatever): self.wait.put(()) self.exited.get() return True class it: def __init__(self, title): self.title = title def __enter__(self, *_whatever): # I'm sure there's a more suitable sync primitive, but, hey, queues. self.wait = queue.Queue() entered = queue.Queue() self.exited = queue.Queue() def hold(): @test.it(self.title) def impostor(): entered.put(()) self.wait.get() self.exited.put(()) threading.Thread(target=hold).start() entered.get() def __exit__(self, *_whatever): self.wait.put(()) self.exited.get() # same as `it`, copy pasted out of laziness class describe: def __init__(self, title): self.title = title def __enter__(self, *_whatever): # I'm sure there's a more suitable sync primitive, but, hey, queues. self.wait = queue.Queue() entered = queue.Queue() self.exited = queue.Queue() def hold(): @test.describe(self.title) def impostor(): entered.put(()) self.wait.get() self.exited.put(()) threading.Thread(target=hold).start() entered.get() def __exit__(self, *_whatever): self.wait.put(()) self.exited.get() def taste(): return 'black' with describe("Once upon a time ..."): with describe("Help! I'm being oppressed"): with it("should taste like purple"): test.assert_equals(taste(), "purple") with it("should taste like black"): test.assert_equals(taste(), "black") with describe("Should things exist?"): with it("yes."): test.expect(True) with it("nah."): test.expect(False) with describe("Never listening to people"): with it("failing?"): test.fail("nope") with it("passing?"): test.pass_() with it("catching?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg) with it("catching bad?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, NameError) with it("not catching wrong?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, KeyError) with itCatcher("not catching wrong?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, KeyError) with itCatcher("raising?"): raise Exception('Meh!') with it("raising?"): raise Exception('oops')
- import codewars_test as test
- import threading
- import queue
- class itCatcher:
- def __init__(self, title):
- self.title = title
- def __enter__(self, *_whatever):
- # I'm sure there's a more suitable sync primitive, but, hey, queues.
- self.wait = queue.Queue()
- entered = queue.Queue()
- self.exited = queue.Queue()
- def hold():
- @test.it(self.title)
- def impostor():
- entered.put(())
- self.wait.get()
- self.exited.put(())
- threading.Thread(target=hold).start()
- entered.get()
- def __exit__(self, *_whatever):
- self.wait.put(())
- self.exited.get()
- return True
- class it:
- def __init__(self, title):
- self.title = title
- def __enter__(self, *_whatever):
- # I'm sure there's a more suitable sync primitive, but, hey, queues.
- self.wait = queue.Queue()
- entered = queue.Queue()
- self.exited = queue.Queue()
def hodor():- def hold():
- @test.it(self.title)
- def impostor():
- entered.put(())
- self.wait.get()
- self.exited.put(())
threading.Thread(target=hodor).start()- threading.Thread(target=hold).start()
- entered.get()
- def __exit__(self, *_whatever):
- self.wait.put(())
- self.exited.get()
- # same as `it`, copy pasted out of laziness
- class describe:
- def __init__(self, title):
- self.title = title
- def __enter__(self, *_whatever):
- # I'm sure there's a more suitable sync primitive, but, hey, queues.
- self.wait = queue.Queue()
- entered = queue.Queue()
- self.exited = queue.Queue()
def hodor():- def hold():
- @test.describe(self.title)
- def impostor():
- entered.put(())
- self.wait.get()
- self.exited.put(())
threading.Thread(target=hodor).start()- threading.Thread(target=hold).start()
- entered.get()
- def __exit__(self, *_whatever):
- self.wait.put(())
- self.exited.get()
- def taste():
- return 'black'
with describe("Help! I'm being oppressed"):with describe("Once upon a time ..."):- with describe("Once upon a time ..."):
- with describe("Help! I'm being oppressed"):
- with it("should taste like purple"):
- test.assert_equals(taste(), "purple")
- with it("should taste like black"):
- test.assert_equals(taste(), "black")
- with describe("Should things exist?"):
- with it("yes."):
- test.expect(True)
- with it("nah."):
test.expect(False)- test.expect(False)
- with describe("Never listening to people"):
- with it("failing?"): test.fail("nope")
- with it("passing?"): test.pass_()
- with it("catching?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg)
- with it("catching bad?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, NameError)
- with it("not catching wrong?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, KeyError)
- with itCatcher("not catching wrong?"): test.expect_error("msg", lambda: ksjghflshfgkjshfg, KeyError)
- with itCatcher("raising?"): raise Exception('Meh!')
- with it("raising?"): raise Exception('oops')
remove=lambda ಠ‿ಠ:__import__('re').sub(r'[A-Z 0-9]','',ಠ‿ಠ) # I just realized why this is no good :( remove=lambda ಠ‿ಠ:__import__('re').sub(r'[^a-z]','',ಠ‿ಠ) # But this is! x)
remoue=lambda ಠ‿ಠ:__import__('re').sub(r'[A-Z 0-9]','',ಠ‿ಠ) # I just realized why this is no good :(- remove=lambda ಠ‿ಠ:__import__('re').sub(r'[A-Z 0-9]','',ಠ‿ಠ) # I just realized why this is no good :(
remove=lambda s:''.join(__import__('re').findall(r'[a-z]',s)) # can the regex also do the ''.join() ?- remove=lambda ಠ‿ಠ:__import__('re').sub(r'[^a-z]','',ಠ‿ಠ) # But this is! x)
...?
import unittest TESTS = [((3,4), 7),((1,5), 6),((78,81), 159),((9,21), 30),((5,7), 12),((50, 50), 100),((-50, -250), -20)] # dirty... class MyTest(unittest.TestCase): pass for i,(inp,exp) in enumerate(TESTS): setattr(MyTest, f'test{i}', lambda self,args=inp,x=exp: self.assertEqual(add(*args), x)) TESTS = [((3,4), 7),((1,5), 6),((78,81), 159),((9,21), 30),((5,7), 12),((50, 50), 100),((-50, -250), -1)] # better... but cannot find how to execute them... x) Somebody? class MyTest0(unittest.TestCase): def fixed_tests(self): for i,(inp,exp) in enumerate(TESTS): with self.subTest(i=i): self.assertEqual(add(*inp), exp) if __name__ == '__main__': # doesn't change anything unittest.main()
- import unittest
class MyTest(unittest.TestCase):def test0(self):self.assertEqual(add(3,4), 7)def test1(self):self.assertEqual(add(1,5), 6)def test2(self):self.assertEqual(add(78,81), 159)def test3(self):self.assertEqual(add(9,21), 30)def test4(self):self.assertEqual(add(5,7), 12)def test5(self):self.assertEqual(add(50, 50), 100)def test6(self):self.assertEqual(add(-50, -250), -300)if __name__ == '__main__':unittest.main()- TESTS = [((3,4), 7),((1,5), 6),((78,81), 159),((9,21), 30),((5,7), 12),((50, 50), 100),((-50, -250), -20)]
- # dirty...
- class MyTest(unittest.TestCase): pass
- for i,(inp,exp) in enumerate(TESTS):
- setattr(MyTest, f'test{i}', lambda self,args=inp,x=exp: self.assertEqual(add(*args), x))
- TESTS = [((3,4), 7),((1,5), 6),((78,81), 159),((9,21), 30),((5,7), 12),((50, 50), 100),((-50, -250), -1)]
- # better... but cannot find how to execute them... x) Somebody?
- class MyTest0(unittest.TestCase):
- def fixed_tests(self):
- for i,(inp,exp) in enumerate(TESTS):
- with self.subTest(i=i):
- self.assertEqual(add(*inp), exp)
- if __name__ == '__main__': # doesn't change anything
- unittest.main()
divisors=lambda n,r=[]:r.clear()or[d for d in range(1,int(n**.5+1))if n%d<1 and(d-n//d and r.append(n//d)or 1)]+r[::-1]
def divisors(n):rev=[]return [d for d,x,r in ((d,*divmod(n,d)) for d in range(1,int(n**.5+1)))if not r and (d!=x and rev.append(x)or 1)] + rev[::-1]- divisors=lambda n,r=[]:r.clear()or[d for d in range(1,int(n**.5+1))if n%d<1 and(d-n//d and r.append(n//d)or 1)]+r[::-1]
(just for fun...)
def divisors(n): rev=[] return [d for d,x,r in ((d,*divmod(n,d)) for d in range(1,int(n**.5+1))) if not r and (d!=x and rev.append(x)or 1)] + rev[::-1]
- def divisors(n):
res,rev,h=[],[],int(n**.5)for d in range(1,h+1):x,r = divmod(n,d)if not r:res.append(d)if x!=d: rev.append(x)return res+rev[::-1]- rev=[]
- return [d for d,x,r in ((d,*divmod(n,d)) for d in range(1,int(n**.5+1)))
- if not r and (d!=x and rev.append(x)or 1)] + rev[::-1]
def divisors(n): res,rev,h=[],[],int(n**.5) for d in range(1,h+1): x,r = divmod(n,d) if not r: res.append(d) if x!=d: rev.append(x) return res+rev[::-1]
- def divisors(n):
- res,rev,h=[],[],int(n**.5)
- for d in range(1,h+1):
if not n%d:- x,r = divmod(n,d)
- if not r:
- res.append(d)
if n//d!=d: rev.append(n//d)- if x!=d: rev.append(x)
- return res+rev[::-1]
-
i in res
is just... bad. This is O(n) containment check -
int(i/n)
is just... bad too. Use the appropriate operator://
-
sorted(dict.fromkeys(res))
is also... bad:- use a set, not a dict (faster)
- actually, don't use a set or a dict at all: just don't generate duplicates => since you store the divisor and its "complementary" value, you just need to go upto sqrt(n), not n/2
- all numbers are generated in some kind of specific order, so find a way to not sort them => build two lists.
def divisors(n): res,rev,h=[],[],int(n**.5) for d in range(1,h+1): if not n%d: res.append(d) if n//d!=d: rev.append(n//d) return res+rev[::-1]
- def divisors(n):
res=[]for i in range(1,int(n*0.5)+1):if i in res: breakif n % i == 0:res.append(i)res.append(int(n / i))return sorted(dict.fromkeys(res))- res,rev,h=[],[],int(n**.5)
- for d in range(1,h+1):
- if not n%d:
- res.append(d)
- if n//d!=d: rev.append(n//d)
- return res+rev[::-1]
?
BRAINFUCK VIZUALISER
How to use it:
Debugging commands usable in the BF code:
'?' char in the code to choose the debugging points.
You cnan name the check points with r'\w+' characters after the ?
'!' char to switch on/off the full debugging (print at the execution of each segment)
Other global switches available:
ALL: vizualisation at each step of the code (each segment). Only when you're desperate...
DEACTIVATE: force the deactivation of the vizualisation whatever is found in the code or the other switches are
CHAR_MODE: if True, the tape will display ascii chars instead of numbers (Note: unprintable chars won't show up...)
LIMITER: interrupt the executions after this number of printing. The count is reseted for each test
Here is the kind of output you get, with the code joint (note: I messed up the code of a previously completed kata):
Input: 3
?START
[ 0, 1, 51] tape
[ 0, 0, 1] p
out = ''
?REMOVE_SOME
[ 0, 1, 13, 0] tape
[ 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 51, 0, 1] tape
[ 0, 0, 0, 0, 1] p
out = ''
?GET_DECIMAL
[ 0, 1, 51, 0, 0, 0] tape
[ 0, 0, 0, 0, 0, 1] p
out = ''
Input: 3
3 should be 3
SUCCESS
---
Input: 1.5
?START
[ 0, 1, 49] tape
[ 0, 0, 1] p
out = ''
?REMOVE_SOME
[ 0, 1, 11, 0] tape
[ 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 0, 1] tape
[ 0, 0, 0, 0, 1] p
out = ''
?START
[ 0, 1, 49, 46, 0] tape
[ 0, 0, 0, 1, 0] p
out = ''
?REMOVE_SOME
[ 0, 1, 49, 8, 0] tape
[ 0, 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 46, 0, 1] tape
[ 0, 0, 0, 0, 0, 1] p
out = ''
?START
[ 0, 1, 49, 46, 53, 0] tape
[ 0, 0, 0, 0, 1, 0] p
out = ''
?REMOVE_SOME
[ 0, 1, 49, 46, 15, 0] tape
[ 0, 0, 0, 0, 1, 0] p
out = ''
?ISNOTDOT
[ 0, 1, 49, 46, 53, 0, 1] tape
[ 0, 0, 0, 0, 0, 0, 1] p
out = ''
?GET_DECIMAL
[ 0, 1, 49, 46, 53, 0, 0, 0] tape
[ 0, 0, 0, 0, 0, 0, 0, 1] p
out = ''
Input: 1.5
1.5 should be 2
STDERR:
Traceback:
in <module>
AssertionError
"""
Created on Mon Oct 23 21:59:51 2017
BrainFuck tape, pointer & output vizualizer
@author: Blind4Basics - CodeWars
"""
# -----------------------------------------------------------------
# Debugging commands usable in the BF code:
#
# '?' char in the code to choose the debugging points.
# You cnan name the check points with r'\w+' characters after the ?
# '!' char to switch on/off the full debugging (print at the execution of each segment)
#
#
# Other global switches available:
#
# ALL: vizualisation at each step of the code (each segment). Only when you're desperate...
# DEACTIVATE: force the deactivation of the vizualisation whatever is found in the code or the other switches are
# CHAR_MODE: if True, the tape will display ascii chars instead of numbers (Note: unprintable chars won't show up...)
# LIMITER: interrupt the executions after this number of printing. The count is reseted for each test
#
# -----------------------------------------------------------------
code = """ # not working example
[
tape: _ S digits _ REF DEC S
]
>+
>,
[?START
>++++[<---------->-]<++
?REMOVE_SOME
[
>++++[<++++++++++>-]<--
>>+<
]
<[<]>[>]>
?ISNOTDOT
[-<,>]<
]
>>,
?GET_DECIMAL
[
>++++[<-------->-]
+<<++++
?
[->[->[>]]<<]
?MINUS4
>[[-]<+>]
?LAST
]
<<<[<]>>[.>]
"""
#------------------------------------------------------------
# Test cases:
#
# 'inputs' and corresponding 'expected' values
# EOF char automatically added at the end of each input
#------------------------------------------------------------
inputs = ["3", "1.5", "101", "101.9", "101.2"]
exp = ["3", "2", "101", "102", "101"]
""" GLOBAL SWITCHES """
ALL = False
DEACTIVATE = False
CHAR_MODE = False
LIMITER = 50
import re
def brainFuckInterpreter(code, prog):
def updateVizu(cmdSegment=''):
def formatLst(lst, charMod=False): # Formater: align the cells of the tape and the list for the pointer
formStr = "{: >" + str(max(map(len, map(str, data)), default=1)) + "}"
return "[{}]".format(', '.join(formStr.format(chr(v) if charMod else v) for v in lst))
if DEACTIVATE: return
countDisplay[0] += 1 # Update the number of display already done (cf. LIMITER)
vizu[-1][lastP[0]] = 0 # Erase the previous position of the pointer
vizu[-1][p] = 1 # Place the pointer at the current position
lastP[0] = p # archive the current position of the pointer
vizu[0] = c[0] # archive the current command
out = ''.join(output)
cmd,tape,point = vizu
print( "\n\n{}{} tape\n{} p\nout = '{}'".format(cmdSegment and cmdSegment+"\n",
formatLst(tape, CHAR_MODE),
formatLst(point),
out) )
if LIMITER >= 0 and LIMITER == countDisplay[0]: raise Exception("Too much printing: LIMITER = {}".format(LIMITER))
def tapeLenUpdater(): # Make the tape length consistent with the actual position of the pointer (even if no value yet in the cells)
if p >= len(data):
data.extend( [0] * (p-len(data)+1) )
vizu[-1].extend( [0] * (len(data)-len(vizu[-1])) )
def getNextInput(): # Simulate getting u'0000' when trying to get an input char after their exhaustion
try:
return ord(next(prog))
except StopIteration:
return 0
p, lastP, i = 0, [0], 0 # p = pointer / lastP = previous P position (mutated) / i = segment of code index
data = [0] # Tape initialization
SWITCH, countDisplay = False, [0] # SWITCH: control for the "!" cmd swtich / countDisplay = control for LIMITER (as list to mutate it from a subroutine)
output, vizu = [], ['', data, [0]] # vizu: [cmd, tape, pointer list]
prog = iter(prog)
code = re.findall(r'\++|<+|>+|-+|[,.[\]]|\?\w*|!', code) # Make the executions more compact by using only segments of identical commands (=> '++++', '<<<', '[', '-', ']', check points with identifiers...)
while 0 <= i < len(code):
c = code[i]
if False: print(c, data, p) # activate manually. Only for debugging of the vizualiser itself...
if c[0] == '+': data[p] = (data[p] + len(c)) % 256
elif c[0] == '-': data[p] = (data[p] - len(c)) % 256
elif c[0] == '>': p += len(c) ; tapeLenUpdater()
elif c[0] == '<': p -= len(c) ; tapeLenUpdater()
elif c[0] == '.': output.append(chr(data[p]))
elif c[0] == ',': data[p] = getNextInput()
elif c[0] == '[':
if not data[p]:
depth = 1
while depth > 0:
i += 1
c = code[i]
if c == '[': depth += 1
elif c== ']': depth -= 1
elif c == ']':
if data[p]:
depth = 1
while depth > 0:
i -= 1
c = code[i]
if c == ']': depth += 1
elif c == '[': depth -= 1
# Vizualisation commands/executions
#--------------------
elif c[0] == '?': updateVizu(c) # check point found
if ALL or SWITCH and c[0] != "?": updateVizu(c) # Vizualisation for swithes (avoid double printing for check points)
if c[0] == '!': SWITCH = not SWITCH # Update '!' swtich state
#--------------------
i += 1
return ''.join(output)
#--------------------
# LAUNCH THE TESTS
#--------------------
EOF = chr(0)
for p,e in zip(inputs,exp):
print("Input: ", p)
act = brainFuckInterpreter(code, p+EOF)
print("Input: ", p) # remainder of the input
print(act, " should be ", e) # print actual/expected before assertion
assert act == e
print("SUCCESS\n---\n")