#!/usr/bin/ruby

var arr_test = [["x", "y", "z"]];

arr_test[0][1]->say;
arr_test[0][-1]->say;

arr_test[1] = "x";
arr_test->to_s->say;

arr_test[0][0,2]->to_s->say;

var ref_slice = [arr_test[0,1,2]];
ref_slice[0,1,2,3] = ("hu","hi","hei","no");

ref_slice.to_s.say;
arr_test->to_s.say;

arr_test->len->to_s->say;

["zzzz","ioana"][1]->say;
[[["zzz","trizen","zzz"]]][0][0][1]->say;

#
## Test `nil` return-values
#

var a = [4, 8, 10, 12]
var r = [a.first_by { .is_odd }, a.last_by { .is_odd }]

assert_eq(r.len, 2)
assert_eq(r, [nil, nil])

#
## Test `map_2d` and `grep_2d`
#

assert_eq(
    Matrix([1,2,3],[4,5,6]).map_2d{ |*a| a.map { _**2 } },
    Matrix([1, 4, 9], [16, 25, 36])
)

assert_eq([[1,2], [3,4], [5,6]].map_2d {|a,b| a+b }, [3, 7, 11])
assert_eq([[1,2], [3,4], [5,6]].map_2d {|a,b| [a**2, b**2] }, [[1,4], [9,16], [25, 36]])

assert_eq([[1,2], [3,4], [5,6]].grep_2d{|a,b| a+b == 7 }, [[3,4]])
assert_eq([[1,2], [3,4], [5,6]].grep_2d{|a,b| a+b <= 7 }, [[1,2], [3,4]])

do {
    var a = %w(a b c d e f)

    assert(a.contains('a'))
    assert(a.contains('a', 'b'))
    assert(a.contains('b'))
    assert(a.contains('b', 'c'))
    assert(a.contains('c'))
    assert(a.contains('b', 'c', 'd'))
    assert(a.contains('b', 'c', 'd', 'e'))
    assert(a.contains('b', 'c', 'd', 'e', 'f'))
    assert(a.contains('e', 'f'))
    assert(a.contains('f'))

    assert(!a.contains('b', 'd'))
    assert(!a.contains('b', 'd', 'e', 'f'))
    assert(!a.contains('a', 'c'))
    assert(!a.contains('d', 'f'))

    assert(['a',nil,'c'].contains(nil, 'c'))
    assert(['a','b',nil].contains('a','b', nil))
    assert(['a','b',nil].contains('b', nil))
    assert(['a','b',nil].contains(nil))

    assert(!['a',nil,'c'].contains(nil, 'd'))
    assert(!['a','b',nil].contains('a', 'b', nil, 'c'))
    assert(!['a','b',nil].contains('b', nil, 'c'))
    assert(!['a','b',nil].contains(nil, 'c'))
    assert(!['a','b',nil].contains('b', nil, nil, nil))

    assert(!a.contains('e', 'f', 'g'))
    assert(!a.contains('e', 'f', nil))
}

assert_eq(20.of{2**_}.solve_rec_seq, [2])
assert_eq(20.of{3**_}.solve_rec_seq, [3])
assert_eq(20.of{2**_ + 3**_}.solve_rec_seq, [5, -6])
assert_eq(20.of{2**_ + 3**_ + 5**_}.solve_rec_seq, [10, -31, 30])

assert_eq(20.of{_}.solve_rec_seq, [2, -1])
assert_eq(20.of{.fib}.solve_rec_seq, [1, 1])
assert_eq(20.of{.lucas}.solve_rec_seq, [1, 1])

assert_eq(10.of{.fib(3)}.solve_rec_seq, [1, 1, 1])
assert_eq(20.of{.fib(3)}.solve_rec_seq, [1, 1, 1])
assert_eq(10.of{.fib(4)}.solve_rec_seq, [1, 1, 1, 1])
assert_eq(20.of{.fib(4)}.solve_rec_seq, [1, 1, 1, 1])
assert_eq(20.of{.fib(5)}.solve_rec_seq, [1, 1, 1, 1, 1])
assert_eq(20.of{.fib(6)}.solve_rec_seq, [1, 1, 1, 1, 1, 1])

assert_eq(20.of{.faulhaber(1)}.solve_rec_seq, [3, -3, 1])
assert_eq(20.of{.faulhaber(2)}.solve_rec_seq, [4, -6, 4, -1])
assert_eq(20.of{.faulhaber(3)}.solve_rec_seq, [5, -10, 10, -5, 1])

assert_eq(30.of{ .fib * .dec.fib**2 }.solve_rec_seq, [3, 6, -3, -1])
assert_eq(find_linear_recurrence(%n[1,2,3,4,30,140,661,3128]), [4,3,2,1])
assert_eq(20.of{.factorial}.solve_rec_seq, %n[100, -4050, 86400, -1058400, 7620480, -31752000, 72576000, -81648000, 36288000, -3628800])

assert_eq(
    find_linear_recurrence(%n[1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, -1, 1, 1, 1, 1, 1, 2, -1, -3, 1, 1, 1, 1, 2, 5, -3, -7, 1, 1, 1, 0, 5, 13, -7, -15, 1, 1, 0, -5, 13, 33, -15, -31, 1, 2, -5, -23, 33, 81, -31, -63, 2, 9, -23, -79, 81, 193, -63, -128, 9, 41, -79, -239, 193, 449, -128, -265, 41, 161, -239]),
    %n[0,-1,0,-1,0,-1,0,1,0,1,0,1],
)

assert_eq(
    77.sqrt.convergents(25).map{.nu}.solve_rec_seq,
    %n[0, 0, 0, 0, 0, 702, 0, 0, 0, 0, 0, -1],
)

assert([false].all -> not)
assert([false, false].all -> not)
assert([true].all)
assert([true, true].all)
assert([].all)
assert([true, false].all -> not)
assert([false, true].all -> not)

assert([true].any)
assert([true, false].any)
assert([false, true].any)
assert([false].any -> not)
assert([false, false].any -> not)
assert([].any -> not)

assert([false, true].none -> not)
assert([true, false].none -> not)
assert([true].none -> not)
assert([false].none)
assert([false, false].none)
assert([].none)

# Tests for Array .slice(i,j) method.

for k in (0..100) {

    var arr = k.of { urand(65, 65+25).chr }

    for i,j in ([2.of { arr.len.sqr.urand }, 2.of { arr.len.urand }]) {

        var str = arr.join

        assert_eq(arr.slice( i).join, str.substr( i), [str,  i])
        assert_eq(arr.slice(-i).join, str.substr(-i), [str, -i])

        assert_eq(arr.slice( i, j).join, str.substr( i, j), [str,  i,  j])
        assert_eq(arr.slice( i,-j).join, str.substr( i,-j), [str,  i, -j])
        assert_eq(arr.slice(-i,-j).join, str.substr(-i,-j), [str, -i, -j])
        assert_eq(arr.slice(-i, j).join, str.substr(-i, j), [str, -i,  j])

        assert_eq(arr.ft(i,j), [arr[i..j]].grep{defined(_)})
        assert_eq(arr.ft(j,i), [arr[j..i]].grep{defined(_)})

        if (j > 0) {
            assert_eq(arr.ft(i,-j), [arr[i .. arr.len-j]].grep{defined(_)})
        }
    }
}

assert_eq(["C", "S", "D"].ft, ["C", "S", "D"])
assert_eq(["C", "S", "D"].slice, ["C", "S", "D"])

assert_eq("CWS".chars.slice(-1), ["S"])
assert_eq("CWS".chars.slice(-2), ["W","S"])
assert_eq("CWS".chars.slice(-3), ["C","W","S"])
assert_eq("CWS".chars.slice(-4), ["C","W","S"])
assert_eq("CWS".chars.slice(-5), ["C","W","S"])
assert_eq("CWS".chars.slice(-6), ["C","W","S"])
assert_eq("CWS".chars.slice(-7), ["C","W","S"])

assert_eq("CWS".chars.slice(-4, 2), ["C"])  # weird, but consistent with string.subtr()
assert_eq("CWS".substr(-4, 2), "C")

assert_eq(["C", "S"].ft(1,1), ["S"])
assert_eq(["C", "S"].ft(1,0), [])

assert_eq(["C", "S", "D"].ft(0), ["C", "S", "D"])
assert_eq(["C", "S", "D"].ft(1), ["S", "D"])
assert_eq(["C", "S", "D"].ft(2), ["D"])
assert_eq(["C", "S", "D"].ft(3), [])

assert_eq(["C", "S", "D"].ft(-1), ["D"])
assert_eq(["C", "S", "D"].ft(-2), ["S", "D"])
assert_eq(["C", "S", "D"].ft(-3), ["C", "S", "D"])
assert_eq(["C", "S", "D"].ft(-4), ["C", "S", "D"])

assert_eq(["C", "S", "D"].ft(-1,1), [])
assert_eq(["C", "S", "D"].ft(-1,2), ["D"])

assert_eq(["C", "S", "D"].ft(-2,0), [])
assert_eq(["C", "S", "D"].ft(-2,1), ["S"])
assert_eq(["C", "S", "D"].ft(-2,2), ["S","D"])

assert_eq(%w(a b c).ft(-2, -1), ["b", "c"])
assert_eq(%w(a b c).ft(-2, -2), ["b"])

say "** Test passed!"
