Ad
  • 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 and disallowed_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.

Code
Diff
  • 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 solution
    • def one_quicksort_pass(length, cmp, swap):
    • e, i, w = length - 1, 1, 1
    • while i <= e:
    • c = cmp(i-w, i)
    • if c > 0:
    • swap(i-w, i)
    • i += 1
    • elif c < 0:
    • if random.randrange(5): # 20% chance to behave wrong, remove condition for correct solution
    • swap(i, e)
    • e -= 1
    • else:
    • w += 1
    • i += 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.

Code
Diff
  • def knight_move3d(position=(0, 0, 0)):
        return sorted(map(abs,position))==[0,1,2]
    • def knight_move3d(position=(0, 0, 0)):
    • cord = [abs(n) for n in position]
    • return 0 in cord and 1 in cord and 2 in cord or cord == position
    • return sorted(map(abs,position))==[0,1,2]
Code
Diff
  • 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)

Code
Diff
  • 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

nice. You forgot to handle errors, tho

Code
Diff
  • 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)
Code
Diff
  • remove=lambda s:''.join(filter(str.islower,s))
    • remove=lambda s:''.join([c for c in s if c.islower()])
    • remove=lambda s:''.join(filter(str.islower,s))

...?

Code
Diff
  • add=int.__add__
    • add = lambda x, y : add(x ^ y, (x & y) << 1) if y else x
    • add=int.__add__
Performance
Code
Diff
  • 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]
Performance

(just for fun...)

Code
Diff
  • 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]
Performance
Code
Diff
  • 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]
Performance
  • 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.
Code
Diff
  • 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: break
    • if 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]

?

Code
Diff
  • from math import hypot as hypotenuse
        
    • from math import *
    • def hypotenuse(a, b): return hypot(a,b)
    • from math import hypot as hypotenuse

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")