Begin a new Kumite
Search
About
  • Filter by Language:
  • Kumite (ko͞omiˌtā) is the practice of taking techniques learned from Kata and applying them through the act of freestyle sparring.

    You can create a new kumite by providing some initial code and optionally some test cases. From there other warriors can spar with you, by enhancing, refactoring and translating your code. There is no limit to how many warriors you can spar with.

    A great use for kumite is to begin an idea for a kata as one. You can collaborate with other code warriors until you have it right, then you can convert it to a kata.

Actually, that was double -> int, now int -> double.

Code
Diff
  • global to_double
    section .text
    to_double:
                    cvtsi2sd    xmm0, edi
                    ret
    
  • 1-global trunc_
    1+global to_double
    22 section .text
    3-trunc_:
    4- cvttsd2si eax, xmm0
    3+to_double:
    4+ cvtsi2sd xmm0, edi
    55 ret

String literals are stored as read-only (const), and any attempt to modify the pointer returned will result in a SEGFAULT (crash) in most current computing environments.

Obvserving the following assembly output from GCC:

    .file   "tst.c"
    .text
    .section    .rodata
.LC0:
    .string "Hello World."
    .text
    .globl  Hi
    .type   Hi, @function
Hi:

You can see string literal referred to by label .LC0 is defined within section '.rodata' meaning ready-only data.

Therefore Hi() should have a return type of const char* to avert the possibility of such faulty access occurring.

Code
Diff
  • const char* Hi (void)
    {
      return("Hello World.");
    }
    
    char *oopsHi(void)
    {
      return ("Hello World.");
    }
    
  • 1-char* Hi (void)
    1+const char* Hi (void)
    22 {
    3-return("Hello World.");
    3+ return("Hello World.");
    4+}
    5+
    6+char *oopsHi(void)
    7+{
    8+ return ("Hello World.");
    44 }
Code
Diff
  • syntax error here again
  • 1-syntax error here
    1+syntax error here again
Code
Diff
  • using System;
    
    namespace Solution {
    
      class FizzBuzz {
        public static string Convert(int input)
            {
                var divisableBy3 = input % 3 == 0;
                var divisableBy5 = input % 5 == 0;
                
                return (!divisableBy3 & !divisableBy5) ? input.ToString()
                  : (divisableBy3 ? "Fizz" : string.Empty) +  (divisableBy5 ? "Buzz" : string.Empty);
            }
      }
    }
  • 11 using System;
    22
    33 namespace Solution {
    44
    55 class FizzBuzz {
    66 public static string Convert(int input)
    77 {
    8- var divisableBy3 = (input % 3 == 0);
    9- var divisableBy5 = (input % 5 == 0);
    8+ var divisableBy3 = input % 3 == 0;
    9+ var divisableBy5 = input % 5 == 0;
    1010
    1111 return (!divisableBy3 & !divisableBy5) ? input.ToString()
    1212 : (divisableBy3 ? "Fizz" : string.Empty) + (divisableBy5 ? "Buzz" : string.Empty);
    1313 }
    1414 }
    1515 }
Advanced Language Features
Fundamentals

Pointers

Fortran has basic support for pointers. A pointer is a rather primitive type of reference - it is essentially a memory address (associated with a given type) which is said to "point to" the data it is referencing. Unlike C/C++/ObjC, Fortran does not support pointers to pointers, function pointers, arrays of pointers or pointer arithmetic but it is still sufficient to allow us to define simple recursive datatypes such as linked lists or binary trees.

To declare a pointer:

integer, pointer :: p ! `p` is a non-associated integer pointer

To associate a pointer to a target:

! The `target` annotation is required for a pointer to point to it
! Otherwise, `n` is just another ordinary integer
integer, target :: n = 42
integer, pointer :: p => n ! `p` is now associated with `n`

To dereference a pointer:

integer, target :: n = 42
integer, pointer :: p => n ! `p` points to `n`
p = 100 ! `p` is automatically dereferenced and its target `n` set to 100

To associate a pointer to another target:

integer, target :: m = 100, n = 42
integer, pointer :: p => n ! `p` points to `n`
p => m ! `p` now points to `m` instead

To make two (or more) pointers point to the same target:

integer, target :: n = 42
integer, pointer :: p1, p2
p1 => n ! `p1` points to `n`
p2 => p1 ! `p2` now points to the TARGET of `p1` which is `n`
! REMEMBER: `p2` does NOT point to `p1` - pointers
! to pointers are not permitted in Fortran

To define a null pointer (i.e. one that does not reference any data):

integer, pointer :: p => null()

To allocate memory for a pointer instead of pointing it to a pre-existing target:

integer, pointer :: p
allocate(p) ! Allocate memory under pointer (just sufficient for one integer)
! Do something with `p`.  Make sure `p` doesn't point to anything else
! before it is deallocated (otherwise a memory leak will occur)!
deallocate(p) ! Free the memory under the pointer

To check whether a pointer is associated with a target:

associated(p) ! Checks whether `p` is associated with a target
! Evaluates to the corresponding logical value
! (.true. if associated, .false. otherwise)

The main code example in this Kumite involves derived data types.

module Pointers
  implicit none
  type Node ! A node of a singly linked list
    integer :: data
    type(Node), pointer :: next
  end type Node
end module Pointers

Operator Overloading

In Fortran, operator overloading is done via interfacing. The syntax is almost identical to overloading procedures except the name of the alias is replaced by operator (OPERATOR) (where OPERATOR is a placeholder for the actual operator).

Unlike some programming languages such as Haskell, operators to be overloaded cannot contain arbitrary symbols (or a sequence thereof). Only the following operators and types of operators can be overloaded/defined:

  • Symbol / symbol combinations already defined as operators in Fortran (e.g. +, -, *, /, ==, /=, etc.)
  • .OPERATOR_NAME. where OPERATOR_NAME may only contain English letters (not even numbers, not even underscore)

Operators can be unary or binary or both (of the form OPERATOR OPERAND or OPERAND_1 OPERATOR OPERAND_2) depending on whether the function(s) implementing it accept one or two arguments. However, for operators intrinsic to Fortran (such as * or /), the functions implemeting their overloads may only accept as many arguments as they were originally defined (e.g. you cannot overload * to accept only one operand).

Note that operators must be pure in Fortran, i.e. they are not permitted to mutate their operands. Therefore, functions implementing the overloaded operator must be declared pure (or if not, at least all input parameters must be declared intent(in)).

module OperatorOverloading
  implicit none
  private :: realRecip, cmplxRecip ! Hide implementation details of overloaded operator
  interface operator (.recip.) ! Operator for finding the reciprocal
  ! (i.e. multiplicative inverse) of a number
    module procedure realRecip, cmplxRecip
  end interface
contains
  pure function realRecip(x)
    real, intent(in) :: x
    real :: realRecip
    realRecip = 1.0 / x
  end function realRecip
  pure function cmplxRecip(z)
    complex, intent(in) :: z
    complex :: cmplxRecip
    cmplxRecip = cmplx(1, 0) / z
  end function cmplxRecip
end module OperatorOverloading

Just a simple C function void say_hello() written in NASM v2.11.x which prints Hello World! to the console.

global say_hello
section .text
say_hello:
  mov eax, 4 ; system call for write (for Linux)
  mov ebx, 1 ; file handle 1 is STDOUT
  mov ecx, message ; memory address of output buffer
  mov edx, msgLen ; size of output buffer in bytes
  int 0x80 ; invoke OS to do the write
  ret ; Return to the caller

section .data ; Read-only data
message db "Hello World!", 10 ; message = "Hello World!\n"
msgLen equ $-message ; msgLen = strlen(message)
Interfaces
Basic Language Features
Object-oriented Programming
Fundamentals

Interfacing

In Fortran modules, it is possible to "overload" a prodecure with several variants, each accepting different types/numbers of arguments through interfacing. An interface is essentially a named alias to one or more defined procedures. For example, when we first introduced functions, our add function was only capable of accepting two default (32-bit) integers and compute its sum (as a 32-bit integer). What if we wanted our add function to work on reals as well? Or complex numbers? In that case, all we have to do is to define three separate functions and implement them accordingly - let's call them addIntegers, addReals and addComplexNumbers. After that, we alias them all under the same name add through interfacing which is achieved by using the interface keyword and has the following syntax (ALL_CAPS denote placeholders):

interface ALIAS_NAME
  module procedure PROC_1, PROC_2, ..., PROC_N
end interface ALIAS_NAME

The interface is always placed at the top section of the module, i.e. before the contains keyword:

module InterfacingExample
  implicit none
  ! Our interface
  interface add
    ! The `addIntegers`, `addReals` and `addComplexNumbers`
    ! functions should all be aliased number the name `add`
    module procedure addIntegers, addReals, addComplexNumbers
  end interface add
contains
  pure function addIntegers(a, b) result(c)
    integer, intent(in) :: a, b
    integer :: c
    c = a + b
  end function addIntegers
  pure function addReals(a, b) result(c)
    real, intent(in) :: a, b
    real :: c
    c = a + b
  end function addReals
  pure function addComplexNumbers(a, b) result(c)
    complex, intent(in) :: a, b
    complex :: c
    c = a + b
  end function addComplexNumbers
end module InterfacingExample

Now let's test it in our program:

program Main
  use InterfacingExample
  implicit none
  print *, add(1, 2) ! > 3 (perhaps with padding)
  print *, add(3.5, 4.5) ! > 8.0 (perhaps with padding)
  print *, add(cmplx(3, -4), cmplx(2, 1)) ! > (5.0, -3.0) (perhaps with padding)
end program Main

Our alias works as expected. However, at this point, you might be wondering if the functions are still accessible through their original names (e.g. addIntegers). If that is the case then your doubts are well-founded - the functions are still accessible through their original names (which may not be desirable). To hide the original names of the functions and expose only the alias, simply declare the original function names as private the same way you would variables/constants:

module InterfacingExample
  implicit none
  private :: addIntegers, addReals, addComplexNumbers
  ! Our interface
  interface add
    ! The `addIntegers`, `addReals` and `addComplexNumbers`
    ! functions should all be aliased number the name `add`
    module procedure addIntegers, addReals, addComplexNumbers
  end interface add
contains
  pure function addIntegers(a, b) result(c)
    integer, intent(in) :: a, b
    integer :: c
    c = a + b
  end function addIntegers
  pure function addReals(a, b) result(c)
    real, intent(in) :: a, b
    real :: c
    c = a + b
  end function addReals
  pure function addComplexNumbers(a, b) result(c)
    complex, intent(in) :: a, b
    complex :: c
    c = a + b
  end function addComplexNumbers
end module InterfacingExample
module InterfacingExample
  implicit none
  private :: addIntegers, addReals, addComplexNumbers
  ! Our interface
  interface add
    ! The `addIntegers`, `addReals` and `addComplexNumbers`
    ! functions should all be aliased number the name `add`
    module procedure addIntegers, addReals, addComplexNumbers
  end interface add
contains
  pure function addIntegers(a, b) result(c)
    integer, intent(in) :: a, b
    integer :: c
    c = a + b
  end function addIntegers
  pure function addReals(a, b) result(c)
    real, intent(in) :: a, b
    real :: c
    c = a + b
  end function addReals
  pure function addComplexNumbers(a, b) result(c)
    complex, intent(in) :: a, b
    complex :: c
    c = a + b
  end function addComplexNumbers
end module InterfacingExample
Functions
Control Flow
Basic Language Features
Fundamentals
Recursion
Algorithms
Computability Theory
Theoretical Computer Science

Fortran Procedures - Subroutines

In a previous Kumite, I mentioned that there are two types of procedures in Fortran:

  1. Functions - These evaluate to a given value which is returned to the caller (for further computation by other parts of the program, for example)
  2. Subroutines - These only perform a set of actions and do not evaluate to any value

This Kumite aims to demonstrate how to define and invoke a Fortran subroutine.

A Fortran subroutine is in fact declared/defined in the same way as a function except the function keyword (in both the first and last lines) are replaced with subroutine. Pretty much everything else that holds for functions also holds for subroutines, with the exception of a lack of return value (and therefore result(<res_var>) annotation is not permitted). You can even declare a subroutine as recursive (and/or even pure)!

module Solution
  implicit none
contains
  recursive subroutine print1ToN(n)
    integer :: n
    if (n > 0) then
      call print1ToN(n - 1) ! NOTE: See explanation below code example
      print "(I0)", n
    end if
  end subroutine print1ToN
end module Solution

When invoking a subroutine, the syntax is slightly different - you have to add the call keyword in front of the subroutine name, like such:

program TestCases
  use Solution
  implicit none
  call print1ToN(10)
  ! > 1
  ! > 2
  ! > ... (you get the idea ;) )
  ! > 10
end program TestCases
module Solution
  implicit none
contains
  recursive subroutine print1ToN(n)
    integer :: n
    if (n > 0) then
      call print1ToN(n - 1) ! NOTE: See explanation below code example
      print "(I0)", n
    end if
  end subroutine print1ToN
end module Solution
Functions
Control Flow
Basic Language Features
Fundamentals
Recursion
Algorithms
Computability Theory
Theoretical Computer Science

Fortran Procedures - Recursive Functions

In my last Kumite you learned how to declare and define a function in Fortran. If you were interested in it, you may have done some experimentation on defining a few of your own. Some of you might even have attempted to define a recursive function in Fortran using the syntax shown in the last Kumite. For example, you might have tried to find the sum of the first n positive integers recursively:

module Solution
  implicit none
contains
  function sum1ToN(n) result(sum)
    integer :: n, sum
    if (n <= 0) then
      sum = 0
    else
      sum = n + sum1ToN(n - 1)
    end if
  end function sum1ToN
end module Solution

However, if you attempted to compile and execute this module (with an accompanying program), you would've seen an error message similar to the following: Error: Function 'sum1ton' at (1) cannot be called recursively, as it is not RECURSIVE. In fact, you can define a recursive function in Fortran, but you need to add the recursive modifier to the beginning of your function declaration in order to do so:

module Solution
  implicit none
contains
  recursive function sum1ToN(n) result(sum)
    integer :: n, sum
    if (n <= 0) then
      sum = 0
    else
      sum = n + sum1ToN(n - 1)
    end if
  end function sum1ToN
end module Solution

Now, when we define our program using this module and test our sum1ToN function, everything works as expected:

program TestCases
    use Solution
    implicit none
    print "(I0)", sum1ToN(10) ! > 55
end program TestCases

The recursive keyword can also be used in conjunction with the pure keyword to specify a pure function that has the capacity to invoke itself recursively.

module Solution
  implicit none
contains
  pure recursive function sum1ToN(n) result(sum)
    integer, intent(in) :: n
    integer :: sum
    if (n <= 0) then
      sum = 0
    else
      sum = n + sum1ToN(n - 1)
    end if
  end function sum1ToN
end module Solution
module Solution
  implicit none
contains
  pure recursive function sum1ToN(n) result(sum)
    integer, intent(in) :: n
    integer :: sum
    if (n <= 0) then
      sum = 0
    else
      sum = n + sum1ToN(n - 1)
    end if
  end function sum1ToN
end module Solution
Functions
Control Flow
Basic Language Features
Fundamentals

Fortran Procedures - Functions, Pass By Reference and Purity

In Fortran it is possible to define reusable sets of instructions that either perform a given action / actions or evaluate to a certain value (or do both) which are called procedures. There are two main types of procedures:

  1. Functions - These eventually evaluate to a certain value which can then be used by the caller. They can be pure (i.e. do not cause any side effects, more on that later) or impure (causing side effects and/or modifying the state of the program in the process).
  2. Subroutines - These only perform a given set of actions and do not evaluate to any value. Subroutines may also be pure/impure.

This Kumite demonstrates how to define and use a function.

A function (and in fact any procedure) can be defined in any module/program (it does not matter which, the declaration syntax is identical in both cases) by placing them at the bottom half of the module/procedure. To do that, the given program/module has to be split into exactly two sections using the contains statement/keyword in between. The top section contains all of the variable declarations and statements of the program/module, while the bottom section contains all of the procedure definitions:

module FunctionExample
  implicit none
  ! Top section - contains all variable declarations/definitions
contains
  ! Bottom section - contains all function and subroutine
  ! (i.e. procedure) definitions
end module FunctionExample

Then, under the contains statement, we declare and define our function using a function declaration of the form function <fn_name>(<var_1>, <var_2>, ..., <var_n>). We end our function definition using end function <fn_name> and our function body goes between these two lines. For example, if we want to declare and define an add function that adds two integers, our module would look like this:

module FunctionExample
  implicit none
  ! Variable declarations
contains
  function add(a, b)
    ! TODO
  end function add
end module FunctionExample

If you've paid any amount of attention to my previous Kumite then it should've occurred to you by now that Fortran is a statically typed language, i.e. each variable has a fixed type that cannot be changed at runtime. However, our function declaration shown above didn't assign any types to the parameters a and b (which we want to be integers). So, how to declare their types? Fortunately, it's very simple and straightforward - just declare them at the top of the function body like you would global variables at the start of a program/module!

module FunctionExample
  implicit none
  ! Variable declarations
contains
  function add(a, b)
    integer :: a, b
  end function add
end module FunctionExample

In our add function, we would like to compute the sum of the integers a and b and return the corresponding integer value to the caller. Unfortunately, there is no return keyword in Fortran so how is it done? In Fortran we must store the result we want to return to the caller in a variable with an identical name to the function name which is add in this case. Our result is anticipated to be an integer so we need to declare the type of add as well:

module FunctionExample
  implicit none
  ! Variable declarations
contains
  function add(a, b)
    integer :: a, b
    integer :: add
  end function add
end module FunctionExample

Then, we simply assign the result of adding a and b to add:

module FunctionExample
  implicit none
  ! Variable declarations
contains
  function add(a, b)
    integer :: a, b
    integer :: add
    add = a + b
  end function add
end module FunctionExample

Now our function declaration/definition is complete and we can use it in our program as desired.

program MyProgram
  use FunctionExample
  implicit none
  print "(I0)", add(3, 5) ! > 8
end program MyProgram

Using a custom variable name for the returned result

What if you don't want to use the function name to store the returned result? For example, instead of add = a + b, you want to do c = a + b and have c store the result to be returned. All you have to do is modify the function declaration to function <fn_name>(<var_1>, <var_2>, ..., <var_n>) result(<result_var>) and subsequently the affected variable declarations:

module FunctionExample
  implicit none
  ! Variable declarations
contains
  function add(a, b) result(c)
    integer :: a, b
    integer :: c
    c = a + b
  end function add
end module FunctionExample

Procedure arguments in Fortran are passed by variable reference, not by value or object reference

Unlike many modern programming languages such as C, Java or Python, procedure (and hence function) arguments in Fortran are passed by variable reference. This means that if you reassign the values of arguments within your function, the passed in variable itself will be affected.

module FunctionExample
  implicit none
contains
  function add(a, b) result(c)
    integer :: a, b
    integer :: c
    a = a + b ! Argument `a` is assigned the value of the result
    c = a ! Result variable `c` assigned the new value of `a`
  end function add
end module FunctionExample
program MyProgram
  use FunctionExample
  implicit none
  integer :: m = 3, n = 5

  ! > m = 3, n = 5
  print "(A4, I0, A6, I0)", "m = ", m, ", n = ", n

  ! > add(m, n) = 8
  print "(A12, I0)", "add(m, n) = ", add(m, n)

  ! This segfaults
  ! print "(I0)", add(3, 5)

  ! > m = 8, n = 5
  print "(A4, I0, A6, I0)", "m = ", m, ", n = ", n
end program MyProgram

Therefore, in Fortran, one must be careful not to assign any new values to existing parameters (unless there is a good reason to do so deliberately).

Pure Functions

A pure function is one that does not mutate its input in any way and does not depend on and/or change the state of the program when it is executed/evaluated. Due to Fortran's pass-by-variable-reference, it is easy to make a mistake and mutate the value of argument variables passed in and therefore violate this rule. Fortunately, Fortran has native syntactical support for these types of functions - simply prepend the function declaration with the pure keyword: pure function <fn_name>(<v1>, <v2>, ..., <vn>) result(<rv>).

By explicitly declaring your function as pure, Fortran enforces compile-time restrictions on the type declarations of all the parameters to ensure that all parameters are declared in a way that their value cannot be reassigned. This means that we need to modify the parameter declarations by adding a comma, followed by intent(in) after the type name (and before the ::) - this tells the Fortran compiler that the values of the parameters are read-only:

module FunctionExample
  implicit none
contains
  pure function add(a, b) result(c)
    integer, intent(in) :: a, b
    integer :: c
    c = a + b
  end function add
end module FunctionExample

Now we can use the add function with the guarantee that it will never mutate its inputs:

program MyProgram
  use FunctionExample
  implicit none
  integer :: m = 3, n = 5
  print "(I0)", add(m, n) ! > 8
  print "(I0)", add(3, 5) ! Works - no segfault :)
  print "(I0)", m ! > 3
  print "(I0)", n ! > 5
end program MyProgram
module FunctionExample
  implicit none
contains
  pure function add(a, b) result(c)
    integer, intent(in) :: a, b
    integer :: c
    c = a + b
  end function add
end module FunctionExample

Just a quick test to see how Preloaded works with GNU Fortran on Codewars ...

module Solution
  use Preloaded
  implicit none
  integer :: n = answer - 42 ! n = 0
end module Solution
Modules
Fundamentals
Object-oriented Programming

Fortran Modules

Fortran modules allow us to split our code into logical chunks across files, each providing a specific functionality and/or set of functionalities and allows us to reuse certain code files in different projects/programs. To create a module, a separate file should first be created. Then, in that separate file, add a module <module_name> statement where <module_name> is a placeholder for the name of our module. In our case, let's name it MyFirstModule. After that, we end our module by adding end module <module_name> on the last line and put everything else in between.

Our module now looks like this:

module MyFirstModule
  ! TODO
end module MyFirstModule

Same as in a program, the first statement inside a module should almost always be implicit none which disables type inference in the case of a programmer error (e.g. forgetting to declare a variable before defining/using it).

module MyFirstModule
  implicit none
  ! TODO
end module MyFirstModule

Apart from the fact that modules are not executed themselves (they are used in other programs which are then executed), they are almost identical to a program, with one major difference: No action can be performed in a module (at least at the top level). This means that you cannot use print statements among other things as you would in a program - you can only declare/define variables, constants and procedures (more on procedures in future Kumite). For example:

module MyFirstModule
  implicit none
  integer, parameter :: answer = 42
  real :: x = 0.0, y = 1.0
  character(len=12) :: hello = "Hello World!"
end module MyFirstModule

Then, to use a module in our program, we add the statement use <module_name> before implicit none:

program MyProgram
  use MyFirstModule
  implicit none
  ! TODO
end program MyProgram

Now our program will be able to see all of the variables, constants and procedures that our module has declared/defined. What if we want to hide the two reals x and y (because it is an implementation detail and not intended to be used directly in a program, for example) from the main program? To do that, we simply add a declaration private :: <variable_or_procedure_name_1>, <variable_or_procedure_name_2>, ..., <variable_or_procedure_name_n> to control its visiblity. Our module now looks like this:

module MyFirstModule
  implicit none
  integer, parameter :: answer = 42
  real :: x = 0.0, y = 1.0
  character(len=12) :: hello = "Hello World!"
  private :: x, y ! x and y are now private to the module itself
  ! and no longer exposed to the program using it
end module MyFirstModule

Finally, we can use the (exposed) variables/constants/procedures from our module in our main program as if they were defined in our program in the first place:

program MyProgram
  use MyFirstModule
  implicit none
  print "(I0)", answer
  print "(A12)", hello
end program MyProgram

See both Kumite "Code" and "Fixture" for the full code example.

module MyFirstModule
  implicit none
  integer, parameter :: answer = 42
  real :: x = 0.0, y = 1.0
  character(len=12) :: hello = "Hello World!"
  private :: x, y ! x and y are now private to the module itself
  ! and no longer exposed to the program using it
end module MyFirstModule
Fundamentals
Variables
Basic Language Features

Constants, Variables and Datatypes in Fortran

In Fortran, there are a few intrinsic datatypes (known as primitive datatypes in other programming languages):

  • integer - An integral value such as 23 or -133. By default, an integer is 4 bytes (32 bits) long. Integers of custom size can be specified using the integer(kind=n) syntax where n is the number of bytes that the integer occupies in memory an can be either of 1, 2, 4, 8 and 16.
  • real - A floating point value such as 2.0 or 3.14. By default, real is single precision (i.e. only 4 bytes long) but real(kind=8) is double precision (since it occupies 8 bytes in memory)
  • complex - A set of (two) floating point values representing a complex number. By default, both floats are single precision but complex(kind=8) holds two double-precision floats instead. Complex numbers are defined using the intrinsic function cmplx with two or three arguments, e.g. cmplx(3, 4) defines a default complex number (components are single precision floating point values) representing the value 3 + 4i
  • logical - A special type of value that can only ever take two values: .true. or .false.. Equivalent to a boolean in most modern programming languages.
  • character - A character (i.e. string with length 1) or character string. By default, it specifies a character such as 'C' or "0" but character(len=n) specifies a character string of length n instead.

Declaration of a variable must be done after implicit none and before any other statements. It takes the following form: <type_name> :: <variable_1>, <variable_2>, ... , <variable_n>. For example, if we want to declare a variable answer with type integer, our program would look like this:

program ConstantsVariablesAndDatatypes
  implicit none
  integer :: answer
end program ConstantsVariablesAndDatatypes

We can also define our variable on the same line as the declaration, like such:

program ConstantsVariablesAndDatatypes
  implicit none
  integer :: answer = 42 ! `=` is the assignment operator
end program ConstantsVariablesAndDatatypes

After we declare a variable, we can assign/reassign to it, use it in our computations and/or print it out as desired. For example:

program ConstantsVariablesAndDatatypes
  implicit none
  integer :: answer = 42
  print "(I0)", answer ! > 42
  answer = 100 ! Reassignment
  print "(I0)", answer ! > 100
end program ConstantsVariablesAndDatatypes

What if we don't want to change the value of a "variable" after initialization? We can do that by adding a comma followed by the parameter keyword to mark a "variable" as a constant. For example:

program ConstantsVariablesAndDatatypes
  implicit none
  real(kind=8), parameter :: PI = 3.141592653589793
end program ConstantsVariablesAndDatatypes

We can then use it in our computations and/or print it out but not reassign to it:

program ConstantsVariablesAndDatatypes
  implicit none
  real(kind=8), parameter :: PI = 3.141592653589793 ! Our PI constant
  print *, PI ! Prints something like "3.141592653589793", perhaps with leading/trailing whitespace

  ! The line below causes compilation to fail with an error
  ! PI = 2.718281828459045
end program ConstantsVariablesAndDatatypes

See "Fixture" of this Kumite for more examples.

module Solution
  ! Please refer to "Fixture" for examples, we will learn about modules in future Kumite ;)
end module Solution
Fundamentals

In my previous Kumite, we learned how to print out Hello World! to the console in Fortran. However, you may have noticed it wasn't perfect - the output has an unnecessary leading whitespace! So, the question is, how to remove it?

When the default settings (denoted by *) is used for the format specifier for print in Fortran, Fortran has to guess how much space it should reserve for the output which it usually overestimates, resulting in undesired padding of the output. To rectify this issue, we can provide our customized format specifier for print.

A customized format specifier for print is passed as a string and is always enclosed in parentheses (). Inside the parentheses, one or more individual format specifiers are separated by a comma , which may or may not be prepended/appended with one or more whitespace characters as desired. The individual format specifiers are as follows:

  • An (n is a positive integer) - a string of length n. For example, A10 specifies that the output contains a string of length 10.
  • I0 - an integer (of any size) containing any number of digits
  • In - an integer containing exactly n digits

There are also many other format specifiers for floating point values, logical values (known as booleans in most modern programming languages) and so on but we won't cover them in this Kumite.

Since we know that the string "Hello World!" contains exactly 12 characters, our format specifier for this string when printing it to STDOUT is A12. Hence, the full format specifier for the entire line of output should be (A12):

program HelloWorld
  implicit none
  print "(A12)", "Hello World!"
end program HelloWorld

This should print the output text Hello World! to the console without any leading or trailing whitespace as the length of the string (which is 12) fits the format specifier perfectly (A12). In the case where the value of n specified in the format specifier exceeds the length of the string, the output is padded with leading/trailing whitespace as required to make up to the given length n. Conversely, if the n in the format specifier is smaller than the size of the output then the output is truncated one way or another. This also applies to integers (and other data types).

module Solution
  ! See "Fixture" for actual Kumite content; we will explore modules in future Kumite ;)
end module Solution
Fundamentals

[GNU Fortran] Free-format Hello World Program

Background

https://en.wikipedia.org/wiki/Fortran

Initially conceived in late 1953 and realized in 1957, Fortran (formerly known as FORTRAN, short for "Formula Transformation") is considered to be the oldest high-level programming language in existence. In its early days, FORTRAN was limited to scientific computing (such as calculating trajectories of missiles) and wasn't even Turing-complete due to lack of support for dynamic memory allocation which is a requirement for initializing arrays of varying size during runtime. Nevertheless, FORTRAN gained widespread acceptance in both the science and engineering communities and became the main programming language used in academia for decades. Most notably, the formulation of the first FORTRAN compiler paved the way for modern compiler theory and influenced one of the most successful and widespread programming languages of all time, C.

Modern Fortran standards and implementations (e.g. F90, F95, F2003, F2008, GNU Fortran) are believed to be Turing-complete. In particular, I have successfully demonstrated that GNU Fortran (an extension of the F95 standard) is indeed Turing-complete by implementing a full-fledged BF interpreter (which itself has been proven to be Turing-complete).

This Kumite

In this Kumite I will show you how to print out the text Hello World! (perhaps with a few leading/trailing whitespace) in GNU Fortran. In Fortran, a program is defined by using the program keyword, then giving the program a name (such as HelloWorld). At the end of the program, one should type end program followed by the program name (which is HelloWorld in this case). The contents of the program are placed between these two statements:

program HelloWorld
  ! Program code here.  Fortran comments start with an exclamation mark
end program HelloWorld

Note that Fortran is case-insensitve, i.e. HelloWorld is the same as helloWorld or helloworld. In fact, we can start with pROGRAM HelloWorld and end with END Program hELLOwORLD and the code will compile/execute just fine.

After we define our program, the first statement inside that program should (almost) always be implicit none. This tells the compiler that any and all variables declared by the programmer should be done so explicitly with a specified type instead of attempting to type-infer when no such type is provided. It is not an absolute necessity to add this statement but is added to 99% of programs as a best practice.

program HelloWorld
  implicit none
end program HelloWorld

Then, we use the print command to print out our text Hello World!. The print statement accepts a format specifier as its first "argument" (double-quoted here because print is not a Fortran procedure) which we'll learn about later but we'll set it to * in this Kumite which means "use the default settings". Any subsequent "arguments" passed to the print command are comma-separated. In our case, our only other "argument" is the string "Hello World!" so our program would appear as follows:

program HelloWorld
  implicit none
  print *, "Hello World!" ! Print the text "Hello World!" to the screen
  ! with the default formatting settings
end program HelloWorld

Note that:

  1. When the default settings * are used for the format specifier in the print command, Fortran is likely to pad the displayed output with one or more leading and/or trailing whitespace. We will learn how to get rid of them in the next Kumite.
  2. Fortran does not make a distinction between characters and strings - in fact, a string is declared as character type and an actual character is just a string with length 1. Due to this, both characters and strings can be wrapped in single quotes '' or double quotes "", e.g. 'Hello World!' is equally valid as "Hello World!" and "H" is considered equal to 'H'.
module Solution
  ! Please refer to the "Test Cases" for the actual Kumite code example - we'll learn
  ! about modules in future Kumite ;)
end module Solution
Testing
Code
Diff
  • def replicate(times, num):
        if times <= 0: return []
        return [num] + replicate(times-1, num)
    
    replicate(8,5)
  • 11 def replicate(times, num):
    22 if times <= 0: return []
    33 return [num] + replicate(times-1, num)
    4+
    5+replicate(8,5)
Testing
Frameworks

Basic idea for the new cw-2.py's timeout function to have an extra argument that prevents running the function right away.

pass
Code
Diff
  • import java.util.stream.IntStream;
    
    public class Area {
    
      public static long[] workOutArea(final long[] values){
        return values.length % 2 != 0? null: IntStream.range(0, values.length).filter(x -> x % 2 == 0).mapToLong(x -> values[x] * values[x+1]).toArray();
      }
    
    }
  • 1+import java.util.stream.IntStream;
    2+
    11 public class Area {
    22
    33 public static long[] workOutArea(final long[] values){
    4- if (values.length % 2 != 0) {
    5- return null; // This is ugly!
    6- } else {
    7- final long[] areas = new long[values.length / 2];
    8- for (int i = 0; i < values.length; i += 2) {
    9- areas[i / 2] = values[i] * values[i + 1];
    10- }
    11- return areas;
    12- }
    6+ return values.length % 2 != 0? null: IntStream.range(0, values.length).filter(x -> x % 2 == 0).mapToLong(x -> values[x] * values[x+1]).toArray();
    1313 }
    1414
    1515 }
Strings
Code
Diff
  • const lastChar=s=>[...s].pop()
    
  • 1-const lastChar=(s)=>s.slice(-1)
    1+const lastChar=s=>[...s].pop()

Show optimization of code. Instead 4 passs throught array (max,min,count double time), use only one pass durring sorting.

Code
Diff
  • # Find stray number
    def find_stray(n)
      n.count(n.min) > n.count(n.max) ? n.max : n.min
    end
    
    # Find stray optimization
    def find_stray_o(n)
      n.sort!
      n[0] == n[1] ? n[-1] : n[0]
    end
    
    require "benchmark"
    
    array = (Array.new(1000_000,7) + [1]).shuffle
    
    Benchmark.bm(10) do |x|
      x.report("Find stray") { 10.times{ find_stray(array.clone.shuffle) }}
      x.report("Optimized") { 10.times{find_stray_o(array.clone.shuffle) }}
    end
  • 11 # Find stray number
    22 def find_stray(n)
    33 n.count(n.min) > n.count(n.max) ? n.max : n.min
    44 end
    5+
    6+# Find stray optimization
    7+def find_stray_o(n)
    8+ n.sort!
    9+ n[0] == n[1] ? n[-1] : n[0]
    10+end
    11+
    12+require "benchmark"
    13+
    14+array = (Array.new(1000_000,7) + [1]).shuffle
    15+
    16+Benchmark.bm(10) do |x|
    17+ x.report("Find stray") { 10.times{ find_stray(array.clone.shuffle) }}
    18+ x.report("Optimized") { 10.times{find_stray_o(array.clone.shuffle) }}
    19+end
Code
Diff
  • ++++++[>++++++<-]>[->+>++>+++>+++<<<<]>>.>-------.>..+++.<<<----.>-.>----.+.>+++.<+++++++.----.>------.
  • 1--[------->+<]>-.-[->+++++<]>++.+++++++..+++.[--->+<]>-----.+++[->++<]>+.-[------>+<]>.+.[--->+<]>----.---------.----.+++++++.
    1+++++++[>++++++<-]>[->+>++>+++>+++<<<<]>>.>-------.>..+++.<<<----.>-.>----.+.>+++.<+++++++.----.>------.

Missing what is it about. Just simplyfing things :)

Code
Diff
  • COLORS = set("RGB")
    def blend(c1, c2):
        colors = {c1, c2}
        return c1 if len(colors) == 1 else (COLORS - colors).pop()
    
    
    def preprocess(row):
        check = ""
        for r in row:
            if r != check:
                yield r
                check = r
    
    
    def triangle(row):
        row = list(preprocess(row))
        while len(row) > 1:
            for i,r in enumerate(row[:-1]):
                row[i] = blend(r, row[i+1])
            row.pop()
        return row[0]
    
  • 1-import re
    2-
    1+COLORS = set("RGB")
    33 def blend(c1, c2):
    4- if c1 == c2: return c1
    5- colors = c1 + c2
    6- if colors == "RB" or colors == "BR": return "G"
    7- if colors == "RG" or colors == "GR": return "B"
    8- if colors == "GB" or colors == "BG": return "R"
    3+ colors = {c1, c2}
    4+ return c1 if len(colors) == 1 else (COLORS - colors).pop()
    5+
    99
    1010 def preprocess(row):
    11- orig = row
    12- row,_ = re.subn('RR+', 'R', row)
    13- row,_ = re.subn('BB+', 'B', row)
    14- row,_ = re.subn('GG+', 'G', row)
    15- print(orig, row)
    16- return row
    8+ check = ""
    9+ for r in row:
    10+ if r != check:
    11+ yield r
    12+ check = r
    13+
    1717
    1818 def triangle(row):
    19- if len(row) == 1: return row
    20- row = preprocess(row)
    21- row = list(row)
    22- for j in range(len(row)-1,0,-1):
    23- for i in range(j):
    24- row[i] = blend(row[i], row[i+1])
    16+ row = list(preprocess(row))
    17+ while len(row) > 1:
    18+ for i,r in enumerate(row[:-1]):
    19+ row[i] = blend(r, row[i+1])
    20+ row.pop()
    2525 return row[0]

Looks familiar?

Expected: equal to [unsupported type]
Actual: [unsupported type]

No more!

Code
Diff
  • template <class... Args>
    bool alwaysTrue(Args&&...) {
      return true;
    }
    
    template <class T>
    T id(T&& x)  {
      return x;
    }
    
  • 11 template <class... Args>
    22 bool alwaysTrue(Args&&...) {
    33 return true;
    44 }
    5+
    6+template <class T>
    7+T id(T&& x) {
    8+ return x;
    9+}
Regular Expressions
Declarative Programming
Advanced Language Features
Fundamentals
Strings
Code
Diff
  • wordCount=s=>s.trim().match(/[^\W_]+/mg).length;
  • 1-wordCount=s=>s.trim().match(/[A-Za-z0-9]+/mg).length;
    1+wordCount=s=>s.trim().match(/[^\W_]+/mg).length;
Testing
Frameworks

More testing on expect_error. By the nature of try..except statement, it is possible to specify multiple exception types to expect.

Algorithms

here is mine updated and better

Code
Diff
  • flatten=a=>a.map?[].concat(...a.map(flatten)):a
  • 1-const flatten = a =>
    2- Array.isArray(a) ? a.reduce((acc,item) => acc.concat(flatten(item)), []) : a;
    1+flatten=a=>a.map?[].concat(...a.map(flatten)):a
Fundamentals
Strings

Maybe basic math operations will work faster than slice, so we can find first digit of minutes like this

Code
Diff
  • const minutes = (n) => `${~~(n / 60)}:${~~(n % 60 / 10)}${(n % 60 % 10)}`;
  • 1-const minutes = (n) => `${Math.trunc(n / 60)}:${("0" + (n % 60)).slice(-2)}`;
    1+const minutes = (n) => `${~~(n / 60)}:${~~(n % 60 / 10)}${(n % 60 % 10)}`;

C has a weak type system that can be easily violated. The sole purpose of the type system is to inform the program how to view/interpret a certain memory block/space. It doesn't take much effort to convince C to view a particular memory space in a completely different manner than previously intended which could lead to interesting behavior ;)

Addendum: Following a bit of additional experimentation, it would appear that it is also possible to reassign value(s) under a pointer that views the given memory space in a completely unintended manner. However, I suspect this may be bordering on undefined behavior which means it may not work properly on all operating systems :p

// See the test cases for the real fun ;)
main = print (maxBound :: Int)
Testing
Frameworks

This kumite illustrates some of the new features of the Python test framework (a.k.a. cw-2.py) through a simple kata format.

Example Task

Compute the sum of two integers.

Constraints

-10**9 <= a, b <= 10**9

Example Solutions

  1. add: Correct solution
  2. add1: Incorrect solution
  3. add2: Solution that timeouts
  4. add3: Solution that cheats
  5. add4: Solution that throws error (see how the error is formatted; files and lines are shown properly now)

You can uncomment each line at the bottom of Code section to see how the tests combat the invalid solutions in different ways.

Extra Things in the code section

  1. You can use and print Unicode characters without error!

Example Test Fixture

  1. @Test.describe(name)
  2. @Test.it(name)
  3. @Test.timeout(sec)
  4. Test.assert_equals and Test.assert_not_equals are non-blocking by default
  5. Test.assert_not_equals can now prevent cheating with magic methods

For more complete list of features and guide on how to write a test fixture, consult this page on GitHub Wiki.

Code
Diff
  • # Correct solution
    def add(a, b): return a + b
    
    # Incorrect solution
    def add1(a, b): return a | b
    
    # Solution that timeouts
    def add2(a, b):
        while a: a, b = a-1, b+1
        return b
    
    # Solution that cheats
    def add3(a, b):
        class X(object):
            def __eq__(self, other): return True
            def __ne__(self, other): return True
            def __gt__(self, other): return True
            def __lt__(self, other): return True
            def __ge__(self, other): return True
            def __le__(self, other): return True
        return X()
    
    # Solution that throws error
    def add4(a, b):
        if a > 10: raise NotImplementedError()
        return a + b
        
    #add = add1
    #add = add2
    #add = add3
    #add = add4
    
    # Other things to demonstrate
    print('가나다')
  • 1616 def __ne__(self, other): return True
    1717 def __gt__(self, other): return True
    1818 def __lt__(self, other): return True
    1919 def __ge__(self, other): return True
    2020 def __le__(self, other): return True
    2121 return X()
    22+
    23+# Solution that throws error
    24+def add4(a, b):
    25+ if a > 10: raise NotImplementedError()
    26+ return a + b
    2222
    2323 #add = add1
    2424 #add = add2
    2525 #add = add3
    31+#add = add4
    32+
    33+# Other things to demonstrate
    34+print('가나다')
Code
Diff
  • import java.util.stream.IntStream;
    
    public class Primes {
      public static boolean isAPrime(int num) {
        return IntStream.range(2, (num/2 +1))
          .noneMatch(divider -> (num % divider) == 0); 
      }
    }
  • 11 import java.util.stream.IntStream;
    22
    33 public class Primes {
    4- public static boolean isAPrime(int number) {
    5- return IntStream.range(2, (number/2 +1))
    6- .noneMatch(divider -> (number % divider) == 0);
    4+ public static boolean isAPrime(int num) {
    5+ return IntStream.range(2, (num/2 +1))
    6+ .noneMatch(divider -> (num % divider) == 0);
    77 }
    88 }

Does the same, just looks a bit neater.

Code
Diff
  • import java.util.stream.IntStream;
    public class CountTheDigit {
    
      public static int count(int num, int digit) {
        int result = 0;
        
        do {
          if (num % 10 == digit)
            ++result;
          num /= 10;
        } while (num != 0);
        
        return result;
      }
      
    	public static int nbDig(int n, int d) {
      	return IntStream.range(0,n)
          .map(i -> count(i * i, d))
          .sum();
      }
    }
  • 1+import java.util.stream.IntStream;
    11 public class CountTheDigit {
    22
    33 public static int count(int num, int digit) {
    44 int result = 0;
    55
    66 do {
    77 if (num % 10 == digit)
    88 ++result;
    99 num /= 10;
    1010 } while (num != 0);
    1111
    1212 return result;
    1313 }
    1414
    1515 public static int nbDig(int n, int d) {
    16- int result = 0;
    17-
    18- for(int i = 0; i < n; ++i)
    19- result += count(i * i, d);
    20-
    21- return result;
    17+ return IntStream.range(0,n)
    18+ .map(i -> count(i * i, d))
    19+ .sum();
    2222 }
    2323 }
Code
Diff
  • import static java.util.stream.IntStream.of;
    
    public class Average {
       public static int averageFinder(int[] arr) {
         return (int)of(arr).average().orElse(0);
       }
    }
  • 1-import java.util.stream.*;
    1+import static java.util.stream.IntStream.of;
    22
    33 public class Average {
    44 public static int averageFinder(int[] arr) {
    5- return (int)IntStream.of(arr).average().orElse(0);
    5+ return (int)of(arr).average().orElse(0);
    66 }
    77 }

Even faster, since it doesn't rely on an iterator. Especially big numbers yield noticeable differences in execution time.

Code
Diff
  • def euler(num):
        sum_range = lambda x: x*(x+1)//2
        return 3*sum_range((num-1)//3) + 5*sum_range((num-1)//5) - 15*sum_range((num-1)//15)
  • 11 def euler(num):
    2- return sum(range(3,num,3)) + sum(range(5,num,5)) - sum(range(15,num,15))
    2+ sum_range = lambda x: x*(x+1)//2
    3+ return 3*sum_range((num-1)//3) + 5*sum_range((num-1)//5) - 15*sum_range((num-1)//15)
Search
Algorithms

shorther version

Code
Diff
  • import java.util.*;
    
    class Node {
      int value;
      Node left;
      Node right;
      
      public Node(int value) {
        this.value = value;
      }
    }
    
    
    class BST {
      public static boolean search(Node root, int key) {
                
        while(root != null) {
          if(root.value == key) {
            return true;
          }
          else    
          root=(root.value > key)?root.left:root.right;
          
        }
        
        return false;
      }
    }
  • 1010 }
    1111 }
    1212
    1313
    1414 class BST {
    1515 public static boolean search(Node root, int key) {
    16- if(root == null) {
    17- return false;
    18- }
    19-
    16+
    2020 while(root != null) {
    2121 if(root.value == key) {
    2222 return true;
    2323 }
    21+ else
    22+ root=(root.value > key)?root.left:root.right;
    2424
    25- if(root.value > key) {
    26- root = root.left;
    27- } else if(root.value < key) {
    28- root = root.right;
    29- }
    3030 }
    3131
    3232 return false;
    3333 }
    3434 }

Write a function that:

  • returns "Fizz" for multiples of 3
  • returns "Buzz" for multiples of 5
  • returns "FizzBuzz" for multiples of both 3 and 5

Any other number should return the number as string.

export function fizzBuzz(input: number): string {
    const output: string = `${input % 3 === 0 ? "Fizz" : ""}${input % 5 === 0 ? "Buzz" : ""}`;
    return output.length > 0 ? output : input.toString(10);
}
Code
Diff
  • inline float multiply(const float &number1, const float &number2 )
    {
      if (number1 == 0 || number2 == 0) return 0;
      if (number2 > 0) return number1 + multiply(number1, number2 - 1);
      if (number2 < 0) return -multiply(number1, -number2);
      return -1;
    }
    
    void shift_dec_point(float &number, int &decimal_positions)
    {
      while(number - static_cast<int>(number) > 0.1)
      {
        number = multiply(number, 10);
        decimal_positions++;
      }
    }
    
    float squared(const float &number)
    {
      float temp = number;
      if(temp < 0) temp = -temp;
    
      int decimal_positions = 0;
      shift_dec_point(temp, decimal_positions);
      float factor = temp;
      if(decimal_positions > 0) {
        temp = multiply(temp, temp);
          switch (decimal_positions){
            case 1: factor = 0.01; break;
            case 2: factor = 0.001; break;
            case 3: factor = 0.0001; break;
            case 4: factor = 0.00001;
          }
      }
      return multiply(factor,temp);
    }
  • 1-inline float multiply(float number1, float number2 )
    1+inline float multiply(const float &number1, const float &number2 )
    22 {
    3- float answer = 0;
    4- while( number2 > 0 )
    5- {
    6- answer += number1;
    7- number2--;
    8- }
    9- return answer;
    3+ if (number1 == 0 || number2 == 0) return 0;
    4+ if (number2 > 0) return number1 + multiply(number1, number2 - 1);
    5+ if (number2 < 0) return -multiply(number1, -number2);
    6+ return -1;
    1010 }
    1111
    12-
    13-float squared(float number)
    9+void shift_dec_point(float &number, int &decimal_positions)
    1414 {
    15- if( number < 0 ) number = -number;
    16-
    17- int decimal_positions = 0;
    18- while( number - int(number) > 0.1 )
    11+ while(number - static_cast<int>(number) > 0.1)
    1919 {
    2020 number = multiply(number, 10);
    2121 decimal_positions++;
    2222 }
    23-
    24- float factor = number;
    16+}
    2525
    26- if( decimal_positions > 0 ) {
    27- number = multiply(number,number);
    28- switch (decimal_positions){
    29- case 1: factor = 0.01; break;
    30- case 2: factor = 0.001; break;
    18+float squared(const float &number)
    19+{
    20+ float temp = number;
    21+ if(temp < 0) temp = -temp;
    22+
    23+ int decimal_positions = 0;
    24+ shift_dec_point(temp, decimal_positions);
    25+ float factor = temp;
    26+ if(decimal_positions > 0) {
    27+ temp = multiply(temp, temp);
    28+ switch (decimal_positions){
    29+ case 1: factor = 0.01; break;
    30+ case 2: factor = 0.001; break;

Since I have to work on an Android project which doesn't use Gradle as a build tool, so I always have to find the aar library and extract the classes.jar file from it. Doing it manually was very boring. So I decided to write my own Python (because it's interpreted) script to do this task. The code I have written works very well, but it can be improved by making it cross-platform, efficient, etc.

So let's start to improve it.

Gist: https://gist.github.com/pavi2410/b1ba0ae03e4b459846c72453204394a6

Note that you have to run this script on your PC, unfortunately.

import zipfile, os

cd = os.getcwd()
for file in os.listdir(cd):
	if file.endswith(".aar"):
		print("Got aar: " + file)
		with zipfile.ZipFile(cd + "\\" + file) as aar:
			aar.extract("classes.jar", cd)
			print("Extracted aar")
		os.rename("classes.jar", os.path.splitext(file)[0] + ".jar")

We shall see.

#import <Foundation/Foundation.h>

// Nope - the bug has not been fixed yet :(
void test_function() {
  [PreloadedTest printTestMessage];
}

In this kata you should find BB-tags (bulletin board tags) in given string.

BB-tags look like:

[B]Some content[/B],

where [B] - opening tag and [/B] - closing tag.

Name of tags also can be lowercase:

[url]Some content[/url]

And BB-tags can be nested into each other, for example:

[url][b][size=5][color=blue]Some content[/color][/size][/b][/url]

If there is nested BB-tags, you should return only the outer tag with all it's content (with another tags into it).

function test(str) {
  return (str.match(/\[([a-zA-Z]+)](.*)\[\/\1]/g)).join('');
}

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

changed id to string and check if result of the custom unique-method is correct

the problem now is, that the groovy-unique-method is not that slow as before....

Algorithms
Code
Diff
  • const getDividors = n => {
      
      let result = [];
    
      for (let i = 1; i <= Math.floor(Math.sqrt(n)); i += 1)
        if (n % i === 0) { result.push(i); if (n / i !== i) result.push(n / i) }
        
      return result; // output array won't be sorted
      
    }
  • 1-const getDividors = (n, result = []) => {
    1+const getDividors = n => {
    2+
    3+ let result = [];
    22
    3- for (let i = 1; i <= Math.floor(Math.sqrt(n)); i++)
    5+ for (let i = 1; i <= Math.floor(Math.sqrt(n)); i += 1)
    44 if (n % i === 0) { result.push(i); if (n / i !== i) result.push(n / i) }
    55
    66 return result; // output array won't be sorted
    77
    88 }
Graphs
Data Structures

Given any matrix, NxN or MxN we should be able to extract the inner matrix.

For example:
MxN [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] -> [[6, 7]]
NxN [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] -> [[6, 7], [10, 11]]

innerMatrix = array => array
  .slice(1, array.length - 1)
  .map(row => row.slice(1, array[0].length - 1));

Output numbers from 1 to x. If the number is divisible by 3, replace it with “Fizz”. If it is divisible by 5, replace it with “Buzz”. If it is divisible by 3 and 5 replace it with “FizzBuzz”.

(ns fizzbuzz.core)

(defn divisible-by? [divisor number]
  (zero? (mod number divisor)))
  
(defn fizzbuzz [x]
  (map #(cond 
          (divisible-by? 15 %) "FizzBuzz"
          (divisible-by? 5 %) "Buzz"
          (divisible-by? 3 %) "Fizz"
          :else %)
        (range 1 (inc x))))

Faster than previsous versions by avoiding sorting and insertion of factor lists. Style fix (not is not a function)

Code
Diff
  • def divisors(n):
        fact_lo = []
        fact_hi = []
        for i in range(1, int(n**0.5) + 1):
            if not n % i:
                v = n // i
                if v != i:
                    fact_hi.append(v)
                fact_lo.append(i)
        fact_lo.extend(reversed(fact_hi))
        return fact_lo
  • 11 def divisors(n):
    2- fact = []
    2+ fact_lo = []
    3+ fact_hi = []
    33 for i in range(1, int(n**0.5) + 1):
    4- if not(n % i):
    5+ if not n % i:
    55 v = n // i
    66 if v != i:
    7- fact.insert(len(fact)//2,v)
    8- fact.insert(len(fact)//2,i)
    9- return fact
    8+ fact_hi.append(v)
    9+ fact_lo.append(i)
    10+ fact_lo.extend(reversed(fact_hi))
    11+ return fact_lo
Testing

Outline

This is a proposal for CodeWars test framework for Python to improve it in many ways (and be more consistent with other languages' frameworks).

Unlike my previous Kumite, this one is designed to completely replace cw-2.py in the runner repo.

Changes / Improvements

Individual Testing / Logging Functions

  • Make testing functions non-blocking
  • Change the expression inside assert_not_equals so that it can prevent operator injection hacks
  • Provide a way to log and test Unicode strings without Unicode-related error
  • Provide a utility for timeout
  • Provide pass, fail and assert_approx_equals

Describe / It

  • Build the decorator version of describe and it, so the text fixture may look like this (and the decorator itself runs the code, so it doesn't need a separate runner function):
@describe('describe-text')
def describe1():
    @it('it-text', before=f1, after=f2)
    def it1():
        # some test function
    @it('it-text')
    def it2():
        # some test function
  • Properly close describe and it blocks in the test output
  • Print the running times of describe and it blocks
  • Provide before and after for describe and it

Changelog

v1.1

  • Replace the timeout utility with decorator version.

v1.2

  • Make the whole code (including fixture examples) compatible with Python 2 using six.
Code
Diff
  • from __future__ import print_function
    import re, six
    range = six.moves.range
    
    
    class AssertException(Exception):
        pass
    
    
    '''Fix the dreaded Unicode Error Trap'''
    def uni_print(*args, **kwargs):
        from sys import stdout
        sep = kwargs.get('sep', ' ')
        end = kwargs.get('end', '\n')
        file = kwargs.get('file', stdout)
        
        def _replace(c):
            if ord(c) >= 128: return u'&#{};'.format(ord(c))
            return c
        def _escape(s):
            escaped = ''.join(_replace(c) for c in six.text_type(s))
            escaped = re.sub(r'\\u([\da-f]{4})', lambda m: '&#{};'.format(int(m.group(1), 16)), escaped)
            escaped = re.sub(r'\\U([\da-f]{8})', lambda m: '&#{};'.format(int(m.group(1), 16)), escaped)
            return escaped
            
        six.print_(*map(_escape, args), sep=_escape(sep), end=_escape(end), file=file)
    
    
    def format_message(message):
        def _replace(c):
            if ord(c) >= 65536: return r'\U' + hex(ord(c))[2:].zfill(8)
            if ord(c) >= 128: return r'\u' + hex(ord(c))[2:].zfill(4)
            return c
        def _escape(s): return ''.join(_replace(c) for c in s)
        return _escape(message.replace("\n", "<:LF:>"))
    
    
    def display(type, message, label="", mode=""):
        print("\n<{0}:{1}:{2}>{3}".format(type.upper(), mode.upper(), label, format_message(message)))
    
    
    def expect(passed=None, message=None, allow_raise=False):
        if passed:
            display('PASSED', 'Test Passed')
        else:
            message = message or "Value is not what was expected"
            display('FAILED', message)
            if allow_raise:
                raise AssertException(message)
    
    
    def assert_equals(actual, expected, message=None, allow_raise=False):
        equals_msg = "{0} should equal {1}".format(repr(actual), repr(expected))
        if message is None:
            message = equals_msg
        else:
            message += ": " + equals_msg
    
        expect(actual == expected, message, allow_raise)
    
    
    def assert_not_equals(actual, expected, message=None, allow_raise=False):
        equals_msg = "{0} should not equal {1}".format(repr(actual), repr(expected))
        if message is None:
            message = equals_msg
        else:
            message += ": " + equals_msg
    
        expect(not (actual == expected), message, allow_raise)
    
    
    def expect_error(message, function):
        passed = False
        try:
            function()
        except:
            passed = True
        expect(passed, message)
    
    
    def pass_(): expect(True)
    def fail(message): expect(False, message)
    
    
    def assert_approx_equals(actual, expected, margin=1e-9, message=None, allow_raise=False):
        equals_msg = "{0} should be close to {1} with absolute or relative margin of {2}".format(
            repr(actual), repr(expected), repr(margin))
        if message is None: message = equals_msg
        else: message += ": " + equals_msg
        div = max(abs(actual), abs(expected), 1)
        expect(abs((actual - expected) / div) < margin, message, allow_raise)
    
    
    '''
    Usage:
    @describe('describe text')
    def describe1():
        @it('it text')
        def it1():
            # some test cases...
    '''
    def _timed_block_factory(opening_text):
        from timeit import default_timer as timer
        from traceback import format_exception
        from sys import exc_info
        
        def _timed_block_decorator(s, before=None, after=None):
            display(opening_text, s)
            def wrapper(func):
                if callable(before): before()
                time = timer()
                try: func()
                except:
                    fail('Unexpected exception raised')
                    tb_str = ''.join(format_exception(*exc_info()))
                    display('ERROR', tb_str)
                display('COMPLETEDIN', '{:.2f}'.format((timer() - time) * 1000))
                if callable(after): after()
            return wrapper
        return _timed_block_decorator
    
    describe = _timed_block_factory('DESCRIBE')
    it = _timed_block_factory('IT')
    
    
    '''
    Timeout utility
    Usage:
    @timeout(sec)
    def some_tests():
        any code block...
    Note: Timeout value can be a float.
    '''
    def timeout(sec):
        def wrapper(func):
            from multiprocessing import Process
            process = Process(target=func)
            process.start()
            process.join(sec)
            if process.is_alive():
                fail('Exceeded time limit of {:.3f} seconds'.format(sec))
                process.terminate()
                process.join()
        return wrapper
    
    
    '''Old-style Fixture'''
    describe('Old-style Describe')
    it('Old-style It')
    assert_equals(0, 0)
    assert_equals(0, 1)
    print('<COMPLETEDIN::>')
    it('Old-style It 2')
    assert_equals('a', 'a')
    assert_equals('a', 'b')
    print('<COMPLETEDIN::>')
    print('<COMPLETEDIN::>')
    
    
    '''Sample Fixture #1'''
    @describe('Sample Fixture #1')
    def sample_describe_1():
        @it('Sample Testcase #1-1')
        def sample_it_1():
            assert_equals(0, 0)
            assert_equals(0, 1)
            assert_not_equals(0, 2)
            pass_()
            fail('This should fail')
        @it('Sample Testcase #1-2')
        def sample_it_2():
            expect_error('ZeroDivisionError', lambda: 0 / 0)
            assert_equals(0, 0 / 0)
            assert_equals(1, 1, 'This is not run due to exception')
        @it('Sample Testcase #1-3')
        def sample_it_3():
            assert_equals('abc', 'abc')
            # source code doesn't support utf-8 chars, but you can at least log and test unicode
            assert_equals(u'\uac00 \ub098 \ub2e4', u'\uac00 \ub098 \ub2e4')
            uni_print(1, 'a', u'\uac00 \ub098 \ub2e4', [2, 'b', u'\uac00'])
            assert_equals(u'\uac00 \ub098 \ub2e4', 'a b c')
    
    
    '''Sample Fixture #2: Featuring Before and After'''
    @describe('Sample Fixture #2')
    def sample_describe_2():
        a = {0}
        def before():
            a.add(len(a))
        @it('Sample Testcase #2-1', before=before, after=before)
        def sample_it_1():
            assert_equals(a, {0, 1})
        @it('Sample Testcase #2-2')
        def sample_it_2():
            assert_equals(a, {0, 1, 2})
    
    
    '''Sample Fixture #3: Featuring Timeout'''
    @describe('Sample Fixture #3')
    def sample_describe_3():
        @it('Sample Testcase #3-1')
        def sample_it_1():
            @timeout(0.01)
            def count():
                for _ in range(100): pass
                pass_()
        @it('Sample Testcase #3-2')
        def sample_it_2():
            @timeout(0.01)
            def count():
                for _ in range(10**10): pass
                pass_()
    
    
    '''Sample Fixture #4: Featuring assert_approx_equals'''
    @describe('Sample Fixture #4')
    def sample_describe_4():
        @it('Sample Testcase #4-1')
        def sample_it_1():
            assert_approx_equals(1, 1 + 1e-10, 1e-9)
            assert_approx_equals(1, 1 + 1e-7, 1e-9)
            assert_approx_equals(-1, -1 - 1e-10, 1e-9)
            assert_approx_equals(-1, -1 - 1e-7, 1e-9)
        @it('Sample Testcase #4-2')
        def sample_it_2():
            assert_approx_equals(0, 1e-10, 1e-9)
            assert_approx_equals(0, 1e-7, 1e-9)
            assert_approx_equals(0, -1e-10, 1e-9)
            assert_approx_equals(0, -1e-7, 1e-9)
    
  • 1-#from __future__ import print_function
    1+from __future__ import print_function
    2+import re, six
    3+range = six.moves.range
    4+
    22
    33 class AssertException(Exception):
    44 pass
    55
    66
    77 '''Fix the dreaded Unicode Error Trap'''
    8-_print = print
    9-def print(*args, sep=' ', end='\n'):
    10- from io import StringIO
    11- def _escape(s): return s.encode('ascii', 'xmlcharrefreplace').decode('ascii')
    12- sio = StringIO()
    13- _print(*args, sep=sep, end=end, file=sio)
    14- _print(_escape(sio.getvalue()))
    15- sio.close()
    11+def uni_print(*args, **kwargs):
    12+ from sys import stdout
    13+ sep = kwargs.get('sep', ' ')
    14+ end = kwargs.get('end', '\n')
    15+ file = kwargs.get('file', stdout)
    16+
    17+ def _replace(c):
    18+ if ord(c) >= 128: return u'&#{};'.format(ord(c))
    19+ return c
    20+ def _escape(s):
    21+ escaped = ''.join(_replace(c) for c in six.text_type(s))
    22+ escaped = re.sub(r'\\u([\da-f]{4})', lambda m: '&#{};'.format(int(m.group(1), 16)), escaped)
    23+ escaped = re.sub(r'\\U([\da-f]{8})', lambda m: '&#{};'.format(int(m.group(1), 16)), escaped)
    24+ return escaped
    25+
    26+ six.print_(*map(_escape, args), sep=_escape(sep), end=_escape(end), file=file)
    1616
    1717
    1818 def format_message(message):
    19- return message.replace("\n", "<:LF:>")
    30+ def _replace(c):
    31+ if ord(c) >= 65536: return r'\U' + hex(ord(c))[2:].zfill(8)
    32+ if ord(c) >= 128: return r'\u' + hex(ord(c))[2:].zfill(4)
    33+ return c
    2020
    2121
    2222 def expect(passed=None, message=None, allow_raise=False):
    23- if passed: print("\n<PASSED::>Test Passed")
    43+ if passed:
    44+ display('PASSED', 'Test Passed')
    2424 else:
    2525 message = message or "Value is not what was expected"
    26- print("\n<FAILED::>{0}".format(message))
    27- if allow_raise: raise AssertException(message)
    47+ display('FAILED', message)
    48+ if allow_raise:
    49+ raise AssertException(message)
    2828
    2929
    30-'''Fix the blocking asserts to non-blocking'''
    3131 def assert_equals(actual, expected, message=None, allow_raise=False):
    3232 equals_msg = "{0} should equal {1}".format(repr(actual), repr(expected))
    33- if message is None: message = equals_msg
    42-'''
    4343 def assert_not_equals(actual, expected, message=None, allow_raise=False):
    4444 equals_msg = "{0} should not equal {1}".format(repr(actual), repr(expected))
    45- if message is None: message = equals_msg
    46- else: message += ": " + equals_msg
    4747 expect(not (actual == expected), message, allow_raise)
    4848
    4949
    5050 def expect_error(message, function):
    5151 passed = False
    52- try: function()
    53- except: passed = True
    74+ try:
    75+ function()
    76+ except:
    77+ passed = True
    5959 def fail(message): expect(False, message)
    6969
    7070
    71-def display(type, message, label="", mode=""):
    72- print("\n<{0}:{1}:{2}>{3}".format(type.upper(), mode.upper(), label, format_message(message)))
    73-
    74-
    7575 '''
    76-Modern-Style Describe & It
    7777 Usage:
    7878 @describe('describe text')
    7979 def describe1():
    8585 from timeit import default_timer as timer
    8686 from traceback import format_exception
    8787 from sys import exc_info
    8888
    8989 def _timed_block_decorator(s, before=None, after=None):
    90- print('<{}::>{}'.format(opening_text, s))
    108+ display(opening_text, s)
    9191 def wrapper(func):
    9292 if callable(before): before()
    9393 time = timer()
    9494 try: func()
    9595 except:
    9696 fail('Unexpected exception raised')
    97- tb_str = ''.join(format_exception(*exc_info())).replace('\n', '<:LF:>')
    98- print('<ERROR::>' + tb_str)
    99- print('<COMPLETEDIN::>{}'.format(round((timer() - time) * 1000, 2)))
    115+ tb_str = ''.join(format_exception(*exc_info()))
    116+ display('ERROR', tb_str)
    117+ display('COMPLETEDIN', '{:.2f}'.format((timer() - time) * 1000))
    100100 if callable(after): after()
    101101 return wrapper
    102102 return _timed_block_decorator
    103103
    104104 describe = _timed_block_factory('DESCRIBE')
    105105 it = _timed_block_factory('IT')
    106106
    107107
    108108 '''
    109109 Timeout utility
    110110 Usage:
    111-with run_with_timeout(func, tuple_of_args, timeout_in_seconds) as run:
    112- Test.assert_equals(run.get(), expected_value)
    129+@timeout(sec)
    130+def some_tests():
    131+ any code block...
    113113 Note: Timeout value can be a float.
    114114 '''
    115-class run_with_timeout(object):
    116- def __init__(self, func, inputs, sec):
    117- from multiprocessing import Process, Queue
    118- def timeout_wrapper(func, inputs, q):
    124- def __enter__(self):
    125- self.p.start()
    126- return self
    127- def get(self):
    128- if self.result is None: self.result = self.q.get(timeout=self.sec)
    129- return self.result
    130- def __exit__(self, typ, val, traceback):
    131- self.q.close()
    132- self.p.terminate()
    133- self.p.join()
    134- if traceback: fail('Exceeded time limit of {:.3f} seconds'.format(self.sec))
    135- return True
    134+def timeout(sec):
    135+ def wrapper(func):
    136+ from multiprocessing import Process
    137+ process = Process(target=func)
    138+ process.start()
    139+ process.join(sec)
    140+ if process.is_alive():
    141+ fail('Exceeded time limit of {:.3f} seconds'.format(sec))
    142+ process.terminate()
    143+ process.join()
    144+ return wrapper
    136136
    137137
    138138 '''Old-style Fixture'''
    139139 describe('Old-style Describe')
    140140 it('Old-style It')
    141141 assert_equals(0, 0)
    142142 assert_equals(0, 1)
    143143 print('<COMPLETEDIN::>')
    144144 it('Old-style It 2')
    145145 assert_equals('a', 'a')
    146146 assert_equals('a', 'b')
    147147 print('<COMPLETEDIN::>')
    148148 print('<COMPLETEDIN::>')
    149149
    150150
    165165 assert_equals(1, 1, 'This is not run due to exception')
    166166 @it('Sample Testcase #1-3')
    167167 def sample_it_3():
    168168 assert_equals('abc', 'abc')
    169169 # source code doesn't support utf-8 chars, but you can at least log and test unicode
    170- assert_equals('\uac00 \ub098 \ub2e4', '\uac00 \ub098 \ub2e4')
    171- print('\uac00 \ub098 \ub2e4')
    172- assert_equals('\uac00 \ub098 \ub2e4', 'a b c')
    179+ assert_equals(u'\uac00 \ub098 \ub2e4', u'\uac00 \ub098 \ub2e4')
    180+ uni_print(1, 'a', u'\uac00 \ub098 \ub2e4', [2, 'b', u'\uac00'])
    181+ assert_equals(u'\uac00 \ub098 \ub2e4', 'a b c')
    173173
    174174
    175175 '''Sample Fixture #2: Featuring Before and After'''
    176176 @describe('Sample Fixture #2')
    177177 def sample_describe_2():
    178178 a = {0}
    179179 def before():
    180180 a.add(len(a))
    181181 @it('Sample Testcase #2-1', before=before, after=before)
    182182 def sample_it_1():
    183183 assert_equals(a, {0, 1})
    184184 @it('Sample Testcase #2-2')
    185185 def sample_it_2():
    186186 assert_equals(a, {0, 1, 2})
    187187
    188188
    189189 '''Sample Fixture #3: Featuring Timeout'''
    190190 @describe('Sample Fixture #3')
    191191 def sample_describe_3():
    192- def wait_count(n):
    193- for _ in range(n): pass
    194- return n
    195195 @it('Sample Testcase #3-1')
    196196 def sample_it_1():
    197- with run_with_timeout(wait_count, (100,), 0.01) as run:
    198- assert_equals(run.get(), 100)
    203+ @timeout(0.01)
    204+ def count():
    205+ for _ in range(100): pass
    206+ pass_()
    199199 @it('Sample Testcase #3-2')
    200200 def sample_it_2():
    201- with run_with_timeout(wait_count, (10 ** 10,), 0.01) as run:
    202- assert_equals(run.get(), 10 ** 10)
    209+ @timeout(0.01)
    210+ def count():
    211+ for _ in range(10**10): pass
    212+ pass_()
    203203
    204204
    205205 '''Sample Fixture #4: Featuring assert_approx_equals'''
    206206 @describe('Sample Fixture #4')
    207207 def sample_describe_4():
    208208 @it('Sample Testcase #4-1')
    209209 def sample_it_1():
    210210 assert_approx_equals(1, 1 + 1e-10, 1e-9)
    211211 assert_approx_equals(1, 1 + 1e-7, 1e-9)
    212212 assert_approx_equals(-1, -1 - 1e-10, 1e-9)
    213213 assert_approx_equals(-1, -1 - 1e-7, 1e-9)
    214214 @it('Sample Testcase #4-2')
    215215 def sample_it_2():
    216216 assert_approx_equals(0, 1e-10, 1e-9)
    217217 assert_approx_equals(0, 1e-7, 1e-9)
    218218 assert_approx_equals(0, -1e-10, 1e-9)
    219219 assert_approx_equals(0, -1e-7, 1e-9)
Testing

This shows a piece of test code in Python that is improved over the default cw-2 (and consistent with other languages' test frameworks) in the following aspects:

Initial release (v1.0)

  • Utilize the with-block to support proper indentation of describe and it blocks in the code
  • Properly close describe and it blocks in the test output
  • Print the running times of describe and it blocks
  • Make testing functions non-blocking

v1.1

  • Provide a way to log Unicode strings for users (does not work for test framework)

v1.2

  • Provide before and after for describe and it
  • Provide a utility for timeout
    • Version 1: Function version
    • Version 2: Context manager version (looks cleaner)

Run the tests and see how the test output looks like.

Algorithms

All equal is a property of a whole list. One of possile ways is to use folds that are more natual way to cacluate/check value/property on a foldable structures.

Also algorithm has O(n) complexity

Code
Diff
  • module AllEqual where
    
    import Data.Foldable(foldl')
    
    allEqual :: [Int] -> Bool
    allEqual []     = True
    allEqual (x:xs) = foldl' (\b a -> b && (a==x)) True xs
  • 11 module AllEqual where
    2-import Data.List
    33
    4-allEqual :: [Int] -> Bool
    5-allEqual xs = length (nub xs) <= 1
    3+import Data.Foldable(foldl')
    4+
    5+allEqual :: [Int] -> Bool
    6+allEqual [] = True
    7+allEqual (x:xs) = foldl' (\b a -> b && (a==x)) True xs
Code
Diff
  • bool Or  ( bool a, bool b ){ return a ? a : b; }
    bool And ( bool a, bool b ){ return a ? b : false; }
    bool Xor ( bool a, bool b ){ return And(a,b) ? false: Or(a,b); }
  • 1-bool Or ( bool a, bool b ){ return a | b; }
    2-bool Xor ( bool a, bool b ){ return a ^ b; }
    3-bool And ( bool a, bool b ){ return a & b; }
    1+bool Or ( bool a, bool b ){ return a ? a : b; }
    2+bool And ( bool a, bool b ){ return a ? b : false; }
    3+bool Xor ( bool a, bool b ){ return And(a,b) ? false: Or(a,b); }