/**
 *  Lösningsförslag till tentamen 2016-10-27
 */


    // --------- 1 --------------
    //   a) Se slides
    //   b) Se slides


    // --------- 2 --------------

    void scope() {
        {
            int x = 0;           // 1
            if (x == 4) {
              //  int x = 0;       // 2     Fel: x redan deklarerad i synlighetsområdet.
                int y = 0;       // 3
                out.println(x);  // 4
                out.println(y);  // 5
            }
           // int x = 0;      // 6    Fel: x redan deklarerad i synlighetsområdet.
            int y = 0;      // 7      Ok: y i blocket (if-satsen) inte synligt här
            out.println(x); // 8
            out.println(y); // 9
        }
        //out.println(x);     // 10    Fel: x inte synlig
    }


    // ----- 3 ----------

    int[] splitEven(int[] arr) {
        int nEven = countEven(arr);
        int[] result = new int[nEven];
        int j = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] % 2 == 0) {
                result[j] = arr[i];
                j++;
            }
        }
        return result;
    }

    int countEven(int[] arr) {
        int even = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] % 2 == 0) {
                even++;
            }
        }
        return even;
    }

    // --------- 4 -------------------
    // Utskriften blir: 1 2 3  (se länk till bild för bild).

    // --------- 5 -------------------

    void transpose(int[][] arr) {
        int[][] tmp = new int[arr.length][arr.length];
        for (int row = 0; row < arr.length; row++) {
            for (int col = 0; col < arr[row].length; col++) {
                tmp[col][row] = arr[row][col];
            }
        }
        for (int row = 0; row < arr.length; row++) {
            for (int col = 0; col < arr[row].length; col++) {
                arr[row][col] = tmp[row][col];
            }
        }
    }

    // Alt. solution
    void transpose2(int[][] arr) {
        for (int row = 0; row < arr.length; row++) {
            for (int col = row + 1; col < arr[row].length; col++) {
                int tmp = arr[row][col];
                arr[row][col] = arr[col][row];
                arr[col][row] = tmp;
            }
        }

    }


    // -------- 6 ---------

    class Vector2D {
        private final double i;
        private final double j;

        public Vector2D() {
            i = 0;
            j = 0;
        }

        public Vector2D(double i, double j) {
            this.i = i;
            this.j = j;
        }

        public Vector2D(Vector2D other) {
            i = other.i;
            j = other.j;
        }

        public Vector2D add(Vector2D other) {
            return new Vector2D(this.i + other.i, this.j + other.j);
        }

        public double length() {
            return sqrt(i * i + j * j);
        }

        public boolean equals(Vector2D other) {
            return i == other.i && j == other.j;
        }

    }

    // -------- 7 ---------
    public boolean isAnagram(String word, String anagram) {
        if (word.length() != anagram.length()) {
            return false;
        }
        char[] chars = word.toCharArray();
        for (char c : chars) {
            int index = anagram.indexOf(c);
            if (index != -1) {
                anagram = anagram.substring(0, index) + anagram.substring(index + 1, anagram.length());
            } else {
                return false;
            }
        }
        return anagram.isEmpty();
    }


    // ------- 8 -----------

    void statics() {
        //A.a = A.b;              // 1    Fel: b instansvariabel måste ha ett objekt. A är en klass
        A.a = (new A()).b;        // 2
        //A.b = A.a;              // 3    Fel: Samma som 1
        (new A()).b = A.a;        // 4
        (new A()).a = (new A()).b;  // 5
        (new A()).b = (new A()).a;  // 6
        //A a = A.doIt();         // 7      Fel: doIt är instansmetod. Måste ha objekt. A är klass.
        //out.println(a.a);       // 8
    }

    static class A {
        static int a;
        int b;

        int doIt() {            // 9
            return a;           // 10
        }

        static int doOther() {  // 11
            //return b;           // 12     // Fel: Klassmetod kan inte använda instansvariabel.
        }
    }


    // ---------- 9 -------------------
    public interface Func {

        public int compute(int n);

    }

    public class MemoFunc implements Func {

        private final int MAX = 100;

        private Func f;
        private int[] inputs = new int[MAX];
        private int[] results = new int[MAX];
        private int total = 0; // alltid <= MAX
        private int index = 0; // alltid < MAX

        public MemoFunc(Func f) {
            this.f = f;
        }

        public int compute(int n) {
            for (int k = 0; k < total; k++) {
                if (inputs[k] == n) {
                    return results[k];
                }
            }
            int res = f.compute(n);
            if (total < MAX) {
                total = total + 1;
            }
            index = (index + 1) % MAX;
            inputs[index] = n;
            results[index] = res;
            return res;
        }
    }

    // -------  10 ----------------------
    // a) Immutable, se slides.
    // Både push och pop (de som kan förändra stacken, top läser bara av) ger nya stackar
    // d.v.s. stacken muteras inte man får nya stackar istället.

    //b)
    public class IntStack {

        private int curr;
        private IntStack next = null;

        public IntStack() {
        }

        public IntStack push(int i) {
            IntStack s = new IntStack();
            s.curr = i;
            s.next = this;
            return s;
        }

        public int top() {
            if (next == null) throw new IllegalArgumentException();
            return curr;
        }

        public IntStack pop() {
            top(); // throws exception if this is empty
            return next;
        }

    }

}