/* ARM assembly Raspberry PI  */
/*  program square4.s   */

/************************************/
/* Constantes                       */
/************************************/
.equ STDOUT, 1     @ Linux output console
.equ EXIT,   1     @ Linux syscall
.equ WRITE,  4     @ Linux syscall

.equ NBBOX,  7

/*********************************/
/* Initialized data              */
/*********************************/
.data
sMessDeb:           .ascii "a="
sMessValeur_a:     .fill 11, 1, ' '            @ size => 11
                    .ascii "b="
sMessValeur_b:     .fill 11, 1, ' '            @ size => 11
                    .ascii "c="
sMessValeur_c:     .fill 11, 1, ' '            @ size => 11
                    .ascii "d="
sMessValeur_d:     .fill 11, 1, ' '            @ size => 11
                    .ascii "\n"
                    .ascii "e="
sMessValeur_e:     .fill 11, 1, ' '            @ size => 11
                    .ascii "f="
sMessValeur_f:     .fill 11, 1, ' '            @ size => 11
                    .ascii "g="
sMessValeur_g:     .fill 11, 1, ' '            @ size => 11

szCarriageReturn:   .asciz "\n************************\n"

sMessNbSolution:   .ascii "Number of solutions :"
sMessCounter:     .fill 11, 1, ' '            @ size => 11
                   .asciz "\n\n\n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
iValues_a:                .skip 4 * NBBOX
iValues_b:                .skip 4 * NBBOX - 1
iValues_c:                .skip 4 * NBBOX - 2
iValues_d:                .skip 4 * NBBOX - 3
iValues_e:                .skip 4 * NBBOX - 4
iValues_f:                .skip 4 * NBBOX - 5
iValues_g:                .skip 4 * NBBOX - 6
iCounterSol:              .skip 4
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                                             @ entry of program
    mov r0,#1
    mov r1,#7
    mov r2,#3                                     @ 0 = rien 1 = display 2 = count 3 = les deux
    bl searchPb
    mov r0,#3
    mov r1,#9
    mov r2,#3                                     @ 0 = rien 1 = display 2 = count 3 = les deux
    bl searchPb
    mov r0,#0
    mov r1,#9
    mov r2,#2                                     @ 0 = rien 1 = display 2 = count 3 = les deux
    bl prepSearchNU

100:                                              @ standard end of the program
    mov r0, #0                                    @ return code
    mov r7, #EXIT                                 @ request to exit program
    svc #0                                        @ perform the system call

iAdrszCarriageReturn:            .int szCarriageReturn

/******************************************************************/
/*     search problèm  value not unique                           */
/******************************************************************/
/* r0 contains start digit */
/* r1 contains end digit */
/* r2 contains action (0 display 1 count) */
prepSearchNU:
    push {r3-r12,lr}                              @ save  registers
    mov r5,#0                                     @ counter
    mov r12,r0                                    @ a
1:
    mov r11,r0                                    @ b
2:
    mov r10,r0                                    @ c
3:
    mov r9,r0                                     @ d
4:
    add r4,r12,r11                                @ a + b reference
    add r3,r11,r10
    add r3,r9                                     @ b + c + d
    cmp r4,r3
    bne 10f
    mov r8,r0                                     @ e
5:
    mov r7,r0                                     @ f
6:
    add r3,r9,r8
    add r3,r7                                     @ d + e + f
    cmp r3,r4
    bne 9f
    mov r6,r0                                     @ g
7:
    add r3,r7,r6                                  @ f + g
    cmp r3,r4
    bne 8f                                        @ not OK
                                                  @ OK
    add r5,#1                                     @ increment counter

8:
    add r6,#1                                     @ increment g
    cmp r6,r1
    ble 7b
9:
    add r7,#1                                     @ increment f
    cmp r7,r1
    ble 6b
    add r8,#1                                     @ increment e
    cmp r8,r1
    ble 5b
10:
    add r9,#1                                     @ increment d
    cmp r9,r1
    ble 4b
    add r10,#1                                    @ increment c
    cmp r10,r1
    ble 3b
    add r11,#1                                    @ increment b
    cmp r11,r1
    ble 2b
    add r12,#1                                    @ increment a
    cmp r12,r1
    ble 1b

    @ end
    tst r2,#0b10                                    @ print count ?
    beq 100f
    mov r0,r5                                       @ counter
    ldr r1,iAdrsMessCounter
    bl conversion10
    ldr r0,iAdrsMessNbSolution
    bl affichageMess

100:
    pop {r3-r12,lr}                                 @ restaur registers
    bx lr                                           @return
iAdrsMessCounter:                .int sMessCounter
iAdrsMessNbSolution:             .int sMessNbSolution

/******************************************************************/
/*     search problem  unique solution                            */
/******************************************************************/
/* r0 contains start digit */
/* r1 contains end digit */
/* r2 contains action (0 display 1 count) */
searchPb:
    push {r0-r12,lr}                                  @ save  registers
    @ init
    ldr r3,iAdriValues_a                              @ area value a
    mov r4,#0
1:                                                    @ loop init value a
    str r0,[r3,r4,lsl #2]
    add r4,#1
    add r0,#1
    cmp r0,r1
    ble 1b

    mov r5,#0                                         @ solution counter
    mov r12,#-1
2:
    add r12,#1                                        @ increment indice a
    cmp r12,#NBBOX-1
    bgt 90f
    ldr r0,iAdriValues_a                              @ area value a
    ldr r1,iAdriValues_b                              @ area value b
    mov r2,r12                                        @ indice  a
    mov r3,#NBBOX                                     @ number of origin values
    bl prepValues
    mov r11,#-1
3:
    add r11,#1                                        @ increment indice b
    cmp r11,#NBBOX - 2
    bgt 2b
    ldr r0,iAdriValues_b                              @ area value b
    ldr r1,iAdriValues_c                              @ area value c
    mov r2,r11                                        @ indice b
    mov r3,#NBBOX -1                                  @ number of origin values
    bl prepValues
    mov r10,#-1
4:
    add r10,#1
    cmp r10,#NBBOX - 3
    bgt 3b
    ldr r0,iAdriValues_c
    ldr r1,iAdriValues_d
    mov r2,r10
    mov r3,#NBBOX - 2
    bl prepValues
    mov r9,#-1
5:
    add r9,#1
    cmp r9,#NBBOX - 4
    bgt 4b
    @ control 2 firsts squares
    ldr r0,iAdriValues_a
    ldr r0,[r0,r12,lsl #2]
    ldr r1,iAdriValues_b
    ldr r1,[r1,r11,lsl #2]
    add r4,r0,r1                               @ a + b   value first square
    ldr r0,iAdriValues_c
    ldr r0,[r0,r10,lsl #2]
    add r7,r1,r0                               @ b + c
    ldr r1,iAdriValues_d
    ldr r1,[r1,r9,lsl #2]
    add r7,r1                                  @ b + c + d
    cmp r7,r4                                  @ equal first square ?
    bne 5b
    ldr r0,iAdriValues_d
    ldr r1,iAdriValues_e
    mov r2,r9
    mov r3,#NBBOX - 3
    bl prepValues
    mov r8,#-1
6:
    add r8,#1
    cmp r8,#NBBOX - 5
    bgt 5b
    ldr r0,iAdriValues_e
    ldr r1,iAdriValues_f
    mov r2,r8
    mov r3,#NBBOX - 4
    bl prepValues
    mov r7,#-1
7:
    add r7,#1
    cmp r7,#NBBOX - 6
    bgt 6b
    ldr r0,iAdriValues_d
    ldr r0,[r0,r9,lsl #2]
    ldr r1,iAdriValues_e
    ldr r1,[r1,r8,lsl #2]
    add r3,r0,r1                                @ d + e
    ldr r1,iAdriValues_f
    ldr r1,[r1,r7,lsl #2]
    add r3,r1                                   @ de + e + f
    cmp r3,r4                                   @ equal first square ?
    bne 7b
    ldr r0,iAdriValues_f
    ldr r1,iAdriValues_g
    mov r2,r7
    mov r3,#NBBOX - 5
    bl prepValues
    mov r6,#-1
8:
    add r6,#1
    cmp r6,#NBBOX - 7
    bgt 7b
    ldr r0,iAdriValues_f
    ldr r0,[r0,r7,lsl #2]
    ldr r1,iAdriValues_g
    ldr r1,[r1,r6,lsl #2]
    add r3,r0,r1                               @ f +g
    cmp r4,r3                                  @ equal first square ?
    bne 8b
    add r5,#1                                  @ increment counter
    ldr r0,[sp,#8]                             @ load action for two parameter in stack
    tst r0,#0b1
    beq 9f                                     @ display solution ?
    ldr r0,iAdriValues_a
    ldr r0,[r0,r12,lsl #2]
    ldr r1,iAdrsMessValeur_a
    bl conversion10
    ldr r0,iAdriValues_b
    ldr r0,[r0,r11,lsl #2]
    ldr r1,iAdrsMessValeur_b
    bl conversion10
    ldr r0,iAdriValues_c
    ldr r0,[r0,r10,lsl #2]
    ldr r1,iAdrsMessValeur_c
    bl conversion10
    ldr r0,iAdriValues_d
    ldr r0,[r0,r9,lsl #2]
    ldr r1,iAdrsMessValeur_d
    bl conversion10
    ldr r0,iAdriValues_e
    ldr r0,[r0,r8,lsl #2]
    ldr r1,iAdrsMessValeur_e
    bl conversion10
    ldr r0,iAdriValues_f
    ldr r0,[r0,r7,lsl #2]
    ldr r1,iAdrsMessValeur_f
    bl conversion10
    ldr r0,iAdriValues_g
    ldr r0,[r0,r6,lsl #2]
    ldr r1,iAdrsMessValeur_g
    bl conversion10
    ldr r0,iAdrsMessDeb
    bl affichageMess
9:
    b 8b    @ suite

90:
    ldr r0,[sp,#8]                                @ load action for two parameter in stack
    tst r0,#0b10
    beq 100f                                      @ display counter ?
    mov r0,r5
    ldr r1,iAdrsMessCounter
    bl conversion10
    ldr r0,iAdrsMessNbSolution
    bl affichageMess
100:
    pop {r0-r12,lr}                               @ restaur registers
    bx lr                                         @return
iAdriValues_a:                   .int iValues_a
iAdriValues_b:                   .int iValues_b
iAdriValues_c:                   .int iValues_c
iAdriValues_d:                   .int iValues_d
iAdriValues_e:                   .int iValues_e
iAdriValues_f:                   .int iValues_f
iAdriValues_g:                   .int iValues_g

iAdrsMessValeur_a:               .int sMessValeur_a
iAdrsMessValeur_b:               .int sMessValeur_b
iAdrsMessValeur_c:               .int sMessValeur_c
iAdrsMessValeur_d:               .int sMessValeur_d
iAdrsMessValeur_e:               .int sMessValeur_e
iAdrsMessValeur_f:               .int sMessValeur_f
iAdrsMessValeur_g:               .int sMessValeur_g
iAdrsMessDeb:                    .int sMessDeb
iAdriCounterSol:                 .int iCounterSol
/******************************************************************/
/*     copy value area  and substract value of indice             */
/******************************************************************/
/* r0 contains the address of values origin */
/* r1 contains the address of values destination */
/* r2 contains value indice to substract     */
/* r3 contains origin values number          */
prepValues:
    push {r1-r6,lr}                                @ save  registres
    mov r4,#0                                      @ indice origin value
    mov r5,#0                                      @ indice destination value
1:
    cmp r4,r2                                      @ substract indice ?
    beq 2f                                         @ yes -> jump
    ldr r6,[r0,r4,lsl #2]                          @ no -> copy value
    str r6,[r1,r5,lsl #2]
    add r5,#1                                      @ increment destination indice
2:
   add r4,#1                                       @ increment origin indice
   cmp r4,r3                                       @ end ?
   blt 1b
100:
    pop {r1-r6,lr}                                 @ restaur registres
    bx lr                                          @return
/******************************************************************/
/*     display text with size calculation                         */
/******************************************************************/
/* r0 contains the address of the message */
affichageMess:
    push {r0,r1,r2,r7,lr}                          @ save  registres
    mov r2,#0                                      @ counter length
1:                                                 @ loop length calculation
    ldrb r1,[r0,r2]                                @ read octet start position + index
    cmp r1,#0                                      @ if 0 its over
    addne r2,r2,#1                                 @ else add 1 in the length
    bne 1b                                         @ and loop
                                                   @ so here r2 contains the length of the message
    mov r1,r0                                      @ address message in r1
    mov r0,#STDOUT                                 @ code to write to the standard output Linux
    mov r7, #WRITE                                 @ code call system "write"
    svc #0                                         @ call systeme
    pop {r0,r1,r2,r7,lr}                           @ restaur des  2 registres */
    bx lr                                          @ return
/******************************************************************/
/*     Converting a register to a decimal unsigned                */
/******************************************************************/
/* r0 contains value and r1 address area   */
/* r0 return size of result (no zero final in area) */
/* area size => 11 bytes          */
.equ LGZONECAL,   10
conversion10:
    push {r1-r4,lr}                                 @ save registers
    mov r3,r1
    mov r2,#LGZONECAL
1:                                                  @ start loop
    bl divisionpar10U                               @ unsigned  r0 <- dividende. quotient ->r0 reste -> r1
    add r1,#48                                      @ digit
    strb r1,[r3,r2]                                 @ store digit on area
    cmp r0,#0                                       @ stop if quotient = 0
    subne r2,#1                                     @ else previous position
    bne 1b                                          @ and loop
                                                    @ and move digit from left of area
    mov r4,#0
2:
    ldrb r1,[r3,r2]
    strb r1,[r3,r4]
    add r2,#1
    add r4,#1
    cmp r2,#LGZONECAL
    ble 2b
                                                      @ and move spaces in end on area
    mov r0,r4                                         @ result length
    mov r1,#' '                                       @ space
3:
    strb r1,[r3,r4]                                   @ store space in area
    add r4,#1                                         @ next position
    cmp r4,#LGZONECAL
    ble 3b                                            @ loop if r4 <= area size

100:
    pop {r1-r4,lr}                                    @ restaur registres
    bx lr                                             @return

/***************************************************/
/*   division par 10   unsigned                    */
/***************************************************/
/* r0 dividende   */
/* r0 quotient    */
/* r1 remainder   */
divisionpar10U:
    push {r2,r3,r4, lr}
    mov r4,r0                                          @ save value
    ldr r3,iMagicNumber                                @ r3 <- magic_number    raspberry 1 2
    umull r1, r2, r3, r0                               @ r1<- Lower32Bits(r1*r0) r2<- Upper32Bits(r1*r0)
    mov r0, r2, LSR #3                                 @ r2 <- r2 >> shift 3
    add r2,r0,r0, lsl #2                               @ r2 <- r0 * 5
    sub r1,r4,r2, lsl #1                               @ r1 <- r4 - (r2 * 2)  = r4 - (r0 * 10)
    pop {r2,r3,r4,lr}
    bx lr                                              @ leave function
iMagicNumber:  	.int 0xCCCCCCCD


# syntax: GAWK -f 4-RINGS_OR_4-SQUARES_PUZZLE.AWK
# converted from C
BEGIN {
    cmd = "SORT /+16"
    four_squares(1,7,1,1)
    four_squares(3,9,1,1)
    four_squares(0,9,0,0)
    four_squares(0,6,1,0)
    four_squares(2,8,1,0)
    exit(0)
}
function four_squares(plo,phi,punique,pshow) {
    lo = plo
    hi = phi
    unique = punique
    show = pshow
    solutions = 0
    print("")
    if (show) {
      print("A B C D E F G  sum  A+B B+C+D D+E+F F+G")
      print("-------------  ---  -------------------")
    }
    acd()
    close(cmd)
    tmp = (unique) ? "unique" : "non-unique"
    printf("%d-%d: %d %s solutions\n",lo,hi,solutions,tmp)
}
function acd() {
    for (c=lo; c<=hi; c++) {
      for (d=lo; d<=hi; d++) {
        if (!unique || c != d) {
          a = c + d
          if (a >= lo && a <= hi && (!unique || (c != 0 && d != 0))) {
            ge()
          }
        }
      }
    }
}
function bf() {
    for (f=lo; f<=hi; f++) {
      if (!unique || (f != a && f != c && f != d && f != g && f != e)) {
        b = e + f - c
        if (b >= lo && b <= hi && (!unique || (b != a && b != c && b != d && b != g && b != e && b != f))) {
          solutions++
          if (show) {
            printf("%d %d %d %d %d %d %d %4d  ",a,b,c,d,e,f,g,a+b) | cmd
            printf("%d+%d ",a,b) | cmd
            printf("%d+%d+%d ",b,c,d) | cmd
            printf("%d+%d+%d ",d,e,f) | cmd
            printf("%d+%d\n",f,g) | cmd
          }
        }
      }
    }
}
function ge() {
    for (e=lo; e<=hi; e++) {
      if (!unique || (e != a && e != c && e != d)) {
        g = d + e
        if (g >= lo && g <= hi && (!unique || (g != a && g != c && g != d && g != e))) {
          bf()
        }
      }
    }
}


#include <stdio.h>

#define TRUE 1
#define FALSE 0

int a,b,c,d,e,f,g;
int lo,hi,unique,show;
int solutions;

void
bf()
{
    for (f = lo;f <= hi; f++)
        if ((!unique) ||
           ((f != a) && (f != c) && (f != d) && (f != g) && (f != e)))
            {
            b = e + f - c;
            if ((b >= lo) && (b <= hi) &&
                   ((!unique) || ((b != a) && (b != c) &&
                   (b != d) && (b != g) && (b != e) && (b != f))))
                {
                solutions++;
                if (show)
                    printf("%d %d %d %d %d %d %d\n",a,b,c,d,e,f,g);
                }
            }
}

void
ge()
{
    for (e = lo;e <= hi; e++)
        if ((!unique) || ((e != a) && (e != c) && (e != d)))
            {
            g = d + e;
            if ((g >= lo) && (g <= hi) &&
                   ((!unique) || ((g != a) && (g != c) &&
                   (g != d) && (g != e))))
                bf();
            }
}

void
acd()
{
    for (c = lo;c <= hi; c++)
        for (d = lo;d <= hi; d++)
            if ((!unique) || (c != d))
                {
                a = c + d;
                if ((a >= lo) && (a <= hi) &&
                   ((!unique) || ((c != 0) && (d != 0))))
                    ge();
                }
}

void
foursquares(int plo,int phi, int punique,int pshow)
{
    lo = plo;
    hi = phi;
    unique = punique;
    show = pshow;
    solutions = 0;

    printf("\n");

    acd();

    if (unique)
        printf("\n%d unique solutions in %d to %d\n",solutions,lo,hi);
    else
        printf("\n%d non-unique solutions in %d to %d\n",solutions,lo,hi);
}

main()
{
    foursquares(1,7,TRUE,TRUE);
    foursquares(3,9,TRUE,TRUE);
    foursquares(0,9,FALSE,FALSE);
}


using System;
using System.Linq;

namespace Four_Squares_Puzzle {
    class Program {
        static void Main(string[] args) {
            fourSquare(1, 7, true, true);
            fourSquare(3, 9, true, true);
            fourSquare(0, 9, false, false);
        }

        private static void fourSquare(int low, int high, bool unique, bool print) {
            int count = 0;

            if (print) {
                Console.WriteLine("a b c d e f g");
            }
            for (int a = low; a <= high; ++a) {
                for (int b = low; b <= high; ++b) {
                    if (notValid(unique, b, a)) continue;

                    int fp = a + b;
                    for (int c = low; c <= high; ++c) {
                        if (notValid(unique, c, b, a)) continue;
                        for (int d = low; d <= high; ++d) {
                            if (notValid(unique, d, c, b, a)) continue;
                            if (fp != b + c + d) continue;

                            for (int e = low; e <= high; ++e) {
                                if (notValid(unique, e, d, c, b, a)) continue;
                                for (int f = low; f <= high; ++f) {
                                    if (notValid(unique, f, e, d, c, b, a)) continue;
                                    if (fp != d + e + f) continue;

                                    for (int g = low; g <= high; ++g) {
                                        if (notValid(unique, g, f, e, d, c, b, a)) continue;
                                        if (fp != f + g) continue;

                                        ++count;
                                        if (print) {
                                            Console.WriteLine("{0} {1} {2} {3} {4} {5} {6}", a, b, c, d, e, f, g);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (unique) {
                Console.WriteLine("There are {0} unique solutions in [{1}, {2}]", count, low, high);
            }
            else {
                Console.WriteLine("There are {0} non-unique solutions in [{1}, {2}]", count, low, high);
            }
        }

        private static bool notValid(bool unique, int needle, params int[] haystack) {
            return unique && haystack.Any(p => p == needle);
        }
    }
}


//C++14/17
#include <algorithm>//std::for_each
#include <iostream> //std::cout
#include <numeric>  //std::iota
#include <vector>   //std::vector, save solutions
#include <list>     //std::list, for fast erase

using std::begin, std::end, std::for_each;

//Generates all the valid solutions for the problem in the specified range [from, to)
std::list<std::vector<int>> combinations(int from, int to)
{
    if (from > to)
        return {};                          //Return nothing if limits are invalid

    auto pool = std::vector<int>(to - from);//Here we'll save our values
    std::iota(begin(pool), end(pool), from);//Populates pool

    auto solutions = std::list<std::vector<int>>{};   //List for the solutions

    //Brute-force calculation of valid values...
    for (auto a : pool)
        for (auto b : pool)
            for (auto c : pool)
                for (auto d : pool)
                    for (auto e : pool)
                        for (auto f : pool)
                            for (auto g : pool)
                                if ( a      == c + d
                                  && b + c  == e + f
                                  && d + e  ==     g )
                                    solutions.push_back({a, b, c, d, e, f, g});
    return solutions;
}

//Filter the list generated from "combinations" and return only lists with no repetitions
std::list<std::vector<int>> filter_unique(int from, int to)
{
    //Helper lambda to check repetitions:
    //If the count is > 1 for an element, there must be a repetition inside the range
    auto has_non_unique_values = [](const auto & range, auto target)
    {
        return std::count( begin(range), end(range), target) > 1;
    };

    //Generates all the solutions...
    auto results = combinations(from, to);

    //For each solution, find duplicates inside
    for (auto subrange = cbegin(results); subrange != cend(results); ++subrange)
    {
        bool repetition = false;

        //If some element is repeated, repetition becomes true
        for (auto x : *subrange)
            repetition |= has_non_unique_values(*subrange, x);

        if (repetition)    //If repetition is true, remove the current subrange from the list
        {
            results.erase(subrange);        //Deletes subrange from solutions
            --subrange;                     //Rewind to the last subrange analysed
        }
    }

    return results; //Finally return remaining results
}

template <class Container> //Template for the sake of simplicity
inline void print_range(const Container & c)
{
    for (const auto & subrange : c)
    {
        std::cout << "[";
        for (auto elem : subrange)
            std::cout << elem << ' ';
        std::cout << "\b]\n";
    }
}

int main()
{
    std::cout << "Unique-numbers combinations in range 1-7:\n";
    auto solution1 = filter_unique(1, 8);
    print_range(solution1);
    std::cout << "\nUnique-numbers combinations in range 3-9:\n";
    auto solution2 = filter_unique(3,10);
    print_range(solution2);
    std::cout << "\nNumber of combinations in range 0-9: "
              << combinations(0, 10).size() << "." << std::endl;

    return 0;
}


(use '[clojure.math.combinatorics]

(defn rings [r & {:keys [unique] :or {unique true}}]
    (if unique
      (apply concat (map permutations (combinations r 7)))
      (selections r 7)))

(defn four-rings [low high & {:keys [unique] :or {unique true}}]
  (for [[a b c d e f g] (rings (range low (inc high)) :unique unique)
    :when (= (+ a b) (+ b c d) (+ d e f) (+ f g))] [a b c d e f g]))


(defpackage four-rings
  (:use common-lisp)
  (:export display-solutions))
(in-package four-rings)

(defun correct-answer-p (a b c d e f g)
  (let ((v (+ a b)))
    (and (equal v (+ b c d))
         (equal v (+ d e f))
         (equal v (+ f g)))))

(defun combinations-if (func len unique min max)
  (let ((results nil))
    (labels ((inner (cur)
               (if (eql (length cur) len)
                 (when (apply func (reverse cur))
                   (push cur results))
                 (dotimes (i (- max min))
                   (when (or (not unique)
                             (not (member (+ i min) cur)))
                     (inner (append (list (+ i min)) cur)))))))
      (inner nil))
    results))

(defun four-rings-solutions (low high unique)
  (combinations-if #'correct-answer-p 7 unique low (1+ high)))

(defun display-solutions ()
  (let ((letters '((a b c d e f g))))
    (format t "Low 1, High 7, unique letters: ~%~{~{~3A~}~%~}~%"
            (append letters (four-rings-solutions 1 7 t)))
    (format t "Low 3, High 9, unique letters: ~%~{~{~3A~}~%~}~%"
            (append letters (four-rings-solutions 3 9 t)))
    (format t "Number of solutions for Low 0, High 9 non-unique:~%~A~%"
            (length (four-rings-solutions 0 9 nil)))))


def check(list)
  a, b, c, d, e, f, g = list
  first = a + b
  {b + c + d, d + e + f, f + g}.all? &.==(first)
end

def four_squares(low, high, unique = true, show = unique)
  solutions = [] of Array(Int32)
  if unique
    uniq = "unique"
    (low..high).to_a.each_permutation(7, true) { |ary| solutions << ary.clone if check(ary) }
  else
    uniq = "non-unique"
    (low..high).to_a.each_repeated_permutation(7, true) { |ary| solutions << ary.clone if check(ary) }
  end
  if show
    puts " " + ("a".."g").join("  ")
    solutions.each { |ary| p ary }
  end
  puts "#{solutions.size} #{uniq} solutions in #{low} to #{high}"
  puts
end

{ {1, 7}, {3, 9} }.each do |(low, high)|
  four_squares(low, high)
end
four_squares(0, 9, false)


import std.stdio;

void main() {
    fourSquare(1,7,true,true);
    fourSquare(3,9,true,true);
    fourSquare(0,9,false,false);
}

void fourSquare(int low, int high, bool unique, bool print) {
    int count;

    if (print) {
        writeln("a b c d e f g");
    }
    for (int a=low; a<=high; ++a) {
        for (int b=low; b<=high; ++b) {
            if (!valid(unique, a, b)) continue;

            int fp = a+b;
            for (int c=low; c<=high; ++c) {
                if (!valid(unique, c, a, b)) continue;
                for (int d=low; d<=high; ++d) {
                    if (!valid(unique, d, a, b, c)) continue;
                    if (fp != b+c+d) continue;

                    for (int e=low; e<=high; ++e) {
                        if (!valid(unique, e, a, b, c, d)) continue;
                        for (int f=low; f<=high; ++f) {
                            if (!valid(unique, f, a, b, c, d, e)) continue;
                            if (fp != d+e+f) continue;

                            for (int g=low; g<=high; ++g) {
                                if (!valid(unique, g, a, b, c, d, e, f)) continue;
                                if (fp != f+g) continue;

                                ++count;
                                if (print) {
                                    writeln(a,' ',b,' ',c,' ',d,' ',e,' ',f,' ',g);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    if (unique) {
        writeln("There are ", count, " unique solutions in [",low,",",high,"]");
    } else {
        writeln("There are ", count, " non-unique solutions in [",low,",",high,"]");
    }
}

bool valid(bool unique, int needle, int[] haystack ...) {
    if (unique) {
        foreach (value; haystack) {
            if (needle == value) {
                return false;
            }
        }
    }
    return true;
}


(* A simple function to generate the sequence
   Nigel Galloway: January 31st., 2017 *)
type G = {d:int;x:int;b:int;f:int}
let N n g =
  {(max (n-g) n) .. (min (g-n) g)} |> Seq.collect(fun d->{(max (d+n+n) (n+n))..(min (g+g) (d+g+g))}           |> Seq.collect(fun x ->
  seq{for a in n .. g do for b in n .. g do if (a+b) = x then for c in n .. g do if (b+c+d) = x then yield b} |> Seq.collect(fun b ->
  seq{for f in n .. g do for G in n .. g do if (f+G) = x then for e in n .. g do if (f+e+d) = x then yield f} |> Seq.map(fun f -> {d=d;x=x;b=b;f=f}))))


USING: arrays backtrack formatting grouping kernel locals math
math.ranges prettyprint sequences sequences.generalizations
sets ;
IN: rosetta-code.4-rings

:: 4-rings ( lo hi unique? -- seq ) [
        7 [ lo hi [a,b] amb-lazy ] replicate
        7 firstn :> ( a b c d e f g )
        { a b c d e f g } :> p
        a b +
        b c d + +
        d e f + +
        f g +
        4array all-equal?
        unique? [ p all-unique? and ] when
        must-be-true p
    ] bag-of ;

: report ( lo hi unique? -- )
    3dup 4-rings over [ dup . ] when length swap "" "non-" ?
    "In [%d, %d] there are %d %sunique solutions.\n" printf ;

1 7 t report
3 9 t report
0 9 f report


WRITE(...) FIRST,LAST,IF (UNIQUE) THEN "Distinct values only" ELSE "Repeated values allowed" FI // "."


' version 18-03-2017
' compile with: fbc -s console

' TRUE/FALSE are built-in constants since FreeBASIC 1.04
' But we have to define them for older versions.
#Ifndef TRUE
  #Define FALSE 0
  #Define TRUE Not FALSE
#EndIf

Sub four_rings(low As Long, high As Long, unique As Long, show As Long)

  Dim As Long a, b, c, d, e, f, g
  Dim As ULong t, total
  Dim As ULong l = Len(Str(high))
  If l < Len(Str(low)) Then l = Len(Str(low))

  If show = TRUE Then
    For a = 97 To 103
      Print Space(l); Chr(a);
    Next
    Print
    Print String((l +1) * 7, "=");
    Print
  End If

  For a = low To high
    For b = low To high
      If unique = TRUE Then
        If b = a Then Continue For
      End If
      t = a + b
      For c = low To high
        If unique = TRUE Then
          If c = a OrElse c = b Then Continue For
        End If
        For d = low To high
          If unique = TRUE Then
            If d = a OrElse d = b OrElse d = c Then Continue For
          End If
          If b + c + d = t Then
            For e = low To high
              If unique = TRUE Then
                If e = a OrElse e = b OrElse e = c OrElse e = d Then Continue For
              End If
              For f = low To high
                If unique = TRUE Then
                  If f = a OrElse f = b OrElse f = c OrElse f = d OrElse f = e Then Continue For
                End If
                If d + e + f = t Then
                  For g = low To high
                    If unique = TRUE Then
                      If g = a OrElse g = b OrElse g = c OrElse g = d OrElse g = e OrElse g = f Then Continue For
                    End If
                    If f + g = t Then
                      total += 1
                      If show = TRUE Then
                        Print Using String(l +1, "#"); a; b; c; d; e; f; g
                      End If
                    End If
                  Next
                End If
              Next
            Next
          End If
        Next
      Next
    Next
  Next

  If unique = TRUE Then
    Print
    Print total; " Unique solutions for "; Str(low); " to "; Str(high)
  Else
    Print total; " Non unique solutions for "; Str(low); " to "; Str(high)
  End If
  Print String(40, "-") : Print
End Sub

' ------=< MAIN >=------

four_rings(1, 7,  TRUE,  TRUE)
four_rings(3, 9,  TRUE,  TRUE)
four_rings(0, 9, FALSE, FALSE)

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import "fmt"

func main(){
	n, c := getCombs(1,7,true)
	fmt.Printf("%d unique solutions in 1 to 7\n",n)
	fmt.Println(c)
	n, c = getCombs(3,9,true)
	fmt.Printf("%d unique solutions in 3 to 9\n",n)
	fmt.Println(c)
	n, _ = getCombs(0,9,false)
	fmt.Printf("%d non-unique solutions in 0 to 9\n",n)
}

func getCombs(low,high int,unique bool) (num int,validCombs [][]int){
	for a := low; a <= high; a++ {
		for b := low; b <= high; b++ {
			for c := low; c <= high; c++ {
				for d := low; d <= high; d++ {
					for e := low; e <= high; e++ {
						for f := low; f <= high; f++ {
							for g := low; g <= high; g++ {
								if validComb(a,b,c,d,e,f,g) {
									if !unique || isUnique(a,b,c,d,e,f,g) {
										num++
										validCombs = append(validCombs,[]int{a,b,c,d,e,f,g})
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return
}
func isUnique(a,b,c,d,e,f,g int) (res bool) {
	data := make(map[int]int)
	data[a]++
	data[b]++
	data[c]++
	data[d]++
	data[e]++
	data[f]++
	data[g]++
	return len(data) == 7
}
func validComb(a,b,c,d,e,f,g int) bool{
	square1 := a + b
	square2 := b + c + d
	square3 := d + e + f
	square4 := f + g
	return square1 == square2 && square2 == square3 && square3 == square4
}


class FourRings {
    static void main(String[] args) {
        fourSquare(1, 7, true, true)
        fourSquare(3, 9, true, true)
        fourSquare(0, 9, false, false)
    }

    private static void fourSquare(int low, int high, boolean unique, boolean print) {
        int count = 0

        if (print) {
            println("a b c d e f g")
        }
        for (int a = low; a <= high; ++a) {
            for (int b = low; b <= high; ++b) {
                if (notValid(unique, a, b)) continue

                int fp = a + b
                for (int c = low; c <= high; ++c) {
                    if (notValid(unique, c, a, b)) continue
                    for (int d = low; d <= high; ++d) {
                        if (notValid(unique, d, a, b, c)) continue
                        if (fp != b + c + d) continue

                        for (int e = low; e <= high; ++e) {
                            if (notValid(unique, e, a, b, c, d)) continue
                            for (int f = low; f <= high; ++f) {
                                if (notValid(unique, f, a, b, c, d, e)) continue
                                if (fp != d + e + f) continue

                                for (int g = low; g <= high; ++g) {
                                    if (notValid(unique, g, a, b, c, d, e, f)) continue
                                    if (fp != f + g) continue

                                    ++count
                                    if (print) {
                                        printf("%d %d %d %d %d %d %d%n", a, b, c, d, e, f, g)
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (unique) {
            printf("There are %d unique solutions in [%d, %d]%n", count, low, high)
        } else {
            printf("There are %d non-unique solutions in [%d, %d]%n", count, low, high)
        }
    }

    private static boolean notValid(boolean unique, int needle, int ... haystack) {
        return unique && Arrays.stream(haystack).anyMatch({ p -> p == needle })
    }
}


import Data.List
import Control.Monad

perms :: (Eq a) => [a] -> [[a]]
perms [] = [[]]
perms xs = [ x:xr | x <- xs, xr <- perms (xs\\[x]) ]

combs :: (Eq a) => Int -> [a] -> [[a]]
combs 0 _ = [[]]
combs n xs = [ x:xr | x <- xs, xr <- combs (n-1) xs ]

ringCheck :: [Int] -> Bool
ringCheck [x0, x1, x2, x3, x4, x5, x6] =
          v == x1+x2+x3
       && v == x3+x4+x5
       && v == x5+x6
    where v = x0 + x1

fourRings :: Int -> Int -> Bool -> Bool -> IO ()
fourRings low high allowRepeats verbose = do
    let candidates = if allowRepeats
                     then combs 7 [low..high]
                     else perms [low..high]

        solutions = filter ringCheck candidates

    when verbose $ mapM_ print solutions

    putStrLn $    show (length solutions)
               ++ (if allowRepeats then " non" else "")
               ++ " unique solutions for "
               ++ show low
               ++ " to "
               ++ show high

    putStrLn ""

main = do
   fourRings 1 7 False True
   fourRings 3 9 False True
   fourRings 0 9 True False


import java.util.Arrays;

public class FourSquares {
    public static void main(String[] args) {
        fourSquare(1, 7, true, true);
        fourSquare(3, 9, true, true);
        fourSquare(0, 9, false, false);
    }

    private static void fourSquare(int low, int high, boolean unique, boolean print) {
        int count = 0;

        if (print) {
            System.out.println("a b c d e f g");
        }
        for (int a = low; a <= high; ++a) {
            for (int b = low; b <= high; ++b) {
                if (notValid(unique, a, b)) continue;

                int fp = a + b;
                for (int c = low; c <= high; ++c) {
                    if (notValid(unique, c, a, b)) continue;
                    for (int d = low; d <= high; ++d) {
                        if (notValid(unique, d, a, b, c)) continue;
                        if (fp != b + c + d) continue;

                        for (int e = low; e <= high; ++e) {
                            if (notValid(unique, e, a, b, c, d)) continue;
                            for (int f = low; f <= high; ++f) {
                                if (notValid(unique, f, a, b, c, d, e)) continue;
                                if (fp != d + e + f) continue;

                                for (int g = low; g <= high; ++g) {
                                    if (notValid(unique, g, a, b, c, d, e, f)) continue;
                                    if (fp != f + g) continue;

                                    ++count;
                                    if (print) {
                                        System.out.printf("%d %d %d %d %d %d %d%n", a, b, c, d, e, f, g);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (unique) {
            System.out.printf("There are %d unique solutions in [%d, %d]%n", count, low, high);
        } else {
            System.out.printf("There are %d non-unique solutions in [%d, %d]%n", count, low, high);
        }
    }

    private static boolean notValid(boolean unique, int needle, int... haystack) {
        return unique && Arrays.stream(haystack).anyMatch(p -> p == needle);
    }
}


(() => {

    // 4-rings or 4-squares puzzle ------------------------

    // rings :: noRepeatedDigits -> DigitList -> solutions
    // rings :: Bool -> [Int] -> [[Int]]
    const rings = (uniq, digits) => {
        return 0 < digits.length ? (() => {
            const
                ns = sortBy(flip(compare), digits),
                h = head(ns);

            // CENTRAL DIGIT :: d
            return bindList(
                ns,
                d => {
                    const ts = filter(x => (x + d) <= h, ns);

                    // LEFT OF CENTRE :: c and a
                    return bindList(
                        uniq ? delete_(d, ts) : ns,
                        c => {
                            const a = c + d;

                            // RIGHT OF CENTRE :: e and g
                            return a > h ? (
                                []
                            ) : bindList(uniq ? (
                                difference(ts, [d, c, a])
                            ) : ns, e => {
                                const g = d + e;
                                return ((g > h) || (uniq && (g === c))) ? (
                                    []
                                ) : (() => {
                                    const
                                        agDelta = a - g,
                                        bfs = uniq ? difference(
                                            ns, [d, c, e, g, a]
                                        ) : ns;

                                    // MID LEFT, MID RIGHT :: b and f
                                    return bindList(bfs, b => {
                                        const f = b + agDelta;
                                        return elem(f, bfs) && (
                                            !uniq || notElem(f, [
                                                a, b, c, d, e, g
                                            ])
                                        ) ? ([
                                            [a, b, c, d, e, f, g]
                                        ]) : [];
                                    });
                                })();
                            });
                        });
                });
        })() : []
    };

    // TEST -----------------------------------------------
    const main = () => {
        return unlines([
            'rings(true, enumFromTo(1,7))\n',
            unlines(map(show, rings(true, enumFromTo(1, 7)))),

            '\nrings(true, enumFromTo(3, 9))\n',
            unlines(map(show, rings(true, enumFromTo(3, 9)))),

            '\nlength(rings(false, enumFromTo(0, 9)))\n',
            length(rings(false, enumFromTo(0, 9)))
            .toString(),
            ''
        ]);
    };

    // GENERIC FUNCTIONS ----------------------------------

    // bindList (>>=) :: [a] -> (a -> [b]) -> [b]
    const bindList = (xs, mf) => [].concat.apply([], xs.map(mf));

    // compare :: a -> a -> Ordering
    const compare = (a, b) => a < b ? -1 : (a > b ? 1 : 0);

    // delete_ :: Eq a => a -> [a] -> [a]
    const delete_ = (x, xs) =>
        xs.length > 0 ? (
            (x === xs[0]) ? (
                xs.slice(1)
            ) : [xs[0]].concat(delete_(x, xs.slice(1)))
        ) : [];

    // difference :: Eq a => [a] -> [a] -> [a]
    const difference = (xs, ys) => {
        const s = new Set(ys);
        return xs.filter(x => !s.has(x));
    };

    // elem :: Eq a => a -> [a] -> Bool
    const elem = (x, xs) => xs.indexOf(x) !== -1;

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = (m, n) =>
        Array.from({
            length: Math.floor(n - m) + 1
        }, (_, i) => m + i);

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = (f, xs) => xs.filter(f);

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f => (a, b) => f.apply(null, [b, a]);

    // head :: [a] -> a
    const head = xs => xs.length ? xs[0] : undefined;

    // length :: [a] -> Int
    const length = xs => xs.length;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // notElem :: Eq a => a -> [a] -> Bool
    const notElem = (x, xs) => xs.indexOf(x) === -1;

    // show :: a -> String
    const show = x => JSON.stringify(x); //, null, 2);

    // sortBy :: (a -> a -> Ordering) -> [a] -> [a]
    const sortBy = (f, xs) => xs.sort(f);

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // MAIN ---
    return main();
})();


# Generate a stream of all the permutations of the input array
def permutations:
  if length == 0 then []
  else
    range(0;length) as $i
    | [.[$i]] + (del(.[$i])|permutations)
  end ;

# Permutations of a ... n inclusive
def permutations(a;n):
  [range(a;n+1)] | permutations;

# value of a box
# Input: the table of values
def valueOfBox($box):
  [ .[ $box[] ]] | add;

def allEqual($boxes):
  . as $values
  | valueOfBox($boxes[0]) as $sum
  | all($boxes[1:][]; . as $box | $values | valueOfBox($box) == $sum);

def combinations($m; $n; $size):
  [range(0; $size) | [range($m; $n)]] | combinations;

def count(s): reduce s as $x (null; .+1);

# a=0, b=1, etc
def boxes: [[0,1], [1,2,3], [3,4,5], [5,6]];

def tasks:
  "1 to 7:",
  (permutations(1;7) | select(allEqual(boxes))),
  "\n3 to 9:",
  (permutations(3;9) | select(allEqual(boxes))),
  "\n0 to 9:\n\(count(permutations(0;9) | select(allEqual(boxes))))",
  "\nThere are \(count(combinations(0;10;7) | select(allEqual(boxes)))) solutions for 0 to 9 with replacement."
;

tasks


using Combinatorics

function foursquares(low, high, onlyunique=true, showsolutions=true)
    integers = collect(low:high)
    count = 0
    sumsallequal(c) = c[1] + c[2] == c[2] + c[3] + c[4] == c[4] + c[5] + c[6] == c[6] + c[7]
    combos = onlyunique ? combinations(integers) :
                          with_replacement_combinations(integers, 7)
    for combo in combos, plist in unique(collect(permutations(combo, 7)))
        if sumsallequal(plist)
            count += 1
            if showsolutions
                println("$plist is a solution for the list $integers")
            end
        end
    end
    println("""Total $(onlyunique?"unique ":"")solutions for HIGH $high, LOW $low: $count""")
end

foursquares(1, 7, true, true)
foursquares(3, 9, true, true)
foursquares(0, 9, false, false)


// version 1.1.2

class FourSquares(
    private val lo: Int,
    private val hi: Int,
    private val unique: Boolean,
    private val show: Boolean
) {
    private var a = 0
    private var b = 0
    private var c = 0
    private var d = 0
    private var e = 0
    private var f = 0
    private var g = 0
    private var s = 0

    init {
        println()
        if (show) {
            println("a b c d e f g")
            println("-------------")
        }
        acd()
        println("\n$s ${if (unique) "unique" else "non-unique"} solutions in $lo to $hi")
    }

    private fun acd() {
        c = lo
        while (c <= hi) {
            d = lo
            while (d <= hi) {
                if (!unique || c != d) {
                    a = c + d
                    if ((a in lo..hi) && (!unique || (c != 0 && d!= 0))) ge()
                }
                d++
            }
            c++
        }
    }

    private fun bf() {
        f = lo
        while (f <= hi) {
            if (!unique || (f != a && f != c && f != d && f != e && f!= g)) {
                b = e + f - c
                if ((b in lo..hi) && (!unique || (b != a && b != c && b != d && b != e && b != f && b!= g))) {
                    s++
                    if (show) println("$a $b $c $d $e $f $g")
                }
            }
            f++
        }
    }

    private fun ge() {
        e = lo
        while (e <= hi) {
            if (!unique || (e != a && e != c && e != d)) {
                g = d + e
                if ((g in lo..hi) && (!unique || (g != a && g != c && g != d && g != e))) bf()
            }
            e++
        }
    }
}

fun main(args: Array<String>) {
    FourSquares(1, 7, true, true)
    FourSquares(3, 9, true, true)
    FourSquares(0, 9, false, false)
}


function valid(unique,needle,haystack)
    if unique then
        for _,value in pairs(haystack) do
            if needle == value then
                return false
            end
        end
    end
    return true
end

function fourSquare(low,high,unique,prnt)
    count = 0
    if prnt then
        print("a", "b", "c", "d", "e", "f", "g")
    end
    for a=low,high do
        for b=low,high do
            if valid(unique, a, {b}) then
                fp = a + b
                for c=low,high do
                    if valid(unique, c, {a, b}) then
                        for d=low,high do
                            if valid(unique, d, {a, b, c}) and fp == b + c + d then
                                for e=low,high do
                                    if valid(unique, e, {a, b, c, d}) then
                                        for f=low,high do
                                            if valid(unique, f, {a, b, c, d, e}) and fp == d + e + f then
                                                for g=low,high do
                                                    if valid(unique, g, {a, b, c, d, e, f}) and fp == f + g then
                                                        count = count + 1
                                                        if prnt then
                                                            print(a, b, c, d, e, f, g)
                                                        end
                                                    end
                                                end
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
    if unique then
        print(string.format("There are %d unique solutions in [%d, %d]", count, low, high))
    else
        print(string.format("There are %d non-unique solutions in [%d, %d]", count, low, high))
    end
end

fourSquare(1,7,true,true)
fourSquare(3,9,true,true)
fourSquare(0,9,false,false)


{low, high} = {1, 7};
SolveValues[{a + b == b + c + d == d + e + f == f + g, low <= a <= high,
  low <= b <= high, low <= c <= high, low <= d <= high,
  low <= e <= high, low <= f <= high, low <= g <= high,
  a != b != c != d != e != f != g}, {a, b, c, d, e, f, g}, Integers]

{low, high} = {3, 9};
SolveValues[{a + b == b + c + d == d + e + f == f + g, low <= a <= high,
  low <= b <= high, low <= c <= high, low <= d <= high,
  low <= e <= high, low <= f <= high, low <= g <= high,
  a != b != c != d != e != f != g}, {a, b, c, d, e, f, g}, Integers]

{low, high} = {0, 9};
SolveValues[{a + b == b + c + d == d + e + f == f + g, low <= a <= high,
   low <= b <= high, low <= c <= high, low <= d <= high,
   low <= e <= high, low <= f <= high, low <= g <= high}, {a, b, c, d,
    e, f, g}, Integers] // Length


MODULE FourSquare;
FROM Conversions IMPORT IntToStr;
FROM Terminal IMPORT *;

PROCEDURE WriteInt(num : INTEGER);
VAR str : ARRAY[0..16] OF CHAR;
BEGIN
    IntToStr(num,str);
    WriteString(str);
END WriteInt;

PROCEDURE four_square(low, high : INTEGER; unique, print : BOOLEAN);
VAR count : INTEGER;
VAR a, b, c, d, e, f, g : INTEGER;
VAR fp : INTEGER;
BEGIN
    count:=0;

    IF print THEN
        WriteString('a b c d e f g');
        WriteLn;
    END;
    FOR a:=low TO high DO
        FOR b:=low TO high DO
            IF unique AND (b=a) THEN CONTINUE; END;

            fp:=a+b;
            FOR c:=low TO high DO
                IF unique AND ((c=a) OR (c=b)) THEN CONTINUE; END;
                FOR d:=low TO high DO
                    IF unique AND ((d=a) OR (d=b) OR (d=c)) THEN CONTINUE; END;
                    IF fp # b+c+d THEN CONTINUE; END;

                    FOR e:=low TO high DO
                        IF unique AND ((e=a) OR (e=b) OR (e=c) OR (e=d)) THEN CONTINUE; END;
                        FOR f:=low TO high DO
                            IF unique AND ((f=a) OR (f=b) OR (f=c) OR (f=d) OR (f=e)) THEN CONTINUE; END;
                            IF fp # d+e+f THEN CONTINUE; END;

                            FOR g:=low TO high DO
                                IF unique AND ((g=a) OR (g=b) OR (g=c) OR (g=d) OR (g=e) OR (g=f)) THEN CONTINUE; END;
                                IF fp # f+g THEN CONTINUE; END;

                                INC(count);
                                IF print THEN
                                    WriteInt(a);
                                    WriteString(' ');
                                    WriteInt(b);
                                    WriteString(' ');
                                    WriteInt(c);
                                    WriteString(' ');
                                    WriteInt(d);
                                    WriteString(' ');
                                    WriteInt(e);
                                    WriteString(' ');
                                    WriteInt(f);
                                    WriteString(' ');
                                    WriteInt(g);
                                    WriteLn;
                                END;
                            END;
                        END;
                    END;
                END;
            END;
        END;
    END;
    IF unique THEN
        WriteString('There are ');
        WriteInt(count);
        WriteString(' unique solutions in [');
        WriteInt(low);
        WriteString(', ');
        WriteInt(high);
        WriteString(']');
        WriteLn;
    ELSE
        WriteString('There are ');
        WriteInt(count);
        WriteString(' non-unique solutions in [');
        WriteInt(low);
        WriteString(', ');
        WriteInt(high);
        WriteString(']');
        WriteLn;
    END;
END four_square;

BEGIN
    four_square(1,7,TRUE,TRUE);
    four_square(3,9,TRUE,TRUE);
    four_square(0,9,FALSE,FALSE);
    ReadChar; (* Wait so results can be viewed. *)
END FourSquare.


func isUnique(a, b, c, d, e, f, g: uint8): bool =
  a != b and a != c and a != d and a != e and a != f and a != g and
    b != c and b != d and b != e and b != f and b != g and
    c != d and c != e and c != f and c != g and
    d != e and d != f and d != f and
    e != f and e != g and
    f != g

func isSolution(a, b, c, d, e, f, g: uint8): bool =
  let sum = a + b
  sum == b + c + d and sum == d + e + f and sum == f + g

func fourSquares(l, h: uint8, unique: bool): seq[array[7, uint8]] =
  for a in l..h:
    for b in l..h:
      for c in l..h:
        for d in l..h:
          for e in l..h:
            for f in l..h:
              for g in l..h:
                if (not unique or isUnique(a, b, c, d, e, f, g)) and
                   isSolution(a, b, c, d, e, f, g):
                  result &= [a, b, c, d, e, f, g]

proc printFourSquares(l, h: uint8, unique = true) =
  let solutions = fourSquares(l, h, unique)

  if unique:
    for s in solutions:
      echo s

  echo solutions.len, (if unique: " " else: " non-"), "unique solutions in ",
     l, " to ", h, " range\n"

when isMainModule:
  printFourSquares(1, 7)
  printFourSquares(3, 9)
  printFourSquares(0, 9, unique = false)


program square4;
{$MODE DELPHI}
{$R+,O+}
const
  LoDgt = 0;
  HiDgt = 9;
type
  tchkset = set of LoDgt..HiDgt;
  tSol = record
           solMin : integer;
           solDat : array[1..7] of integer;
         end;

var
  sum,a,b,c,d,e,f,g,cnt,uniqueCount : NativeInt;
  sol : array of tSol;

procedure SolOut;
var
  i,j,mn: NativeInt;
Begin
  mn := 0;
  repeat
    writeln(mn:3,' ...',mn+6:3);
    For i := Low(sol) to High(sol) do
      with sol[i] do
        IF solMin = mn then
        Begin
          For j := 1 to 7 do
            write(solDat[j]:3);
          writeln;
        end;
    writeln;
    inc(mn);
  until mn > HiDgt-6;
end;

function CheckUnique:Boolean;
var
  i,sum,mn: NativeInt;
  chkset : tchkset;

Begin
  chkset:= [];
  include(chkset,a);include(chkset,b);include(chkset,c);
  include(chkset,d);include(chkset,e);include(chkset,f);
  include(chkset,g);
  sum := 0;
  For i := LoDgt to HiDgt do
    IF i in chkset then
      inc(sum);

  result := sum = 7;
  IF result then
  begin
    inc(uniqueCount);
    //find the lowest entry
    mn:= LoDgt;
    For i := LoDgt to HiDgt do
      IF i in chkset then
      Begin
        mn := i;
        BREAK;
      end;
    // are they consecutive
    For i := mn+1 to mn+6  do
      IF NOT(i in chkset) then
        EXIT;

    setlength(sol,Length(sol)+1);
    with sol[high(sol)] do
      Begin
        solMin:= mn;
        solDat[1]:= a;solDat[2]:= b;solDat[3]:= c;
        solDat[4]:= d;solDat[5]:= e;solDat[6]:= f;
        solDat[7]:= g;
      end;
  end;
end;

Begin
  cnt := 0;
  uniqueCount := 0;
  For a:= LoDgt to HiDgt do
  Begin
    For b := LoDgt to HiDgt do
    Begin
      sum := a+b;
      //a+b = b+c+d => a = c+d => d := a-c
      For c := a-LoDgt downto LoDgt do
      begin
        d := a-c;
        e := sum-d;
        IF e>HiDgt then
          e:= HiDgt;
        For e := e downto LoDgt do
          begin
          f := sum-e-d;
          IF f in [loDGt..Hidgt]then
          Begin
            g := sum-f;
            IF g in [loDGt..Hidgt]then
            Begin
              inc(cnt);
              CheckUnique;
            end;
          end;
        end;
      end;
    end;
  end;
  SolOut;
  writeln('       solution count for ',loDgt,' to ',HiDgt,' = ',cnt);
  writeln('unique solution count for ',loDgt,' to ',HiDgt,' = ',uniqueCount);
end.


use ntheory qw/forperm/;
use Set::CrossProduct;

sub four_sq_permute {
    my($list) = @_;
    my @solutions;
    forperm {
       @c = @$list[@_];
       push @solutions, [@c] if check(@c);
    } @$list;
    print +@solutions . " unique solutions found using: " . join(', ', @$list) . "\n";
    return @solutions;
}

sub four_sq_cartesian {
    my(@list) = @_;
    my @solutions;
    my $iterator = Set::CrossProduct->new( [(@list) x 7] );
    while( my $c = $iterator->get ) {
       push @solutions, [@$c] if check(@$c);
    }
    print +@solutions . " non-unique solutions found using: " . join(', ', @{@list[0]}) . "\n";
    return @solutions;
}

sub check {
    my(@c) = @_;
    $a = $c[0] + $c[1];
    $b = $c[1] + $c[2] + $c[3];
    $c = $c[3] + $c[4] + $c[5];
    $d = $c[5] + $c[6];
    $a == $b and $a == $c and $a == $d;
}

sub display {
    my(@solutions) = @_;
    my $fmt = "%2s " x 7 . "\n";
    printf $fmt, ('a'..'g');
    printf $fmt, @$_ for @solutions;
    print "\n";
}

display four_sq_permute( [1..7] );
display four_sq_permute( [3..9] );
display four_sq_permute( [8, 9, 11, 12, 17, 18, 20, 21] );
four_sq_cartesian( [0..9] );


-- demo/rosetta/4_rings_or_4_squares_puzzle.exw
with javascript_semantics
integer solutions

procedure check(sequence set, bool show)
    integer {a,b,c,d,e,f,g} = set, ab = a+b
    if ab=b+d+c and ab=d+e+f and ab=f+g then
        solutions += 1
        if show then
            ?set
        end if
    end if
end procedure

procedure foursquares(integer lo, hi, bool uniq, show)
    sequence set = repeat(lo,7)
    solutions = 0
    if uniq then
        for i=1 to 7 do
            set[i] = lo+i-1
        end for
        for i=1 to factorial(7) do
            check(permute(i,set),show)
        end for
    else
        integer done = 0
        while not done do
            check(set,show)
            for i=1 to 7 do
                set[i] += 1
                if set[i]<=hi then exit end if
                if i=7 then
                    done = 1
                    exit
                end if
                set[i] = lo
            end for
        end while
    end if
    printf(1,"%d solutions\n",solutions)
end procedure
foursquares(1,7,uniq:=true,show:=true)
foursquares(3,9,true,true)
foursquares(0,9,false,false)


import cp.

main =>
  puzzle_all(1, 7, true, Sol1),
  foreach(Sol in Sol1) println(Sol) end,
  nl,

  puzzle_all(3, 9, true, Sol2),
  foreach(Sol in Sol2) println(Sol) end,
  nl,

  puzzle_all(0, 9, false, Sol3),
  println(len=Sol3.len),
  nl.

puzzle_all(Min, Max, Distinct, LL) =>
    L = [A,B,C,D,E,F,G],
    L :: Min..Max,
    if Distinct then
      all_different(L)
    else
      true
    end,
    T #= A+B,
    T #= B+C+D,
    T #= D+E+F,
    T #= F+G,
    % Another approach:
    % Sums = $[A+B,B+C+D,D+E+F,F+G],
    % foreach(I in 2..Sums.len) Sums[I] #= Sums[I-1] end,
    LL = solve_all(L).


CREATE TABLE allints (v NUMBER);
CREATE TABLE results
(
a NUMBER,
b NUMBER,
c NUMBER,
d NUMBER,
e NUMBER,
f NUMBER,
g NUMBER
);

CREATE OR REPLACE PROCEDURE foursquares(lo NUMBER,hi NUMBER,uniq BOOLEAN,show BOOLEAN)
AS
    a NUMBER;
    b NUMBER;
    c NUMBER;
    d NUMBER;
    e NUMBER;
    f NUMBER;
    g NUMBER;
    out_line VARCHAR2(2000);

    CURSOR results_cur IS
    SELECT
       a,
       b,
       c,
       d,
       e,
       f,
       g
    FROM
        results
    ORDER BY
        a,b,c,d,e,f,g;

    results_rec results_cur%ROWTYPE;

    solutions NUMBER;
    uorn VARCHAR2(2000);
BEGIN
    solutions := 0;
    DELETE FROM allints;
    DELETE FROM results;
    FOR i IN lo..hi LOOP
        INSERT INTO allints VALUES (i);
    END LOOP;
    COMMIT;

    IF uniq = TRUE THEN
        INSERT INTO results
            SELECT
                a.v a,
                b.v b,
                c.v c,
                d.v d,
                e.v e,
                f.v f,
                g.v g
            FROM
                allints a, allints b, allints c,allints d,
                allints e, allints f, allints g
            WHERE
                a.v NOT IN (b.v,c.v,d.v,e.v,f.v,g.v) AND
                b.v NOT IN (c.v,d.v,e.v,f.v,g.v) AND
                c.v NOT IN (d.v,e.v,f.v,g.v) AND
                d.v NOT IN (e.v,f.v,g.v) AND
                e.v NOT IN (f.v,g.v) AND
                f.v NOT IN (g.v) AND
                a.v = c.v + d.v AND
                g.v = d.v + e.v AND
                b.v = e.v + f.v - c.v
            ORDER BY
                a,b,c,d,e,f,g;
        uorn := ' unique solutions in ';
    ELSE
        INSERT INTO results
            SELECT
                a.v a,
                b.v b,
                c.v c,
                d.v d,
                e.v e,
                f.v f,
                g.v g
            FROM
                allints a, allints b, allints c,allints d,
                allints e, allints f, allints g
            WHERE
                a.v = c.v + d.v AND
                g.v = d.v + e.v AND
                b.v = e.v + f.v - c.v
            ORDER BY
                a,b,c,d,e,f,g;
        uorn := ' non-unique solutions in ';
    END IF;
    COMMIT;

    OPEN results_cur;
    LOOP
        FETCH results_cur INTO results_rec;
        EXIT WHEN results_cur%notfound;
        a := results_rec.a;
        b := results_rec.b;
        c := results_rec.c;
        d := results_rec.d;
        e := results_rec.e;
        f := results_rec.f;
        g := results_rec.g;

        solutions := solutions + 1;
        IF show = TRUE THEN
            out_line := TO_CHAR(a) || ' ';
            out_line := out_line || ' ' || TO_CHAR(b) || ' ';
            out_line := out_line || ' ' || TO_CHAR(c) || ' ';
            out_line := out_line || ' ' || TO_CHAR(d) || ' ';
            out_line := out_line || ' ' || TO_CHAR(e) || ' ';
            out_line := out_line || ' ' || TO_CHAR(f) ||' ';
            out_line := out_line || ' ' || TO_CHAR(g);
        END IF;

        DBMS_OUTPUT.put_line(out_line);
    END LOOP;
    CLOSE results_cur;
    out_line := TO_CHAR(solutions) || uorn;
    out_line := out_line || TO_CHAR(lo) || ' to ' || TO_CHAR(hi);
    DBMS_OUTPUT.put_line(out_line);

END;
/


:- use_module(library(clpfd)).

% main predicate
my_sum(Min, Max, Top, LL):-
    L = [A,B,C,D,E,F,G],
    L ins Min..Max,
    (   Top == 0
    ->  all_distinct(L)
    ;    true),
    R #= A+B,
    R #= B+C+D,
    R #= D+E+F,
    R #= F+G,
    setof(L, labeling([ff], L), LL).

my_sum_1(Min, Max) :-
    my_sum(Min, Max, 0, LL),
    maplist(writeln, LL).

my_sum_2(Min, Max, Len) :-
    my_sum(Min, Max, 1, LL),
    length(LL, Len).


import itertools

def all_equal(a,b,c,d,e,f,g):
    return a+b == b+c+d == d+e+f == f+g

def foursquares(lo,hi,unique,show):
    solutions = 0
    if unique:
        uorn = "unique"
        citer = itertools.combinations(range(lo,hi+1),7)
    else:
        uorn = "non-unique"
        citer =  itertools.combinations_with_replacement(range(lo,hi+1),7)

    for c in citer:
            for p in set(itertools.permutations(c)):
                if all_equal(*p):
                    solutions += 1
                    if show:
                        print str(p)[1:-1]

    print str(solutions)+" "+uorn+" solutions in "+str(lo)+" to "+str(hi)
    print


# 4 rings or 4 squares puzzle

perms <- function (n, r, v = 1:n, repeats.allowed = FALSE) {
  if (repeats.allowed)
    sub <- function(n, r, v) {
      if (r == 1)
        matrix(v, n, 1)
      else if (n == 1)
        matrix(v, 1, r)
      else {
        inner <- Recall(n, r - 1, v)
        cbind(rep(v, rep(nrow(inner), n)), matrix(t(inner),
                                                  ncol = ncol(inner), nrow = nrow(inner) * n,
                                                  byrow = TRUE))
      }
    }
  else sub <- function(n, r, v) {
    if (r == 1)
      matrix(v, n, 1)
    else if (n == 1)
      matrix(v, 1, r)
    else {
      X <- NULL
      for (i in 1:n) X <- rbind(X, cbind(v[i], Recall(n - 1, r - 1, v[-i])))
      X
    }
  }
  X <- sub(n, r, v[1:n])

  result <- vector(mode = "numeric")

  for(i in 1:nrow(X)){
    y <- X[i, ]
    x1 <- y[1] + y[2]
    x2 <- y[2] + y[3] + y[4]
    x3 <- y[4] + y[5] + y[6]
    x4 <- y[6] + y[7]
    if(x1 == x2 & x2 == x3 & x3 == x4) result <- rbind(result, y)
  }
  return(result)
}

print_perms <- function(n, r, v = 1:n, repeats.allowed = FALSE, table.out = FALSE) {
  a <- perms(n, r, v, repeats.allowed)
  colnames(a) <- rep("", ncol(a))
  rownames(a) <- rep("", nrow(a))
  if(!repeats.allowed){
    print(a)
    cat(paste('\n', nrow(a), 'unique solutions from', min(v), 'to', max(v)))
  } else {
    cat(paste('\n', nrow(a), 'non-unique solutions from', min(v), 'to', max(v)))
  }
}

registerS3method("print_perms", "data.frame", print_perms)

print_perms(7, 7, repeats.allowed = FALSE, table.out = TRUE)
print_perms(7, 7, v = 3:9, repeats.allowed = FALSE, table.out = TRUE)
print_perms(10, 7, v = 0:9, repeats.allowed = TRUE, table.out = FALSE)


#lang racket

(define solution? (match-lambda [(list a b c d e f g) (= (+ a b) (+ b c d) (+ d e f) (+ f g))]))

(define (fold-4-rings-or-4-squares-puzzle lo hi kons k0)
  (for*/fold ((k k0))
            ((combination (in-combinations (range lo (add1 hi)) 7))
             (permutation (in-permutations combination))
             #:when (solution? permutation))
            (kons permutation k)))

(fold-4-rings-or-4-squares-puzzle 1 7 cons null)
(fold-4-rings-or-4-squares-puzzle 3 9 cons null)
(fold-4-rings-or-4-squares-puzzle 0 9 (λ (ignored-solution count) (add1 count)) 0)


sub four-squares ( @list, :$unique=1, :$show=1 ) {

    my @solutions;

    for $unique.&combos -> @c {
        @solutions.push: @c if [==]
          @c[0] + @c[1],
          @c[1] + @c[2] + @c[3],
          @c[3] + @c[4] + @c[5],
          @c[5] + @c[6];
    }

    say +@solutions, ($unique ?? ' ' !! ' non-'), "unique solutions found using {join(', ', @list)}.\n";

    my $f = "%{@list.max.chars}s";

    say join "\n", (('a'..'g').fmt: $f), @solutions».fmt($f), "\n" if $show;

    multi combos ( $ where so * ) { @list.combinations(7).map: |*.permutations }

    multi combos ( $ where not * ) { [X] @list xx 7 }
}

# TASK
four-squares( [1..7] );
four-squares( [3..9] );
four-squares( [8, 9, 11, 12, 17, 18, 20, 21] );
four-squares( [0..9], :unique(0), :show(0) );


/*REXX pgm solves the 4-rings puzzle,  where letters represent unique (or not) digits). */
arg LO HI unique show .                          /*the  ARG  statement capitalizes args.*/
if LO=='' | LO==","  then LO=1                   /*Not specified?  Then use the default.*/
if HI=='' | HI==","  then HI=7                   /* "      "         "   "   "     "    */
if unique=='' | unique==',' | unique=='UNIQUE'  then unique=1  /*unique letter solutions*/
                                                else unique=0  /*non-unique        "    */
if   show=='' |   show==',' |   show=='SHOW'    then show=1    /*noshow letter solutions*/
                                                else show=0    /*  show    "       "    */
w=max(3, length(LO), length(HI) )                /*maximum width of any number found.   */
bar=copies('═', w)                               /*define a horizontal bar (for title). */
times=HI - LO + 1                                /*calculate number of times to loop.   */
#=0                                              /*number of solutions found (so far).  */
       do a=LO     for times
          do b=LO  for times
          if unique  then  if b==a  then  iterate
             do c=LO  for times
             if unique  then  do;  if c==a  then  iterate
                                   if c==b  then  iterate
                              end
                do d=LO  for times
                if unique  then  do;  if d==a  then  iterate
                                      if d==b  then  iterate
                                      if d==c  then  iterate
                                 end
                   do e=LO  for times
                   if unique  then  do;  if e==a  then  iterate
                                         if e==b  then  iterate
                                         if e==c  then  iterate
                                         if e==d  then  iterate
                                    end
                      do f=LO  for times
                      if unique  then  do;  if f==a  then  iterate
                                            if f==b  then  iterate
                                            if f==c  then  iterate
                                            if f==d  then  iterate
                                            if f==e  then  iterate
                                       end
                         do g=LO  for times
                         if unique  then  do;  if g==a  then  iterate
                                               if g==b  then  iterate
                                               if g==c  then  iterate
                                               if g==d  then  iterate
                                               if g==e  then  iterate
                                               if g==f  then  iterate
                                          end
                         sum=a+b
                         if   f+g\==sum  then  iterate
                         if b+c+d\==sum  then  iterate
                         if d+e+f\==sum  then  iterate
                         #=# + 1                          /*bump the count of solutions.*/
                         if #==1  then call align  'a',  'b',  'c',  'd',  'e',  'f',  'g'
                         if #==1  then call align  bar,  bar,  bar,  bar,  bar,  bar,  bar
                                       call align   a,    b,    c,    d,    e,    f,    g
                         end   /*g*/
                      end      /*f*/
                   end         /*e*/
                end            /*d*/
             end               /*c*/
          end                  /*b*/
       end                     /*a*/
say
                 _= ' non-unique'
if  unique  then _= ' unique '
say #  _  'solutions found.'
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
align: parse arg a1,a2,a3,a4,a5,a6,a7
       if show  then say left('',9)  center(a1,w) center(a2,w) center(a3,w) center(a4,w),
                                     center(a5,w) center(a6,w) center(a7,w)
       return


def four_squares(low, high, unique=true, show=unique)
  f = -> (a,b,c,d,e,f,g) {[a+b, b+c+d, d+e+f, f+g].uniq.size == 1}
  if unique
    uniq = "unique"
    solutions = [*low..high].permutation(7).select{|ary| f.call(*ary)}
  else
    uniq = "non-unique"
    solutions = [*low..high].repeated_permutation(7).select{|ary| f.call(*ary)}
  end
  if show
    puts " " + [*"a".."g"].join("  ")
    solutions.each{|ary| p ary}
  end
  puts "#{solutions.size} #{uniq} solutions in #{low} to #{high}"
  puts
end

[[1,7], [3,9]].each do |low, high|
  four_squares(low, high)
end
four_squares(0, 9, false)


#![feature(inclusive_range_syntax)]

fn is_unique(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8) -> bool {
    a != b && a != c && a != d && a != e && a != f && a != g &&
    b != c && b != d && b != e && b != f && b != g &&
    c != d && c != e && c != f && c != g &&
    d != e && d != f && d != g &&
    e != f && e != g &&
    f != g
}

fn is_solution(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, g: u8) -> bool {
    a + b == b + c + d &&
        b + c + d == d + e + f &&
        d + e + f == f + g
}

fn four_squares(low: u8, high: u8, unique: bool) -> Vec<Vec<u8>> {
    let mut results: Vec<Vec<u8>> = Vec::new();

    for a in low..=high {
        for b in low..=high {
            for c in low..=high {
                for d in low..=high {
                    for e in low..=high {
                        for f in low..=high {
                            for g in low..=high {
                                if (!unique || is_unique(a, b, c, d, e, f, g)) &&
                                    is_solution(a, b, c, d, e, f, g) {
                                    results.push(vec![a, b, c, d, e, f, g]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    results
}

fn print_results(solutions: &Vec<Vec<u8>>) {
    for solution in solutions {
        println!("{:?}", solution)
    }
}

fn print_results_summary(solutions: usize, low: u8, high: u8, unique: bool) {
    let uniqueness = if unique {
        "unique"
    } else {
        "non-unique"
    };
    println!("{} {} solutions in {} to {} range", solutions, uniqueness, low, high)
}

fn uniques(low: u8, high: u8) {
    let solutions = four_squares(low, high, true);
    print_results(&solutions);
    print_results_summary(solutions.len(), low, high, true);
}

fn nonuniques(low: u8, high: u8) {
    let solutions = four_squares(low, high, false);
    print_results_summary(solutions.len(), low, high, false);
}

fn main() {
    uniques(1, 7);
    println!();
    uniques(3, 9);
    println!();
    nonuniques(0, 9);
}


object FourRings {

  def fourSquare(low: Int, high: Int, unique: Boolean, print: Boolean): Unit = {
    def isValid(needle: Integer, haystack: Integer*) = !unique || !haystack.contains(needle)

    if (print) println("a b c d e f g")

    var count = 0
    for {
      a <- low to high
      b <- low to high if isValid(a, b)
      fp = a + b
      c <- low to high if isValid(c, a, b)
      d <- low to high if isValid(d, a, b, c) && fp == b + c + d
      e <- low to high if isValid(e, a, b, c, d)
      f <- low to high if isValid(f, a, b, c, d, e) && fp == d + e + f
      g <- low to high if isValid(g, a, b, c, d, e, f) && fp == f + g
    } {
      count += 1
      if (print) println(s"$a $b $c $d $e $f $g")
    }

    println(s"There are $count ${if(unique) "unique" else "non-unique"} solutions in [$low, $high]")
  }

  def main(args: Array[String]): Unit = {
    fourSquare(1, 7, unique = true, print = true)
    fourSquare(3, 9, unique = true, print = true)
    fourSquare(0, 9, unique = false, print = false)
  }
}


(import (scheme base)
        (scheme write)
        (srfi 1))

;; return all combinations of size elements from given set
(define (combinations size set unique?)
  (if (zero? size)
    (list '())
    (let loop ((base-combns (combinations (- size 1) set unique?))
               (results '())
               (items set))
      (cond ((null? base-combns) ; end, as no base-combinations to process
             results)
            ((null? items)       ; check next base-combination
             (loop (cdr base-combns)
                   results
                   set))
            ((and unique?        ; ignore if wanting list unique
                  (member (car items) (car base-combns) =))
             (loop base-combns
                   results
                   (cdr items)))
            (else                ; keep the new combination
              (loop base-combns
                    (cons (cons (car items) (car base-combns))
                          results)
                    (cdr items)))))))

;; checks if all 4 sums are the same
(define (solution? a b c d e f g)
  (= (+ a b)
     (+ b c d)
     (+ d e f)
     (+ f g)))

;; Tasks
(display "Solutions: LOW=1 HIGH=7\n")
(display (filter (lambda (combination) (apply solution? combination))
                 (combinations 7 (iota 7 1) #t))) (newline)

(display "Solutions: LOW=3 HIGH=9\n")
(display (filter (lambda (combination) (apply solution? combination))
                 (combinations 7 (iota 7 3) #t))) (newline)

(display "Solution count: LOW=0 HIGH=9 non-unique\n")
(display (count (lambda (combination) (apply solution? combination))
                (combinations 7 (iota 10 0) #f))) (newline)


func four_squares (list, unique=true, show=true) {

    var solutions = []

    func check(c) {
        solutions << c if ([
            c[0] + c[1],
            c[1] + c[2] + c[3],
            c[3] + c[4] + c[5],
            c[5] + c[6],
        ].uniq.len == 1)
    }

    if (unique) {
        list.combinations(7, {|*a|
            a.permutations { |*c|
                check(c)
            }
        })
    } else {
        7.of { list }.cartesian {|*c|
            check(c)
        }
    }

    say (solutions.len,
        (unique ? ' ' : ' non-'),
        "unique solutions found using #{list.join(', ')}.\n")

    if (show) {
        var f = "%#{list.max.len+1}s"
        say ("\n".join(
                ('a'..'g').map{f % _}.join,
                solutions.map{ .map{f % _}.join }...
        ), "\n")
    }
}

# TASK
four_squares(@(1..7))
four_squares(@(3..9))
four_squares([8, 9, 11, 12, 17, 18, 20, 21])
four_squares(@(0..9), unique: false, show: false)


BEGIN

    INTEGER PROCEDURE GETCOMBS(LOW, HIGH, UNIQUE, COMBS);
        INTEGER LOW, HIGH;
        INTEGER ARRAY COMBS;
        BOOLEAN UNIQUE;
    BEGIN
        INTEGER A, B, C, D, E, F, G;
        INTEGER NUM;

        BOOLEAN PROCEDURE ISUNIQUE(A, B, C, D, E, F, G);
            INTEGER A, B, C, D, E, F, G;
        BEGIN
            INTEGER ARRAY DATA(LOW:HIGH);
            INTEGER I;

            FOR I := LOW STEP 1 UNTIL HIGH DO
                DATA(I) := -1;

            FOR I := A, B, C, D, E, F, G DO
              IF DATA(I) = -1
                  THEN DATA(I) := 1
                  ELSE GOTO L;

            ISUNIQUE := TRUE;
        L:
        END;

        PROCEDURE ADDCOMB;
        BEGIN
            NUM := NUM + 1;
            COMBS(NUM, LOW + 0) := A;
            COMBS(NUM, LOW + 1) := B;
            COMBS(NUM, LOW + 2) := C;
            COMBS(NUM, LOW + 3) := D;
            COMBS(NUM, LOW + 4) := E;
            COMBS(NUM, LOW + 5) := F;
            COMBS(NUM, LOW + 6) := G;
        END;

        FOR A := LOW STEP 1 UNTIL HIGH DO
        FOR B := LOW STEP 1 UNTIL HIGH DO
        FOR C := LOW STEP 1 UNTIL HIGH DO
        FOR D := LOW STEP 1 UNTIL HIGH DO
        FOR E := LOW STEP 1 UNTIL HIGH DO
        FOR F := LOW STEP 1 UNTIL HIGH DO
        FOR G := LOW STEP 1 UNTIL HIGH DO
        BEGIN
            IF VALIDCOMB(A, B, C, D, E, F, G) THEN
            BEGIN
                IF UNIQUE THEN
                    BEGIN IF ISUNIQUE(A, B, C, D, E, F, G) THEN ADDCOMB END
                ELSE ADDCOMB;
            END;
        END;
        GETCOMBS := NUM;
    END;

    BOOLEAN PROCEDURE VALIDCOMB(A, B, C, D, E, F, G);
        INTEGER A, B, C, D, E, F, G;
    BEGIN
        INTEGER SQUARE1, SQUARE2, SQUARE3, SQUARE4;

        SQUARE1 := A + B;
        SQUARE2 := B + C + D;
        SQUARE3 := D + E + F;
        SQUARE4 := F + G;
        VALIDCOMB := SQUARE1 = SQUARE2 AND SQUARE2 = SQUARE3 AND SQUARE3 = SQUARE4
    END;

    COMMENT ----- MAIN PROGRAM ----- ;

    INTEGER ARRAY LO(1:3);
    INTEGER ARRAY HI(1:3);
    BOOLEAN ARRAY UQ(1:3);
    INTEGER I;

    LO(1) := 1; HI(1) := 7; UQ(1) := TRUE;
    LO(2) := 3; HI(2) := 9; UQ(2) := TRUE;
    LO(3) := 0; HI(3) := 9; UQ(3) := FALSE;

    FOR I := 1 STEP 1 UNTIL 3 DO
    BEGIN
        INTEGER LOW, HIGH;
        BOOLEAN UNIQ;

        LOW := LO(I); HIGH := HI(I); UNIQ := UQ(I);
        BEGIN
            INTEGER ARRAY VALIDCOMBS(1:8000, LOW:HIGH);
            INTEGER N;

            N := GETCOMBS(LOW, HIGH, UNIQ, VALIDCOMBS);
            OUTINT(N, 0);
            IF UNIQ THEN OUTTEXT(" UNIQUE");
            OUTTEXT(" SOLUTIONS IN ");
            OUTINT(LOW, 0); OUTTEXT(" TO ");
            OUTINT(HIGH, 0);
            OUTIMAGE;
            IF I < 3 THEN
            BEGIN INTEGER I, J;
                FOR I := 1 STEP 1 UNTIL N DO
                BEGIN
                    OUTTEXT("[");
                    FOR J := LOW STEP 1 UNTIL HIGH DO
                        OUTINT(VALIDCOMBS(I, J), 2);
                    OUTTEXT(" ]");
                    OUTIMAGE;
                END;
            END;
        END;
    END;

END.


--#SET TERMINATOR @

SET SERVEROUTPUT ON @

CREATE TABLE ALL_INTS (
  V INTEGER
)@

CREATE TABLE RESULTS (
  A INTEGER,
  B INTEGER,
  C INTEGER,
  D INTEGER,
  E INTEGER,
  F INTEGER,
  G INTEGER
)@

CREATE OR REPLACE PROCEDURE FOUR_SQUARES(
  IN LO INTEGER,
  IN HI INTEGER,
  IN UNIQ SMALLINT,
  --IN UNIQ BOOLEAN,
  IN SHOW SMALLINT)
  --IN SHOW BOOLEAN)
 BEGIN
  DECLARE A INTEGER;
  DECLARE B INTEGER;
  DECLARE C INTEGER;
  DECLARE D INTEGER;
  DECLARE E INTEGER;
  DECLARE F INTEGER;
  DECLARE G INTEGER;
  DECLARE OUT_LINE VARCHAR(2000);
  DECLARE I SMALLINT;

  DECLARE SOLUTIONS INTEGER;
  DECLARE UORN VARCHAR(2000);

  SET SOLUTIONS = 0;
  DELETE FROM ALL_INTS;
  DELETE FROM RESULTS;
  SET I = LO;
  WHILE (I <= HI) DO
   INSERT INTO ALL_INTS VALUES (I);
   SET I = I + 1;
  END WHILE;
  COMMIT;

  -- Computes unique solutions.
  IF (UNIQ = 0) THEN
  --IF (UNIQ = TRUE) THEN
   INSERT INTO RESULTS
     SELECT
      A.V A, B.V B, C.V C, D.V D, E.V E, F.V F, G.V G
     FROM
      ALL_INTS A, ALL_INTS B, ALL_INTS C, ALL_INTS D, ALL_INTS E, ALL_INTS F,
      ALL_INTS G
     WHERE
          A.V NOT IN (B.V, C.V, D.V, E.V, F.V, G.V)
      AND B.V NOT IN (C.V, D.V, E.V, F.V, G.V)
      AND C.V NOT IN (D.V, E.V, F.V, G.V)
      AND D.V NOT IN (E.V, F.V, G.V)
      AND E.V NOT IN (F.V, G.V)
      AND F.V NOT IN (G.V)
      AND A.V = C.V + D.V
      AND G.V = D.V + E.V
      AND B.V = E.V + F.V - C.V
     ORDER BY
      A, B, C, D, E, F, G;
   SET UORN = ' unique solutions in ';
  ELSE
   -- Compute non-unique solutions.
   INSERT INTO RESULTS
     SELECT
      A.V A, B.V B, C.V C, D.V D, E.V E, F.V F, G.V G
     FROM
      ALL_INTS A, ALL_INTS B, ALL_INTS C, ALL_INTS D, ALL_INTS E, ALL_INTS F,
      ALL_INTS G
     WHERE
          A.V = C.V + D.V
      AND G.V = D.V + E.V
      AND B.V = E.V + F.V - C.V
     ORDER BY
      A, B, C, D, E, F, G;
   SET UORN = ' non-unique solutions in ';
  END IF;
  COMMIT;

  -- Counts the possible solutions.
  FOR v AS c CURSOR FOR
    SELECT
     A, B, C, D, E, F, G
    FROM RESULTS
    ORDER BY
     A, B, C, D, E, F, G
    DO
   SET SOLUTIONS = SOLUTIONS + 1;
   -- Shows the results.
   IF (SHOW = 0) THEN
   --IF (SHOW = TRUE) THEN
    SET OUT_LINE = A || ' ' || B || ' ' || C || ' ' || D || ' ' || E || ' '
      || F ||' ' || G;
    CALL DBMS_OUTPUT.PUT_LINE(OUT_LINE);
   END IF;
  END FOR;

  SET OUT_LINE = SOLUTIONS || UORN || LO || ' to ' || HI;
  CALL DBMS_OUTPUT.PUT_LINE(OUT_LINE);
 END
@

CALL FOUR_SQUARES(1, 7, 0, 0)@
CALL FOUR_SQUARES(3, 9, 0, 0)@
CALL FOUR_SQUARES(0, 9, 1, 1)@


set vars {a b c d e f g}
set exprs {
    {$a+$b}
    {$b+$c+$d}
    {$d+$e+$f}
    {$f+$g}
}

proc permute {xs} {
    if {[llength $xs] < 2} {
        return $xs
    }
    set i -1
    foreach x $xs {
        incr i
        set rest [lreplace $xs $i $i]
        foreach rest [permute $rest] {
            lappend res [list $x {*}$rest]
        }
    }
    return $res
}

proc range {a b} {
    set a [uplevel 1 [list expr $a]]
    set b [uplevel 1 [list expr $b]]
    set res {}
    while {$a <= $b} {
        lappend res $a
        incr a
    }
    return $res
}

proc compile_4rings {vars exprs} {
    set script "set _ \[[list expr [lindex $exprs 0]]\]\n"
    foreach expr [lrange $exprs 1 end] {
        append script "if {\$_ != $expr} {return false}\n"
    }
    append script "return true\n"
    list $vars $script
}

proc solve_4rings {vars exprs range} {
    set lambda [compile_4rings $vars $exprs]
    foreach values [permute $range] {
        if {[apply $lambda {*}$values]} {
            puts " $values"
        }
    }
}

proc compile_4rings_hard {vars exprs values} {
    append script "set _ \[[list expr [lindex $exprs 0]]\]\n"
    foreach expr [lrange $exprs 1 end] {
        append script "if {\$_ != $expr} {continue}\n"
    }
    append script "incr res\n"
    foreach var $vars {
        set script [list foreach $var $values $script]
    }
    set script "set res 0\n$script\nreturn \$res"
    list {} $script
}

proc solve_4rings_hard {vars exprs range} {
    apply [compile_4rings_hard $vars $exprs $range]
}

puts "# Combinations of 1..7:"
solve_4rings $vars $exprs [range 1 7]
puts "# Combinations of 3..9:"
solve_4rings $vars $exprs [range 3 9]
puts "# Number of solutions, free over 0..9:"
puts [solve_4rings_hard $vars $exprs [range 0 9]]


Dim a As Integer, b As Integer, c As Integer, d As Integer
Dim e As Integer, f As Integer, g As Integer
Dim lo As Integer, hi As Integer, unique As Boolean, show As Boolean
Dim solutions As Integer
Private Sub bf()
    For f = lo To hi
        If ((Not unique) Or _
            ((f <> a And f <> c And f <> d And f <> g And f <> e))) Then
            b = e + f - c
            If ((b >= lo) And (b <= hi) And _
                ((Not unique) Or ((b <> a) And (b <> c) And _
                (b <> d) And (b <> g) And (b <> e) And (b <> f)))) Then
                solutions = solutions + 1
                If show Then Debug.Print a; b; c; d; e; f; g
            End If
        End If
    Next
End Sub
Private Sub ge()
    For e = lo To hi
        If ((Not unique) Or ((e <> a) And (e <> c) And (e <> d))) Then
            g = d + e
            If ((g >= lo) And (g <= hi) And _
                ((Not unique) Or ((g <> a) And (g <> c) And _
                (g <> d) And (g <> e)))) Then
                bf
            End If
        End If
    Next
End Sub
Private Sub acd()
    For c = lo To hi
        For d = lo To hi
            If ((Not unique) Or (c <> d)) Then
                a = c + d
                If ((a >= lo) And (a <= hi) And _
                    ((Not unique) Or ((c <> 0) And (d <> 0)))) Then
                    ge
                End If
            End If
        Next d
    Next c
End Sub
Private Sub foursquares(plo As Integer, phi As Integer, punique As Boolean, pshow As Boolean)
    lo = plo
    hi = phi
    unique = punique
    show = pshow
    solutions = 0
    acd
    Debug.Print
    If unique Then
        Debug.Print solutions; " unique solutions in"; lo; "to"; hi
    Else
        Debug.Print solutions; " non-unique solutions in"; lo; "to"; hi
    End If
End Sub
Public Sub program()
    Call foursquares(1, 7, True, True)
    Debug.Print
    Call foursquares(3, 9, True, True)
    Call foursquares(0, 9, False, False)
End Sub


Module Module1

    Dim CA As Char() = "0123456789ABC".ToCharArray()

    Sub FourSquare(lo As Integer, hi As Integer, uni As Boolean, sy As Char())
        If sy IsNot Nothing Then Console.WriteLine("a b c d e f g" & vbLf & "-------------")
        Dim r = Enumerable.Range(lo, hi - lo + 1).ToList(), u As New List(Of Integer),
            t As Integer, cn As Integer = 0
        For Each a In r
            u.Add(a)
            For Each b In r
                If uni AndAlso u.Contains(b) Then Continue For
                u.Add(b)
                t = a + b
                For Each c In r : If uni AndAlso u.Contains(c) Then Continue For
                    u.Add(c)
                    For d = a - c To a - c
                        If d < lo OrElse d > hi OrElse uni AndAlso u.Contains(d) OrElse
                            t <> b + c + d Then Continue For
                        u.Add(d)
                        For Each e In r
                            If uni AndAlso u.Contains(e) Then Continue For
                            u.Add(e)
                            For f = b + c - e To b + c - e
                                If f < lo OrElse f > hi OrElse uni AndAlso u.Contains(f) OrElse
                                    t <> d + e + f Then Continue For
                                u.Add(f)
                                For g = t - f To t - f : If g < lo OrElse g > hi OrElse
                                    uni AndAlso u.Contains(g) Then Continue For
                                    cn += 1 : If sy IsNot Nothing Then _
                                        Console.WriteLine("{0} {1} {2} {3} {4} {5} {6}",
                                            sy(a), sy(b), sy(c), sy(d), sy(e), sy(f), sy(g))
                                Next : u.Remove(f) : Next : u.Remove(e) : Next : u.Remove(d)
                    Next : u.Remove(c) : Next : u.Remove(b) : Next : u.Remove(a)
        Next : Console.WriteLine("{0} {1}unique solutions for [{2},{3}]{4}",
                                 cn, If(uni, "", "non-"), lo, hi, vbLf)
    End Sub

    Sub main()
        fourSquare(1, 7, True, CA)
        fourSquare(3, 9, True, CA)
        fourSquare(0, 9, False, Nothing)
        fourSquare(5, 12, True, CA)
    End Sub

End Module


fn main(){
	mut n, mut c := get_combs(1,7,true)
	println("$n unique solutions in 1 to 7")
	println(c)
	n, c = get_combs(3,9,true)
	println("$n unique solutions in 3 to 9")
	println(c)
	n, _ = get_combs(0,9,false)
	println("$n non-unique solutions in 0 to 9")
}

fn get_combs(low int,high int,unique bool) (int, [][]int) {
    mut num := 0
    mut valid_combs := [][]int{}
	for a := low; a <= high; a++ {
		for b := low; b <= high; b++ {
			for c := low; c <= high; c++ {
				for d := low; d <= high; d++ {
					for e := low; e <= high; e++ {
						for f := low; f <= high; f++ {
							for g := low; g <= high; g++ {
								if valid_comb(a,b,c,d,e,f,g) {
									if !unique || is_unique(a,b,c,d,e,f,g) {
										num++
										valid_combs << [a,b,c,d,e,f,g]
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return num, valid_combs
}
fn is_unique(a int,b int,c int,d int,e int,f int,g int) bool {
	mut data := map[int]int{}
	data[a]++
	data[b]++
	data[c]++
	data[d]++
	data[e]++
	data[f]++
	data[g]++
	return data.len == 7
}
fn valid_comb(a int,b int,c int,d int,e int,f int,g int) bool {
	square1 := a + b
	square2 := b + c + d
	square3 := d + e + f
	square4 := f + g
	return square1 == square2 && square2 == square3 && square3 == square4
}


import "/fmt" for Fmt

var a = 0
var b = 0
var c = 0
var d = 0
var e = 0
var f = 0
var g = 0

var lo
var hi
var unique
var show
var solutions

var bf = Fn.new {
    f = lo
    while (f <= hi) {
        if (!unique || (f != a && f != c && f != d && f != e && f != g)) {
            b = e + f - c
            if (b >= lo && b <= hi &&
               (!unique || (b != a && b != c && b != d && b != e && b != f && b != g))) {
                    solutions = solutions + 1
                    if (show) Fmt.lprint("$d $d $d $d $d $d $d", [a, b, c, d, e, f, g])
            }
        }
        f = f + 1
    }
}

var ge = Fn.new {
    e = lo
    while (e <= hi) {
        if (!unique || (e != a && e != c && e != d)) {
            g = d + e
            if (g >= lo && g <= hi &&
                (!unique || (g != a && g != c && g != d && g != e))) bf.call()
        }
        e = e + 1
    }
}

var acd = Fn.new {
    c = lo
    while (c <= hi) {
        d = lo
        while (d <= hi) {
            if (!unique || c != d) {
                a = c + d
                if (a >= lo && a <= hi && (!unique || (c != 0 && d != 0))) ge.call()
            }
            d = d + 1
        }
        c = c + 1
    }
}

var foursquares = Fn.new { |plo, phi, punique, pshow|
    lo = plo
    hi = phi
    unique = punique
    show = pshow
    solutions = 0
    if (show) {
        System.print("\na b c d e f g")
        System.print("-------------")
    }
    acd.call()
    if (unique) {
        Fmt.print("\n$d unique solutions in $d to $d", solutions, lo, hi)
    } else {
        Fmt.print("\n$d non-unique solutions in $d to $d\n", solutions, lo, hi)
    }
}

foursquares.call(1, 7, true, true)
foursquares.call(3, 9, true, true)
foursquares.call(0, 9, false, false)


int  Show, Low, High, Digit(7\a..g\), Count;
proc Rings(Level);
int  Level; \of recursion
int  D, Temp, I, Set;
[for D:= Low to High do
    [Digit(Level):= D;
    if Level < 7-1 then Rings(Level+1)
    else [  Temp:= Digit(0) + Digit(1); \solution?
         if Temp = Digit(1) + Digit(2) + Digit(3) and
            Temp = Digit(3) + Digit(4) + Digit(5) and
            Temp = Digit(5) + Digit(6) then
                [Count:= Count+1;
                if Show then
                    [Set:= 0;           \digits must be unique
                    for I:= 0 to 7-1 do
                        Set:= Set ! 1<<Digit(I);
                    if Set = %111_1111 << Low then
                        [for I:= 0 to 7-1 do
                            [IntOut(0, Digit(I));  ChOut(0, ^ )];
                        CrLf(0);
                        ];
                    ];
                ];
         ];
    ];
];

[Show:= true;
Low:= 1;  High:= 7;
Rings(0);
CrLf(0);
Low:= 3;  High:= 9;
Rings(0);
CrLf(0);
Show:= false;
Low:= 0;  High:= 9;  Count:= 0;
Rings(0);
IntOut(0, Count);
CrLf(0);
]


fourSquare(1,7,true,true)
fourSquare(3,9,true,true)
fourSquare(0,9,false,false)

sub fourSquare(low, high, unique, prin)
    local count, a, b, c, d, e, f, g, fp

    if (prin) print "a b c d e f g"

    for a = low to high
        for b = low to high
            if (not valid(unique, a, b)) continue

            fp = a+b
            for c = low to high
                if (not valid(unique, c, a, b)) continue
                for d = low to high
                    if (not valid(unique, d, a, b, c)) continue
                    if (fp <> b+c+d) continue

                    for e = low to high
                        if (not valid(unique, e, a, b, c, d)) continue
                        for f = low to high
                            if (not valid(unique, f, a, b, c, d, e)) continue
                            if (fp <> d+e+f) continue

                            for g = low to high
                                if (not valid(unique, g, a, b, c, d, e, f)) continue
                                if (fp <> f+g) continue

                                count = count + 1
                                if (prin) print a," ",b," ",c," ",d," ",e," ",f," ",g
                            next
                        next
                    next
                next
            next
        next
    next
    if (unique) then
        print "There are ", count, " unique solutions in [",low,",",high,"]"
    else
        print "There are ", count, " non-unique solutions in [",low,",",high,"]"
    end if
end sub

sub valid(unique, needle, n1, n2, n3, n4, n5, n6)
    local i

    if (unique) then
        for i = 1 to numparams - 2
            switch i
                case 1: if needle = n1 return false : break
                case 2: if needle = n2 return false : break
                case 3: if needle = n3 return false : break
                case 4: if needle = n4 return false : break
                case 5: if needle = n5 return false : break
                case 6: if needle = n6 return false : break
            end switch
        next
    end if
    return true
end sub


    // unique: No repeated numbers in solution
fcn fourSquaresPuzzle(lo=1,hi=7,unique=True){  //-->list of solutions
   _assert_(0<=lo and hi<36);
   notUnic:=fcn(a,b,c,etc){ abc:=vm.arglist; // use base 36, any repeated character?
      abc.apply("toString",36).concat().unique().len()!=abc.len()
   };
   s:=List();		// solutions
   foreach a,b,c in ([lo..hi],[lo..hi],[lo..hi]){ // chunk to reduce unique
      if(unique and notUnic(a,b,c)) continue;     // solution space. Slow VM
      foreach d,e in ([lo..hi],[lo..hi]){	  // -->for d { for e {} }
         if(unique and notUnic(a,b,c,d,e)) continue;
	 foreach f,g in ([lo..hi],[lo..hi]){
	    if(unique and notUnic(a,b,c,d,e,f,g)) continue;
	    sqr1,sqr2,sqr3,sqr4 := a+b,b+c+d,d+e+f,f+g;
	    if((sqr1==sqr2==sqr3) and sqr1==sqr4) s.append(T(a,b,c,d,e,f,g));
	 }
      }
   }
   s
}


[Char = ((Float, Float) -> Float)] op
op[Char(‘+’)] = (x, y) -> x + y
op[Char(‘-’)] = (x, y) -> x - y
op[Char(‘*’)] = (x, y) -> x * y
op[Char(‘/’)] = (x, y) -> I y != 0 {x / y} E 9999999

F almost_equal(a, b)
   R abs(a - b) <= 1e-5

F solve(nums)
   V syms = ‘+-*/’
   V sorted_nums = sorted(nums).map(Float)
   L(x, y, z) cart_product(syms, syms, syms)
      V n = copy(sorted_nums)
      L
         V (a, b, c, d) = (n[0], n[1], n[2], n[3])
         I almost_equal(:op[x](:op[y](a, b), :op[z](c, d)), 24.0)
            R ‘(’a‘ ’y‘ ’b‘) ’x‘ (’c‘ ’z‘ ’d‘)’
         I almost_equal(:op[x](a, :op[y](b, :op[z](c, d))), 24.0)
            R a‘ ’x‘ (’b‘ ’y‘ (’c‘ ’z‘ ’d‘))’
         I almost_equal(:op[x](:op[y](:op[z](c, d), b), a), 24.0)
            R ‘((’c‘ ’z‘ ’d‘) ’y‘ ’b‘) ’x‘ ’a
         I almost_equal(:op[x](:op[y](b, :op[z](c, d)), a), 24.0)
            R ‘(’b‘ ’y‘ (’c‘ ’z‘ ’d‘)) ’x‘’a
         I !n.next_permutation()
            L.break
   R ‘not found’

L(nums) [[9, 4, 4, 5],
         [1, 7, 2, 7],
         [5, 7, 5, 4],
         [1, 4, 6, 6],
         [2, 3, 7, 3],
         [8, 7, 9, 7],
         [1, 6, 2, 6],
         [7, 9, 4, 1],
         [6, 4, 2, 2],
         [5, 7, 9, 7],
         [3, 3, 8, 8]]
   print(‘solve(’nums‘) -> ’solve(nums))