text:
<repo_name>niwtr/SudoCool<file_sep>/SudoCool/src/team/sudocool/ImgWorks/Recognizer.java
package team.sudocool.ImgWorks;

import org.opencv.core.*;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
import team.sudocool.Identifier.Identifier;
import team.sudocool.ImgWorks.nImgProc.Utils;
import team.sudocool.Solver.Solver;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.opencv.core.Core.FONT_HERSHEY_COMPLEX;
import static org.opencv.imgproc.Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C;
import static org.opencv.imgproc.Imgproc.THRESH_BINARY;
import static org.opencv.imgproc.Imgproc.approxPolyDP;

/**
 * Created by Heranort on 16/11/19.
 */

//cowsay: write func "set sudoku size"
public class Recognizer {

    //background color of sudoku.

    public static final int WHITE_BACKGROUND=Patternizor.WHITE_BACKGROUND;
    public static final int BLACK_BACKGROUND=Patternizor.BLACK_BACKGROUND;
    public static final int STANDARD_OUTERBOUND_SIZEX=450;
    public static final int STANDARD_OUTERBOUND_SIZEY=450;
    public static final int STANDARD_SCISSOR_SIZE=5;//old: three
    public static final int STANDARD_SUDOKU_SIZE=9;

    private Patternizor           P;
    private Identifier            I;
    private Solver                S;
    private EzGridSquareExtractor E;
    private Mat Img;
    private Mat ThresholdImg;
    private MatOfPoint Bound;

    private boolean isSolved=false;
    private List<Integer> RecognizedNumbers;
    private int[][] ArrangedNumbers;
    private int[][][] RecognizedNumbersHistory;
    private int[][] SolvedNumbers;
    private int[][] __empty;//all -1 arr.
    private boolean firstRush=true;//有时候相机刚启动的时候会导致神奇的现象发生——导致一个神奇的正方形被捕捉到。
    //所以我们需要把第一次采样的结果扔掉。

    public Recognizer(){

        P=new Patternizor(7, Patternizor.WHITE_BACKGROUND);//default is white background.
        I=new Identifier();
        E=new EzGridSquareExtractor(STANDARD_SUDOKU_SIZE, STANDARD_OUTERBOUND_SIZEX,
                STANDARD_OUTERBOUND_SIZEY, STANDARD_SCISSOR_SIZE);
        S=new Solver();

        this.RecognizedNumbersHistory=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE][E.SUDOKU_SIZE];

        this.Bound=new MatOfPoint();

        this.__empty=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        for(int i=0;i<E.SUDOKU_SIZE;i++){
            for(int j=0;j<E.SUDOKU_SIZE;j++)
                this.__empty[i][j]=-1;
        }

    }

    public void setScissor(int scissorWidth){
        this.E.scissorWidth=scissorWidth;
    }

    private Recognizer getImg(Mat img){
        this.Img=img;

        return this;

    }

    private Recognizer preProcessImg(){
        Mat img2=this.Img.clone();
        Imgproc.cvtColor(Img,img2,Imgproc.COLOR_RGB2GRAY);//morph into gray pic
        Imgproc.adaptiveThreshold(img2,img2,255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 151,1);
        //the background should be in white.
        this.ThresholdImg=img2;

        return this;
    }

    private Recognizer extractOuterBound(){
        E.ExtractOuterBoundContour(this.ThresholdImg);
        return this;
    }
    private Recognizer recognizeNumbers(){
        if(isSolved)return this;
        if(E.Extract(this.ThresholdImg)){

            this.RecognizedNumbers=E
                    .getExtractedCells()
                    .stream()
                    .map(P::Patternize28x28)
                    .map(I::toDigit)
                    .collect(Collectors.toList());
        }
        return this;
    }

    private boolean contains(int[] arr, int j){
        for(int i=0;i<arr.length;i++)
            if(arr[i]==j)return true;
        return false;
    }
    private int[] setAdd(int[] arr, int n){
        for(int i=0;i<arr.length;i++){
            if(arr[i]==n)return arr;
            if(arr[i]==0){//找到第一个空位
                arr[i]=n;return arr;
            }
        }
        return arr;
    }

    private synchronized Recognizer arrangeNumbersMatrix(){
        if(this.RecognizedNumbers==null || isSolved) {

            return this;
        }
        this.ArrangedNumbers=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];

        for(int i=0; i<E.SUDOKU_SIZE ; i++){
            for(int j=0; j<E.SUDOKU_SIZE ; j++){
                int num=this.RecognizedNumbers.get(i*E.SUDOKU_SIZE+j);
                this.ArrangedNumbers[i][j]=num;

                int[]anf=this.RecognizedNumbersHistory[i][j];

                if(!contains(anf, -1))//有-1说明该格子其实是空的。
                    this.RecognizedNumbersHistory[i][j]=setAdd(anf, num);

            }
        }

        return this;
    }

    private ArrayList<int[][]> Answers=new ArrayList<>();

    private int[][] copyMatrix(int[][] in_matrix) {
        int[][] out_matrix = new int[in_matrix.length][];

        for(int i = 0; i < in_matrix.length; i++)
            out_matrix[i] = in_matrix[i].clone();

        return out_matrix;
    }
    private boolean sol(int [][] arr, int i, int j){

        if(i>E.SUDOKU_SIZE-1)return false;

        for(int ind=0;ind<this.RecognizedNumbersHistory[i][j].length;ind++){

            arr[i][j]=this.RecognizedNumbersHistory[i][j][ind];

            ArrayList<int[][]> ans=S.solveSudo(arr);
            if(ans.size()>0){
                this.Answers=ans;

                return true;
            } else {
                return sol(arr, i + (j == E.SUDOKU_SIZE-1 ? 1 : 0), (j == E.SUDOKU_SIZE-1 ) ? 0 : (j + 1));
            }
        }

        return false;
    }

    private int[][]sudoXor(int[][]a, int[][]b){
        int [][]dst=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];

        for(int i=0;i<E.SUDOKU_SIZE;i++){
            for(int j=0;j<E.SUDOKU_SIZE;j++){
                if(a[i][j]!=-1 && b[i][j]==-1)
                dst[i][j]=a[i][j];
                else dst[i][j]=-1;
            }
        }
        return dst;
    }

    private boolean bruteForce=true;

    private Recognizer solveNumbers(){

        if(this.ArrangedNumbers==null || isSolved)return this;

        ArrayList<int[][]> rst=new ArrayList<>();//=S.solveSudo(this.ArrangedNumbers);

        if(bruteForce) {

            if (sol(copyMatrix(this.ArrangedNumbers), 0, 0)) {
                rst = Answers;
            }
        } else {

            rst=S.solveSudo(this.ArrangedNumbers);//alert: potential bug
        }

        if(rst.size()!=0 && !firstRush){
            isSolved=true;
            this.SolvedNumbers=rst.get(0);
            this.RecognizedNumbersHistory=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        }
        return this;
    }

    private Recognizer drawOuterBound (){

        MatOfPoint bound= E.getBound();
        if (bound==null)return this;

        MatOfPoint2f boundf=new MatOfPoint2f(),
                abound=new MatOfPoint2f();
        boundf.fromList(bound.toList());
        double peri= Imgproc.arcLength(boundf, true);
        approxPolyDP(boundf, abound, 0.02*peri, true);
        this.Bound.fromList(abound.toList());
        List<MatOfPoint> mp=new ArrayList<>();
        mp.add(Bound);
        if(isSolved)
            Core.polylines(Img, mp, true, getRandomScalar(),3);
        else Core.polylines(Img, mp, true, new Scalar(255,255,0),3);
        return this;
    }

    private Recognizer drawText(){
        if(this.Img==null)return this;
        String txt="";

        if(E.getBound()==null)
            txt = "Targeting...";
        else if(isSolved)
            txt="Solved.";
        else txt="Scanning...";

        Core.putText(Img,
                txt,
                new Point(50,50),
                Core.FONT_HERSHEY_PLAIN,
                2,
                new Scalar(0,255,0),2
        );

        return this;

    }

    @FunctionalInterface
    interface Function3 <A, B, C, R> {public R apply (A a, B b, C c);}

    Random r=new Random(255);

    private int getRandomColor(){
        return (r.nextInt()%200)+55;
    }

    Scalar[] colorTable={
            new Scalar(255,0,0),
            new Scalar(255,255,0),
            new Scalar(255,0,255),
            new Scalar(0,255,255),
            new Scalar(255,255,255),
            new Scalar(0,255,0),
            new Scalar(0,0,255)
    } ;
    private Scalar getRandomScalar(){
        return colorTable[r.nextInt(colorTable.length)];
    }

    private Recognizer drawRecognizedNumbers() {
        MatOfPoint bound = E.getBound();
        if (bound == null || RecognizedNumbers == null) return this;

        int[][]Xored=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        if(isSolved)Xored=sudoXor(this.SolvedNumbers, this.ArrangedNumbers);

        List<Point> clockwised = Utils.clockwise(this.Bound.toList());
        Function<Integer, Point>
                l1=Utils.lineDivPointFunc
                (clockwised.get(Utils.UP_LEFT), clockwised.get(Utils.DOWN_LEFT),
                        E.SUDOKU_SIZE),
                l2=Utils.lineDivPointFunc
                        (clockwised.get(Utils.UP_RIGHT), clockwised.get(Utils.DOWN_RIGHT),
                                E.SUDOKU_SIZE);

        for(int y=0; y<E.SUDOKU_SIZE; y++) {
            for (int x = 0; x < E.SUDOKU_SIZE; x++) {
                Point pl=l1.apply(y+1), pr=l2.apply(y+1);
                BiFunction<Integer, Integer, Point> __=(z, w)->
                {
                    Function<Integer, Point> l3=Utils.lineDivPointFunc(pl,pr, E.SUDOKU_SIZE);
                    return l3.apply(z);
                };
                double width=Math.abs(pl.x-pr.x)/E.SUDOKU_SIZE;
                Point p=__.apply(x,y);

                int num;
                if(!isSolved)
                    num=ArrangedNumbers[y][x];
                else num=Xored[y][x];

                Core.putText
                        (Img,
                                (num==-1?"":""+num),
                                p,
                                Core.FONT_HERSHEY_PLAIN,
                                (width/(9))*0.8,
                                isSolved?(new Scalar(0,0,255)):new Scalar(255,0,0),
                                2);
            }
        }
        if(firstRush){
            this.firstRush=false;
            this.RecognizedNumbersHistory=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        }
        return this;
    }

    public Mat __getTransformedBound(Mat img){//will be removed in the future.
        this.getImg(img).preProcessImg().extractOuterBound();
        if(E.Extract2(ThresholdImg))
            return E.ExtractedCellsGraph;
        else return img;

    }

    //印刷体识别接口
    public Mat RecognizeAndSolve(Mat img){

        this
                .getImg(img)
                .preProcessImg()
                .extractOuterBound()
                .recognizeNumbers()
                .arrangeNumbersMatrix()
                .solveNumbers()
                .drawText()
                .drawOuterBound()
                .drawRecognizedNumbers();

        return this
                .Img;
    }

    public Mat RecognizeOnly(Mat img){
        this.getImg(img)
                .preProcessImg()
                .extractOuterBound()
                .recognizeNumbers()
                .arrangeNumbersMatrix()
                .drawText()
                .drawOuterBound()
                .drawRecognizedNumbers();
        return this.Img;
    }

    //solving function that triggered by user.
    public boolean Solve(int[][] input){

        if (input.length != E.SUDOKU_SIZE)
            throw new AssertionError();
        if (input[0].length != E.SUDOKU_SIZE)
            throw new AssertionError();

        this.bruteForce=false;
        this.ArrangedNumbers = input;

        this.solveNumbers();
        return isSolved;
    }

    public int[][] GetCurrentSudoku(){//获取当前识别好的数独矩阵，用-1来表示空
        if(isSolved)
            return this.SolvedNumbers;
        else
            return this.ArrangedNumbers!=null?this.ArrangedNumbers:__empty;
    }

    //User set number to the sudoku matrix.
    public void SetRecognizedNumbers(int y, int x, int num) {//更改对应（X,Y)位置的识别结果
        this.bruteForce = false;
        for (int i = 0; i < E.SUDOKU_SIZE; i++)
            this.RecognizedNumbersHistory[y][x][i] = 0;
        this.RecognizedNumbersHistory[y][x][0] = num;
    }

    //reset all, prepare for the next scan.
    public  void Reset(){

        this.isSolved=false;
        this.RecognizedNumbers=null;
        this.ArrangedNumbers=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        this.RecognizedNumbersHistory=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        this.SolvedNumbers=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        this.firstRush=true;
        this.bruteForce=true;
    }

    private Mat black=new Mat();
    public Mat GetTransformedImage(){return E.getTransformed()==null?black:E.getTransformed();}

    public void SetSudokuSize(int size){
        E.SetSize(size);

        Reset();

        this.__empty=new int[E.SUDOKU_SIZE][E.SUDOKU_SIZE];
        for(int i=0;i<E.SUDOKU_SIZE;i++){
            for(int j=0;j<E.SUDOKU_SIZE;j++)
                this.__empty[i][j]=-1;
        }

    }

    public Mat ExportAnswerToStandardSudokuImage()
    {
        Mat img=Highgui.imread("./resources/blankSudoku.png");

        if(!isSolved)return null;

        int offsetx=970
                , offsety=1200;

        int dx=330,dy=343;
        Point p=new Point();

        for(int y=0;y<E.SUDOKU_SIZE;y++){
            for(int x=0;x<E.SUDOKU_SIZE;x++){

                int xx=offsetx+dx*x, yy=offsety+dy*y,
                        num=this.SolvedNumbers[y][x];
                p.x=xx;
                p.y=yy;
                Core.putText
                        (img,
                                (num==-1?"":""+num),
                                p,
                                Core.FONT_HERSHEY_PLAIN,
                                20,
                                new Scalar(0,0,0),
                                10);

            }
        }

        return img;

    }

}
<file_sep>/_obselete/SquareArranger.java
package team.sudocool.ImgWorks;

import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Heranort on 16/11/9.
 */
public class SquareArranger {

   private static class cell<A, B> {
        public  Rect rect;
        public  MatOfPoint mat;
        public int y;
        public int x;
        public int width;
        public int height;
        public cell(Rect a, MatOfPoint b) {
            rect = a;
            mat = b;
            y=a.y;
            x=a.x;
            width=a.width;
            height=a.height;
        }
    }

    public SquareArranger(int sudokuSize, int fillMethod){
        this.sudokuSize=sudokuSize;
        this.fillMethod=fillMethod;
    }

    private int fillMethod;
    private int sudokuSize;

    public static final int STANDARD_SUDOKU_SIZE=9;
    public static final int FILL_EMPTY=0;//arrange the lost squares with empties.
    public static final int FILL_COPY=1;//copy the square next to the lost square.
    private cell copyDown(cell c){
        List<Point> pl;
        if(fillMethod==FILL_COPY)
            pl=c.mat.toList().stream().map((p)->new Point(p.x, p.y+c.height)).collect(Collectors.toList());
        else
            pl=new ArrayList<>();
        c.mat.fromList(pl);
        return new cell(
                new Rect(c.x, c.y+c.height, c.width, c.height),
                c.mat);
    }

    private cell copyUp(cell c){
        List<Point> pl;
        if(fillMethod==FILL_COPY)
            pl=c.mat.toList().stream().map((p)->new Point(p.x, p.y-c.height)).collect(Collectors.toList());
        else
            pl=new ArrayList<>();
        c.mat.fromList(pl);
        return new cell(
                new Rect(c.x, c.y-c.height, c.width, c.height),
                c.mat);
    }
    private cell newCell(cell c){
        return new cell(new Rect(c.x,c.y,0,0), new MatOfPoint());
    }
    private List<List<cell>> _arrange_last(List<List<cell>> matrix, double dist){
        List<cell> lastRow = matrix.get(matrix.size()-1);//last row.
        List<cell>lst=matrix.get(matrix.size()-2);
        matrix.remove(matrix.size()-1);

        for (cell x : lst) {

            if (lastRow.stream().filter((y) ->
                    Math.abs(y.x - x.x) < dist / 2).count() == 0)// found exact position
            {
                int index = 0;

                for (; index < lastRow.size(); index++) {
                    if (lastRow.get(index).x > x.x) {
                        //lastRow.add(index, new cell(new Rect(x.x, x.y, 0, 0), new MatOfPoint()));
                        lastRow.add(index, copyDown(x));

                        break;
                    }
                }

            }
        }
        matrix.add(lastRow);
        return matrix;
    }
    private List<List<cell>> _arrange (List<List<cell>> matrix, double dist){
        List<List<cell>> rmatrix=new ArrayList<>();
        List<cell> lastRow = matrix.get(0);
        matrix.remove(0);
        for (List<cell> lst : matrix) {

            for (cell x : lst) {

                if (lastRow.stream().filter((y) ->
                        Math.abs(y.x - x.x) < dist / 2).count() == 0)// found exact position
                {
                    int index = 0;

                    for (; index < lastRow.size(); index++) {
                        if (lastRow.get(index).x > x.x) {//find next to .
                            lastRow.add(index, copyUp(x));
                            //lastRow.add(index, new cell(new Rect(x.x, x.y, 0, 0), new MatOfPoint()));
                            break;
                        }
                    }

                }
            }
            rmatrix.add(lastRow);
            lastRow=lst;
        }
        rmatrix.add(lastRow);
        return rmatrix;
    }

    public List<List<MatOfPoint>> Arrange(List<MatOfPoint> pl){

        List<cell> rl=pl.stream()
                .map((x)->new cell(Imgproc.boundingRect(x), x))
                .sorted((m1, m2)->(m1.y>m2.y?1:-1))
                .collect(Collectors.toList());
        List<List<cell>> matrix=new ArrayList<>();
        while(rl.size()>0) {

            int y = rl.get(0).y,
                    wid = rl.get(0).width;
            matrix.add(
                    rl.stream().filter((x) ->
                            (Math.abs(x.y - y) < wid / 2))
                            .sorted((a,b)->
                                    (a.x>b.x?1:-1))
                            .collect(Collectors.toList())
            );
            rl = rl.stream()
                    .filter((x) ->
                            (Math.abs(x.y - y) > wid / 2))
                    .collect(Collectors.toList());
        }

        //do not handle when exsist one row that
        //the number of elements is larger than SUDOKU_SIZE.

        //matrix.stream().forEach(x->System.out.println(x.size()));

        for(List<cell> lst : matrix)
            if(lst.size()>sudokuSize)return new ArrayList<>();

        int width=matrix.get(0).get(0).width;
        for(int i=0;i<sudokuSize-1;i++)
            matrix=_arrange(matrix,width);//first n-1 rows

        if(matrix.get(matrix.size()-1).size()!=sudokuSize)
            //the last row does not satisfy.
            _arrange_last(matrix, width);

        if(matrix.stream().filter((x)->x.size()!=sudokuSize).count()!=0)
            return new ArrayList<>();
        return matrix.stream().map(
                lst->
                        lst.stream().map(
                                x -> x.mat)
                                .collect(Collectors.toList()))
                .collect(Collectors.toList());
    }
    public static void printM(List<List<cell>> polys){
        polys.forEach((lst)-> {
                    lst.forEach(x ->
                        System.out.printf("%d ",x.x));
                    System.out.println();
                });
    }
}
<file_sep>/SudoCool/src/team/sudocool/Solver/ReadSudo.java
package team.sudocool.Solver;

import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

/**
 * Created by L.Laddie on 2016/11/29.
 */
public class ReadSudo {
    /**
     * Read some matrix from file
     * @param path file_path
     * @param size matrix_size
     * @return matrix(-1 replace 0)
     * @throws IOException file can`t read
     */
    public static int[][][] readMatrixFile(String path, int size) throws IOException {
        int[][] ans_ele = new int[size][size];
        ArrayList<int[][]> ans = new ArrayList<>();

        int j = 0, i = 0;
        FileReader in = null;

        try {
            in = new FileReader(path);
            int temp;

            while ((temp = in.read()) != -1) {
                if (temp >= 48 && temp < 58)
                    ans_ele[i][j++] = temp == 48 ? -1 : (temp-48);  //when read 0, write -1

                if (j == size) {
                    j = 0;
                    i++;
                }

                if (i == size) {
                    i = 0;

                    int[][] matrix_temp = new int[ans_ele.length][];
                    for (int k = 0; k < ans_ele.length; k++)
                        matrix_temp[k] = ans_ele[k].clone();

                    ans.add(matrix_temp);
                }
            }
        } finally {
            if (in != null)
                in.close();
        }

        return ans.toArray(new int[0][0][0]);
    }
}
<file_sep>/README.md
# SudoCool -- Webcam Sudoku Recognizer & Solver

![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss0.png)

Let me introduce this in general.

This is originally an assignment project of lesson "Machine Intelligence" in Beijing University of Posts & Communications (BUPT) but now I'm making it open-source. I learned a lot from other projects available on Github and I also want to share my knowledges. So here it goes.

Our major developers are:
<NAME> (niwtr)
<NAME> (laddie 132)
<NAME> (shunvforever)

## A simple introduction
This is a Webcam Sudoku Recognizer & Solver based on OpenCV 2.4.13 and BPNN. You use your webcam to capture sudoku puzzles on flat platforms (You can either use papers, iPads or your smartphones.) and this one will solve your puzzles "automagically". The solution will be printed on the same screen. You needn't perform any operations during that period since our software will do that for you. It automatically captures the video flow, locates the puzzle, recognizes the numbers and solves them.

When no puzzle's found in the TV, it displays "Targeting..." and keep searching for the puzzle boards.
![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss4.png)

When a puzzle board is found in TV and it's not at that time able to solve that puzzle, displays "Scanning...".
![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss6.png)

When the puzzle is solved the solution will be displayed on both TV screen and solution board on the right.
![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss1.png)

 After you get the solution you are also allowed to export your solution in PDF format.

This picture demonstrates that the software has recognized & solved a sudoku puzzle which is projected on my New iPad.
![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss2.png)

And this demonstrates the whole recognition procedure:

![](https://github.com/niwtr/SudoCool/blob/master/Screenshots/ss3.gif)

This software comes in both source code and precompiled jar packet. You can first take a try before you dive into the code.

## How it works
The basic algorithm of number recognition is BP neural networks. In our precompiled jar package the neural networks is trained from both handwriting and printed numbers so the software performs well on both hand-written and printed sudoku. The NN is saved on JSON files and you can check that if you like. Note that we currently do not support users to train their own networks but you may modify the code to achieve that. Sorry.

The project splits into four major parts:

* **Eye**: Controls the webcam (TV), collects raw video flow.

* **ImgWorks**: Process each frames of the raw video flow, extracts features, locates the puzzles, splits the puzzles and extract each numbers. This also handles the output images. The operation sequence can be seen in this piece of code which is in Recognizer.java:
```this
                .getImg(img)
                .preProcessImg()
                .extractOuterBound()
                .recognizeNumbers()
                .arrangeNumbersMatrix()
                .solveNumbers()
                .drawText()
                .drawOuterBound()
                .drawRecognizedNumbers();
```

The image processing algorithm is easy to understand. When a webcam frame is sent to the Recognizer module, it converts the image to binary and find the largest outline (say, contour). If that outline is almost square, we recon that to be a game board. Then we split that contour into several small parts (ex. 81 for 9x9 sudoku, 64 for 8x8 sudoku) and perform after-processing for each parts, cuts them into smaller ones and extract the features. These will be arranged to an ordered Java matrix. After that, those 28x28 binary images, or features, will be sent to the BP neural network for number recognizing. When the sudoku is solved we also need to project the answer to the TV, which brings us a taste of "Augmented Reality".

* **Identifier**: Identifies the numbers extracted by ImgWorks and recognizes the numbers (picture -> text). This part also contains the BP neural network algorithm. You can replace this one with another NN if you like.
* **Solver**: Contains fast sudoku solving algorithm. It solves the sudoku after numbers are recognized. Note that if the solving algorithm is only performed on each frame, regardless of the history, in rare chance could we find the solution, cuz a single failure to correctly recognize a number would ruin the whole solution. For that cause we will try to remember all the occurs of numbers on each cell and traverse all the possibilities. This will boost our memory & CPU usage but guarantees that the solution work is done in a relatively short time.

If you are here seeking for BPNN, go for **Identifier**, or is you are seeking for image processing techniques, watch for **ImgWorks**.

Hack and glory awaits!

<NAME> (niwtr)<file_sep>/SudoCool/src/team/sudocool/Solver/Solver.java
package team.sudocool.Solver;

import javafx.util.Pair;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Stack;

/**
 * @author L.Laddie
 * @version 1.0
 * @since 2016/11/22
 */
public class Solver {
    private static final int MAXANSWERS = 50;
    private static final int NULLUNIT = -1;

    private int sudoType;
    private boolean finish;
    private int[][] curSudo;
    private ArrayList<int[][]> ansSudo;
    private HashMap<Pair<Integer, Integer>, ArrayList<Integer>> curSudoReadyNum;
    private Stack<Pair<int[][], HashMap<Pair<Integer, Integer>, ArrayList<Integer>>>> sudoBuffer;

    /**
     * Initial
     */
    public Solver(){
        ansSudo = new ArrayList<>();
        sudoBuffer = new Stack<>();
        curSudoReadyNum = new HashMap<>();
    }

    /**
     * This is the function for solving the Sudoku
     */
    public ArrayList<int[][]> solveSudo(int[][] sudo) {
        finish = false;
        sudoType = sudo.length;
        curSudo = copyMatrix(sudo);
        ansSudo.clear();
        sudoBuffer.clear();
        curSudoReadyNum.clear();

        if(checkSudoValid())
        {
            ArrayList<Pair<Integer, Integer>> nullPoint = getNullUnit();
            if(nullPoint.isEmpty())
            {
                ansSudo.add(this.curSudo);
            }
            else
            {
                if(findAvaFill(nullPoint))
                {
                    while(!finish) {
                        fillUnit();
                        updateSudoReadyNum();
                    }
                }
            }
        }

        return ansSudo;
    }

    /**
     * judge the matrix whether have null unit
     * @return  the null unit point list
     */
    private ArrayList<Pair<Integer, Integer>> getNullUnit() {
        if (curSudo == null)
            throw new AssertionError();

        ArrayList<Pair<Integer, Integer>> nullPoint = new ArrayList<>();
        for (int i = 0; i < sudoType; i++) {
            for (int j = 0; j < sudoType; j++) {
                if(curSudo[i][j] == NULLUNIT)
                    nullPoint.add(new Pair<>(i, j));
            }
        }

        return nullPoint;
    }

    /**
     * find every blank unit the possible number
     * @param point_list null unit point list
     * @return false for existing some unit no answer
     */
    private boolean findAvaFill(ArrayList<Pair<Integer, Integer>> point_list) {
        for(Pair<Integer, Integer> point : point_list)
        {
            int i = point.getKey();
            int j = point.getValue();
            ArrayList<Integer> readyNumber = new ArrayList<>();

            for(int value = 1; value <= sudoType; value++)
            {
                if(checkNumValid(i, j, value)) {
                    readyNumber.add(value);
                }
            }

            if(readyNumber.isEmpty())
                return false;
            else
                curSudoReadyNum.put(point, readyNumber);
        }

        return true;
    }

    /**
     * fill in the blank unit
     */
    private void fillUnit() {
        boolean findUnique = false;
        Iterator<HashMap.Entry<Pair<Integer, Integer>, ArrayList<Integer>>> it;

        it = curSudoReadyNum.entrySet().iterator();
        while(it.hasNext()) {
            HashMap.Entry<Pair<Integer, Integer>, ArrayList<Integer>> entry = it.next();
            Pair<Integer, Integer> point = entry.getKey();
            ArrayList<Integer> readyNumber = entry.getValue();

            //find the unique unit
            if(readyNumber.size() == 1)
            {
                findUnique = true;

                curSudo[point.getKey()][point.getValue()] = readyNumber.get(0);
                it.remove();

                break;
            }
        }

        //didn`t find the unique unit
        if(!findUnique) {

            it = curSudoReadyNum.entrySet().iterator();
            if(it.hasNext()) {
                HashMap.Entry<Pair<Integer, Integer>, ArrayList<Integer>> entry = it.next();
                Pair<Integer, Integer> point = entry.getKey();
                int i = point.getKey();
                int j = point.getValue();
                int value;

                ArrayList<Integer> readyNumber = entry.getValue();
                if(!readyNumber.isEmpty())
                {
                    int location = readyNumber.size()-1;
                    value = readyNumber.get(location);
                    readyNumber.remove(location);

                    sudoBuffer.push(new Pair<>(copyMatrix(curSudo), copyHashMap(curSudoReadyNum)));

                    it.remove();
                    curSudo[i][j] = value;
                }
            }
        }
    }

    /**
     * After fill in a blank, check the other ready number whether ready now
     */
    private void updateSudoReadyNum() {

        for (HashMap.Entry<Pair<Integer, Integer>, ArrayList<Integer>> entry : curSudoReadyNum.entrySet()) {
            int i = entry.getKey().getKey();
            int j = entry.getKey().getValue();

            ArrayList<Integer> readyNum = entry.getValue();
            Iterator<Integer> it = readyNum.iterator();
            while(it.hasNext()) {
                int value = it.next();
                if(!checkNumValid(i, j, value))
                    it.remove();
            }

            //existing some unit no answer
            if(entry.getValue().isEmpty()) {
                backState();
                break;
            }
        }

        //check the answer
        if(curSudoReadyNum.isEmpty())
        {
            ansSudo.add(copyMatrix(curSudo));

            if(ansSudo.size() > MAXANSWERS)     //no more than 50 answers
                finish = true;
            backState();
        }
    }

    /**
     * back to the nearest state
     */
    private void backState() {
        if(sudoBuffer.isEmpty()) {
            finish = true;
            return;
        }

        Pair<int[][], HashMap<Pair<Integer, Integer>, ArrayList<Integer>>> bufferPair = sudoBuffer.pop();
        curSudo = bufferPair.getKey();
        curSudoReadyNum = bufferPair.getValue();
    }

    /**
     * check whether the value is allowed
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid(int i, int j, int value) {
        if (curSudo == null)
            throw new AssertionError();

        switch (sudoType)
        {
            case 4:
                return checkNumValid_Four(i, j, value);

            case 5:
                return checkNumValid_Five(i, j, value);

            case 6:
                return checkNumValid_Six(i, j, value);

            case 7:
                return checkNumValid_Seven(i, j, value);

            case 8:
                return checkNumValid_Eight(i, j, value);

            case 9:
                return checkNumValid_Nine(i, j, value);

            default:
                throw new AssertionError();
        }
    }

    private boolean checkHorAndVer(int i, int j, int value) {
        for(int k = 0; k < sudoType; k++)
            if(k != j && curSudo[i][k] == value)
                return false;

        for (int k = 0; k < sudoType; k++)
            if (k != i && curSudo[k][j] == value)
                return false;

        return true;
    }

    /**
     * sudoku rule for 4*4
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Four(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        for (int k = (i/2)*2; k < (i/2)*2+2; k++)
            for(int w = (j/2)*2; w < (j/2)*2+2; w++)
                if((k != i || w != j) && curSudo[k][w] == value)
                    return false;

        return true;
    }

    /**
     * sudoku rule for 5*5
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Five(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        HashMap<Integer, ArrayList<Pair<Integer, Integer>>> rulePoint = new HashMap<>();
        ArrayList<Pair<Integer, Integer>> pointArray = new ArrayList<>();
        pointArray.add(new Pair<>(1, 2));
        pointArray.add(new Pair<>(2, 2));
        pointArray.add(new Pair<>(3, 2));
        pointArray.add(new Pair<>(2, 1));
        pointArray.add(new Pair<>(2, 3));
        rulePoint.put(1, pointArray);

        ArrayList<Pair<Integer, Integer>> pointArray2 = new ArrayList<>();
        pointArray2.add(new Pair<>(0, 0));
        pointArray2.add(new Pair<>(0, 1));
        pointArray2.add(new Pair<>(0, 2));
        pointArray2.add(new Pair<>(1, 0));
        pointArray2.add(new Pair<>(1, 1));
        rulePoint.put(2, pointArray2);

        ArrayList<Pair<Integer, Integer>> pointArray3 = new ArrayList<>();
        pointArray3.add(new Pair<>(0, 3));
        pointArray3.add(new Pair<>(0, 4));
        pointArray3.add(new Pair<>(1, 3));
        pointArray3.add(new Pair<>(1, 4));
        pointArray3.add(new Pair<>(2, 4));
        rulePoint.put(3, pointArray3);

        ArrayList<Pair<Integer, Integer>> pointArray4 = new ArrayList<>();
        pointArray4.add(new Pair<>(2, 0));
        pointArray4.add(new Pair<>(3, 0));
        pointArray4.add(new Pair<>(3, 1));
        pointArray4.add(new Pair<>(4, 0));
        pointArray4.add(new Pair<>(4, 1));
        rulePoint.put(4, pointArray4);

        ArrayList<Pair<Integer, Integer>> pointArray5 = new ArrayList<>();
        pointArray5.add(new Pair<>(3, 3));
        pointArray5.add(new Pair<>(3, 4));
        pointArray5.add(new Pair<>(4, 2));
        pointArray5.add(new Pair<>(4, 3));
        pointArray5.add(new Pair<>(4, 4));
        rulePoint.put(5, pointArray5);

        Pair<Integer, Integer> cur_point = new Pair<>(i, j);
        for(int w = 1; w <= 5; w++)
        {
            ArrayList<Pair<Integer, Integer>> pointArray_temp = rulePoint.get(w);
            if(pointArray_temp.indexOf(cur_point) != -1) {
                for(int q = 0; q < 5; q++)
                {
                    Pair<Integer, Integer> point = pointArray_temp.get(q);
                    if(!point.equals(cur_point) && curSudo[point.getKey()][point.getValue()] == value)
                        return false;
                }
            }
        }

        return true;
    }

    /**
     * sudoku rule for 6*6
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Six(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        for (int k = (i/2)*2; k < (i/2)*2+2; k++)
            for(int w = (j/3)*3; w < (j/3)*3+3; w++)
                if((k != i || w != j) && curSudo[k][w] == value)
                    return false;

        return true;
    }

    /**
     * sudoku rule for 7*7
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Seven(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        HashMap<Integer, ArrayList<Pair<Integer, Integer>>> rulePoint = new HashMap<>();
        ArrayList<Pair<Integer, Integer>> pointArray = new ArrayList<>();
        pointArray.add(new Pair<>(0, 0));
        pointArray.add(new Pair<>(0, 1));
        pointArray.add(new Pair<>(1, 0));
        pointArray.add(new Pair<>(1, 1));
        pointArray.add(new Pair<>(1, 2));
        pointArray.add(new Pair<>(2, 1));
        pointArray.add(new Pair<>(2, 2));
        rulePoint.put(1, pointArray);

        ArrayList<Pair<Integer, Integer>> pointArray2 = new ArrayList<>();
        pointArray2.add(new Pair<>(0, 2));
        pointArray2.add(new Pair<>(0, 3));
        pointArray2.add(new Pair<>(0, 4));
        pointArray2.add(new Pair<>(0, 5));
        pointArray2.add(new Pair<>(1, 3));
        pointArray2.add(new Pair<>(1, 4));
        pointArray2.add(new Pair<>(1, 5));
        rulePoint.put(2, pointArray2);

        ArrayList<Pair<Integer, Integer>> pointArray3 = new ArrayList<>();
        pointArray3.add(new Pair<>(0, 6));
        pointArray3.add(new Pair<>(1, 6));
        pointArray3.add(new Pair<>(2, 6));
        pointArray3.add(new Pair<>(3, 6));
        pointArray3.add(new Pair<>(4, 6));
        pointArray3.add(new Pair<>(2, 5));
        pointArray3.add(new Pair<>(3, 5));
        rulePoint.put(3, pointArray3);

        ArrayList<Pair<Integer, Integer>> pointArray4 = new ArrayList<>();
        pointArray4.add(new Pair<>(2, 0));
        pointArray4.add(new Pair<>(3, 0));
        pointArray4.add(new Pair<>(4, 0));
        pointArray4.add(new Pair<>(5, 0));
        pointArray4.add(new Pair<>(6, 0));
        pointArray4.add(new Pair<>(3, 1));
        pointArray4.add(new Pair<>(4, 1));
        rulePoint.put(4, pointArray4);

        ArrayList<Pair<Integer, Integer>> pointArray5 = new ArrayList<>();
        pointArray5.add(new Pair<>(2, 3));
        pointArray5.add(new Pair<>(2, 4));
        pointArray5.add(new Pair<>(3, 2));
        pointArray5.add(new Pair<>(3, 3));
        pointArray5.add(new Pair<>(3, 4));
        pointArray5.add(new Pair<>(4, 3));
        pointArray5.add(new Pair<>(4, 2));
        rulePoint.put(5, pointArray5);

        ArrayList<Pair<Integer, Integer>> pointArray6 = new ArrayList<>();
        pointArray6.add(new Pair<>(5, 1));
        pointArray6.add(new Pair<>(5, 2));
        pointArray6.add(new Pair<>(5, 3));
        pointArray6.add(new Pair<>(6, 1));
        pointArray6.add(new Pair<>(6, 2));
        pointArray6.add(new Pair<>(6, 3));
        pointArray6.add(new Pair<>(6, 4));
        rulePoint.put(6, pointArray6);

        ArrayList<Pair<Integer, Integer>> pointArray7 = new ArrayList<>();
        pointArray7.add(new Pair<>(4, 4));
        pointArray7.add(new Pair<>(4, 5));
        pointArray7.add(new Pair<>(5, 4));
        pointArray7.add(new Pair<>(5, 5));
        pointArray7.add(new Pair<>(5, 6));
        pointArray7.add(new Pair<>(6, 5));
        pointArray7.add(new Pair<>(6, 6));
        rulePoint.put(7, pointArray7);

        Pair<Integer, Integer> cur_point = new Pair<>(i, j);
        for(int w = 1; w <= 7; w++)
        {
            ArrayList<Pair<Integer, Integer>> pointArray_temp = rulePoint.get(w);
            if(pointArray_temp.indexOf(cur_point) != -1) {
                for(int q = 0; q < 7; q++)
                {
                    Pair<Integer, Integer> point = pointArray_temp.get(q);
                    if(!point.equals(cur_point) && curSudo[point.getKey()][point.getValue()] == value)
                        return false;
                }
            }
        }

        return true;
    }

    /**
     * sudoku rule for 8*8
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Eight(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        for (int k = (i/2)*2; k < (i/2)*2+2; k++)
            for(int w = (j/4)*4; w < (j/4)*4+4; w++)
                if((k != i || w != j) && curSudo[k][w] == value)
                    return false;

        return true;
    }

    /**
     * sudoku rule for 9*9
     * @param i horizontal
     * @param j vertical
     * @param value padding value
     * @return true or false
     */
    private boolean checkNumValid_Nine(int i, int j, int value) {
        if(!checkHorAndVer(i, j, value))
            return false;

        for (int k = (i/3)*3; k < (i/3)*3+3; k++)
            for(int w = (j/3)*3; w < (j/3)*3+3; w++)
                if((k != i || w != j) && curSudo[k][w] == value)
                    return false;

        return true;
    }

    /**
     * check whether current sudoku is the valid
     * @return true or false
     */
    private boolean checkSudoValid() {
        for (int i = 0; i < sudoType; i++) {
            for (int j = 0; j < sudoType; j++) {
                if(curSudo[i][j] != NULLUNIT && !checkNumValid(i, j, curSudo[i][j]))
                    return false;
            }
        }

        return true;
    }

    /**
     * deep copy of matrix
     * @param in_matrix input
     * @return output
     */
    private int[][] copyMatrix(int[][] in_matrix) {
        int[][] out_matrix = new int[in_matrix.length][];

        for(int i = 0; i < in_matrix.length; i++)
            out_matrix[i] = in_matrix[i].clone();

        return out_matrix;
    }

    /**
     * deep copy of hashmap
     * @param in_hashmap input
     * @return copy hashmap
     */
    private HashMap<Pair<Integer, Integer>, ArrayList<Integer>> copyHashMap(HashMap<Pair<Integer, Integer>, ArrayList<Integer>> in_hashmap) {
        HashMap<Pair<Integer, Integer>, ArrayList<Integer>> newHashMap = new HashMap<>();

        for(HashMap.Entry<Pair<Integer, Integer>, ArrayList<Integer>> entry : in_hashmap.entrySet())
        {
            newHashMap.put(entry.getKey(), (ArrayList<Integer>) entry.getValue().clone());
        }

        return newHashMap;
    }
}
<file_sep>/SudoCool/src/team/sudocool/Identifier/algol/BasisFunc.java
package team.sudocool.Identifier.algol;

import java.io.FileReader;
import java.io.IOException;

/**
 * @author L.Laddie
 * @version 1.0
 * @since 2016/11/11
 */
public class BasisFunc {

    /**
     * Judge the input data whether null
     * @param in matrix
     * @return whether null
     */
    public static boolean isNull(int[][] in) {
        for(int[] i : in)
            for(int ele : i)
                if(ele != 0) {
                    return false;
                }
        return true;
    }

    /**
     * Convert Two-dimensional to One-dimensional
     * and also int to double
     * @param in two-dimension matrix
     * @return one-dimension matrix
     */
    public static double[] convertOne(int[][] in)
    {
        int n = in.length;
        double[] ans = new double[n*n];
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
            {
                ans[i*n+j] = in[i][j];
            }
        }

        return ans;
    }

    /**
     * Calculate the max
     */
    public static int getMax(double[] in) {
        double max_val = in[0];
        int ans = 0;

        for(int i = 1; i < in.length; i++)
        {
            if(in[i] > max_val){
                ans = i;
                max_val = in[i];
            }
        }

        return ans;
    }
}
<file_sep>/SudoCool/src/team/sudocool/Identifier/algol/ReadData.java
package team.sudocool.Identifier.algol;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * This is for reading the training data
 * @author L.Laddie
 * @version 1.0
 * @since 2016/11/7
 */
public class ReadData {
    /**
     * read from learning file
     * @param size matrix size
     * @return all the one-dimension matrix
     * @throws IOException read error
     */
    private double[][] readFile(String path, int size) throws IOException
    {
        double[] ans_ele = new double[size*size];
        ArrayList<double[]> ans = new ArrayList<>();

        int j = 0;
        FileReader in = null;

        try {
            in = new FileReader(path);
            int temp;

            while((temp = in.read()) != -1) {
                if(temp == 48 || temp == 49)
                {
                    ans_ele[j++] = temp-48;         //'0' or '1'
                }

                if(j == size*size){
                    j = 0;
                    ans.add(ans_ele.clone());
                }
            }
        } finally {
            if (in != null)
                in.close();
        }

        return ans.toArray(new double[0][0]);
    }

    /**
     * get all the ten digit data
     * @param ppath data path
     * @param size matrix size
     * @return all the ten digit data
     */
    public double[][][] getData(String ppath, int size) {
        double[][][] ans = new double[9][][];
        for (int i = 1; i < 10; i++) {
            String path = ppath + String.valueOf(i) + ".pat";
            try{
                ans[i-1] = readFile(path, size);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return ans;
    }
}
<file_sep>/SudoCool_jar/run.bat
@echo off

set JAVA=%JAVA_HOME%\bin\java
SET OPENCV=D:\opencv\build\java\x64;D:\opencv\build\x64\vc12\bin;/usr/local/share/OpenCV/java/
SET OPENCV2=./build/x64

java -Djava.library.path=%OPENCV2% -jar ./SudoCool.jar

pause

<file_sep>/SudoCool/src/team/sudocool/ImgWorks/Patternizor.java
package team.sudocool.ImgWorks;

import org.opencv.core.*;
import team.sudocool.ImgWorks.nImgProc.Cropper;
import team.sudocool.ImgWorks.nImgProc.Utils;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

import static org.opencv.core.Core.NORM_MINMAX;
import static org.opencv.core.CvType.CV_8U;
import static org.opencv.core.CvType.CV_8UC1;
import static org.opencv.core.CvType.CV_8UC3;
import static org.opencv.imgproc.Imgproc.*;

/**
 * Created by Heranort on 16/11/7.
 */

public class Patternizor {

    public static final int BLACK_BACKGROUND=THRESH_BINARY;
    public static final int WHITE_BACKGROUND=THRESH_BINARY_INV;

    private int COLOR;
    private int size;

    public Patternizor(int size, int COLOR){
        this.COLOR=COLOR;
        this.size=size;
    }
    /*@obselete
    public static int [][] Patternize(Mat img, int size, int color){

        Mat oimg=img.clone();
        if(img.empty())return new int[size][size];
        Imgproc.cvtColor(img, img, COLOR_RGB2GRAY);
        //这里默许了数独棋盘它是黑色的。
//        Imgproc.threshold(img, img, 127,255, color+THRESH_OTSU);

        Imgproc.adaptiveThreshold(img,img,255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 151,1);
        //why we should do this again?

        return pattern(oimg, Skeletonizor.Skeletonize(img), size);

    }

    public int [][] Patternize(Mat img){

        Mat iimg=img.clone();

        if(img.empty())return new int[size][size];

        //Core.normalize(img,img,0,255,NORM_MINMAX);

        Imgproc.cvtColor(img, img, COLOR_RGB2GRAY);

        Imgproc.threshold(img, img, 127,255, COLOR);//+THRESH_OTSU);
        //Utils.printMatrix(pattern(iimg, Skeletonizor.Skeletonize(img), size));
        //System.out.println();

        return pattern(iimg, Skeletonizor.Skeletonize(img), size);

    }
    */
    public int[][] Patternize28x28(Mat img){
        Mat iimg=img.clone();
        if(img.empty())return new int[size][size];
        Imgproc.threshold(img, img, 127,255, COLOR);//+THRESH_OTSU);
        return ezPattern28x28(iimg, img, size); //old: pattern28x28.
    }

    private static int[][] pattern28x28(Mat oimg, Mat img, int size){

        img=Cropper.ccrop(img);
        int[][] bimg = Cropper.crop(Utils.convertMat(img), 1);

        if(bimg.length==0)return new int[size][size];//all empty matrix.

        Mat _1=Utils.convertByteM(Cropper.nomalize(bimg,size,size));
        Imgproc.resize(_1,_1,new Size(28,28));

        //Utils.showResult(_1);
        return Utils.convertMat(_1);
    }

    private static int[][] ezPattern28x28(Mat oimg, Mat img, int size){
        int[][] bimg=Cropper.ezCrop(img);
        if(bimg.length==0)return new int[size][size];
        Mat _1=Utils.convertByteM(Cropper.nomalize(bimg,size,size));
        Imgproc.resize(_1,_1,new Size(28,28));
        return Utils.convertMat(_1);

    }

    private static double calcVal(int [][]img, int x1,int x2, int y1, int y2){
        int sum=0, wcount=0;
        for(int i=x1;i<x2;i++){
            for(int j=y1;j<y2;j++){
                sum++;
                if(img[j][i]==1)wcount++;
            }
        }
        return (double)wcount/sum;
    }
    private static int[][] divPattern(int[][]img, int iterate){
        int [][]rst=new int[iterate][iterate];
        int cols=img[0].length,rows=img.length;
        if(rows>=iterate && cols>=iterate){
            int hstep=cols/iterate;
            int vstep=rows/iterate;

            for(int i=0;i<iterate;i++){
                for(int j=0;j<iterate;j++){
                    int x=i*hstep,y=j*vstep;
                    double val=
                            calcVal(img,
                                    x,
                                    x+(i<iterate-1?hstep:(cols-x)),
                                    y,
                                    y+(j<iterate-1?vstep:(rows-y)));
                    rst[j][i]=val>0?1:0;
                }
            }

        }
        else{
            //error: img is not normalized.
        }
        //Utils.printMatrix(rst);
        //System.out.println();
        return rst;
    }
}
<file_sep>/SudoCool/src/team/sudocool/Eye/VideoCap.java
package team.sudocool.Eye;

/**
 * Created by Heranort on 16/11/15.
 */
import java.awt.image.BufferedImage;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.VideoCapture;
import org.opencv.imgproc.Imgproc;
import team.sudocool.ImgWorks.Recognizer;
import team.sudocool.ImgWorks.nImgProc.Utils;

import static org.opencv.highgui.Highgui.CV_CAP_PROP_FRAME_HEIGHT;
import static org.opencv.highgui.Highgui.CV_CAP_PROP_FRAME_WIDTH;
import static team.sudocool.Eye.EyeFrame.WIDTH;

public class VideoCap {
    static{
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    VideoCapture cap;
//    Recognizer R=new Recognizer();
    public Mat captured;

    VideoCap(int num){
        captured=new Mat();
        cap = new VideoCapture();
        cap.open(num);
        cap.set(CV_CAP_PROP_FRAME_WIDTH,640);
        cap.set(CV_CAP_PROP_FRAME_HEIGHT,480);

    }

    Mat getMat(){
        getOneFrame();
        return captured;
    }

//    BufferedImage getRectedFrame(int mode){
//        Mat mn=new Mat();
//        cap.read(mn);
//        captured=mn;
//        double rate=captured.size().width/captured.size().height;
//        Imgproc.resize(captured,captured, new Size(WIDTH, WIDTH/rate));
//        Mat img = mode == Eye.HANDWRITEING ? R.RecognizeOnly(captured) : R.RecognizeAndSolve(captured);
//        return Utils.Mat2BufferedImg(img, WIDTH);
//    }
    BufferedImage getOneFrame() {
        Mat mn=new Mat();
        cap.read(mn);
        captured=mn;
        double rate=captured.size().width/captured.size().height;
        Imgproc.resize(captured,captured, new Size(WIDTH, WIDTH/rate));
        return Utils.Mat2BufferedImg(captured.clone(), WIDTH); //mat2Img.getImage(mat2Img.mat);
    }
}
<file_sep>/SudoCool/src/team/sudocool/ImgWorks/EzGridSquareExtractor.java
package team.sudocool.ImgWorks;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.utils.Converters;
import team.sudocool.ImgWorks.nImgProc.Utils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.opencv.core.CvType.CV_8UC1;
import static org.opencv.imgproc.Imgproc.*;

/**
 * Created by Heranort on 16/11/16.
 */
public class EzGridSquareExtractor {

    public int SUDOKU_SIZE;

    private int outerBoundSizex;
    private int outerBoundSizey;
    public int scissorWidth;
    private MatOfPoint Bound=new MatOfPoint();
    private List<Mat> ExtractedCells = new ArrayList<>();
    public Mat ExtractedCellsGraph=new Mat();
    public MatOfPoint getBound(){return this.Bound;}//brings getOuterBoundContour() to passive.

    private Mat Transformed=null;
    public Mat getTransformed(){return Transformed;}
    public List<Mat> getExtractedCells(){return this.ExtractedCells;}

    public EzGridSquareExtractor(int sudokuSize, int sizex, int sizey, int scissor){
        this.SUDOKU_SIZE=sudokuSize;
        this.outerBoundSizex =sizex;
        this.outerBoundSizey =sizey;
        this.scissorWidth =scissor;
    }

    public void SetSize(int size){
        assert size>0;
        this.SUDOKU_SIZE=size;
        this.outerBoundSizex=size*50;
        this.outerBoundSizey=size*50;

    }

    public  MatOfPoint ExtractOuterBoundContour(Mat img){
        //Mat img2=img.clone();
        Mat img2=img.clone();

        double imgSizex=img.size().width,imgSizey=img.size().height;

        Imgproc.Laplacian(img2,img2,img2.depth());

        List<MatOfPoint> squares=new ArrayList<>();

        List<MatOfPoint> contours=new ArrayList<>();

        Mat hierarchy=new Mat();
        Imgproc.findContours(img2, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE,new Point(0,0));

        List<MatOfPoint> bound=contours.stream().filter(mp ->
        {
            //first filter out small pieces.
            if(Imgproc.contourArea(mp)<(imgSizex * imgSizey /15))//used: 9
                return false;

            //second, filter out non-rec things.
            MatOfPoint2f m2f=new MatOfPoint2f(),
                    apr=new MatOfPoint2f();

            m2f.fromList(mp.toList());
            double peri=Imgproc.arcLength(m2f, true);

            Imgproc.approxPolyDP(m2f, apr, 0.02*peri,true);

            if (apr.size().height!=4) return false;

            //third, filter out non-square things.
            //@modify 11 20
            List<Point>fourPoint=new ArrayList<Point>();
            fourPoint.addAll(apr.toList());
            fourPoint=Utils.clockwise(fourPoint);
            double d1=Utils.pointDist(fourPoint.get(0), fourPoint.get(1));
            double d2=Utils.pointDist(fourPoint.get(0), fourPoint.get(3));

            return  Math.abs(d2-d1)<0.2*d1;
        }).sorted((mp1,mp2)->
        {
            double amp1=Imgproc.contourArea(mp1),amp2=Imgproc.contourArea(mp2);
            if(amp1>amp2)return -1;
            else if(amp1==amp2)return 0;
            else return 1;
        }).collect(Collectors.toList());

        this.Bound=bound.size()>=1?bound.get(0):null;

        return this.Bound;
    }

    public Mat transform4(Mat img){

        MatOfPoint bound=getBound();
        if(bound==null)//return new Mat();//cowsay, change to original
            return img;

        MatOfPoint2f boundf=new MatOfPoint2f(), abound=new MatOfPoint2f();
        boundf.fromList(bound.toList());
        double peri=Imgproc.arcLength(boundf, true);
        approxPolyDP(boundf, abound, 0.02*peri, true);

        List<Point> lp=abound.toList();

        Comparator<Point>
                _x=( _1, _2)->
        {
            if (_1.x > _2.x) return 1;
            else if (_1.x == _2.x) return 0;
            else return -1;
        },
                _y=(_1, _2)->
                {
                    if(_1.y>_2.y)return 1;
                    else if (_1.y == _2.y)return 0;
                    else return -1;
                };

        List<Point> clockwised=Utils.clockwise(lp);

        //add points clockwisely.
        List<Point> dstl=new ArrayList<>();
        dstl.add(new Point(0,0));
        dstl.add(new Point(outerBoundSizex,0));
        dstl.add(new Point(outerBoundSizex, outerBoundSizey));
        dstl.add(new Point(0, outerBoundSizey));

        Mat perspectiveTransform = Imgproc.getPerspectiveTransform(Converters.vector_Point2f_to_Mat(clockwised),
                Converters.vector_Point2f_to_Mat(dstl));
        Mat rst=new Mat();
        Imgproc.warpPerspective(img, rst, perspectiveTransform, new Size(outerBoundSizex, outerBoundSizey));

        return rst;
    }

    public boolean Extract(Mat img){
        List<Mat>rst=new ArrayList<>();
        MatOfPoint bound= getBound();   //GetOuterBoundContour(img);
        if(bound==null)return false;
        Mat tr=transform4(img);

        this.Transformed=tr;
        double dx= outerBoundSizex /SUDOKU_SIZE,dy= outerBoundSizey /SUDOKU_SIZE;
        for(int y=0;y<SUDOKU_SIZE;y++){//0 to 8
            for(int x=0;x<SUDOKU_SIZE;x++){
                Rect r=new Rect((int)(x*dx+scissorWidth), (int)(y*dy+scissorWidth),(int)dx-2* scissorWidth,(int)dy-2* scissorWidth);
                rst.add(new Mat(tr, r));

            }
        }
        this.ExtractedCells=rst;
        return true;
    }

    private Patternizor P=new Patternizor(7, Patternizor.WHITE_BACKGROUND);

    public boolean Extract2(Mat img){
        Mat img2=img.clone();
        Imgproc.cvtColor(img,img2,Imgproc.COLOR_RGB2GRAY);//morph into gray pic
        Imgproc.adaptiveThreshold(img2,img2,255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 151,1);
        //the background should be in white.

        this.ExtractOuterBoundContour(img2);

        List<Mat>rst=new ArrayList<>();
        MatOfPoint bound= getBound();   //GetOuterBoundContour(img);
        if(bound==null)return false;
        Mat tr=transform4(img);

        Mat Out=Mat.zeros(tr.size(), CV_8UC1);

        double dx= outerBoundSizex /SUDOKU_SIZE,dy= outerBoundSizey /SUDOKU_SIZE;
        for(int y=0;y<SUDOKU_SIZE;y++){//0 to 8
            for(int x=0;x<SUDOKU_SIZE;x++){

                Rect r=new Rect((int)(x*dx+scissorWidth), (int)(y*dy+scissorWidth),(int)dx-2* scissorWidth,(int)dy-2* scissorWidth);

                Mat mask=new Mat(tr.size(), CV_8UC1, new Scalar(0));
                Core.rectangle(mask, new Point(r.x,r.y), new Point(r.x+r.width, r.y+r.height), new Scalar(255), Core.FILLED);
                tr.copyTo(Out, mask);

                Mat smallPiece=new Mat(tr,r);

                rst.add(smallPiece);

            }
        }
        this.ExtractedCells=rst;

        this.ExtractedCellsGraph=Out;

        return true;
    }

}

languages: Java Markdown Batchfile

repo_language: Java

repo_name: niwtr/SudoCool


text:
<file_sep>package file

import (
	"crypto/md5"
	"encoding/hex"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// File defines an struct for working around files.
type File struct {
	Path string
	Ext  string
	hash *string
}

func ofPath(path string) File {
	return File{Path: path, Ext: ext(path), hash: nil}
}

// Hash returns the MD5 hash of the contents of the file. The result is then
// memoized.
func (f *File) Hash() string {
	if f.hash == nil {
		md5, _ := f.makeMD5()
		f.hash = &md5
	}
	return *f.hash
}

func (f File) makeMD5() (string, error) {

	file, err := os.Open(f.Path)
	if err != nil {
		return "", err
	}

	defer file.Close()

	md5 := md5.New()
	if _, err := io.Copy(md5, file); err != nil {
		return "", err
	}

	return hex.EncodeToString(md5.Sum(nil)[:16]), nil
}

// Find recursively retrieves all files from the given directory, that match an
// optional list of extensions.
func Find(dir string, ext []string) []File {

	files := []File{}

	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			for _, r := range ext {
				if strings.HasSuffix(info.Name(), r) {
					files = append(files, ofPath(path))
				}
			}
		}
		return nil
	})

	return files
}

// Copy copies the file as the specified target.
func (f *File) Copy(target string) error {

	src, err := os.Open(f.Path)
	if err != nil {
		return err
	}
	defer src.Close()

	dst, err := os.Create(target)
	if err != nil {
		return err
	}
	defer dst.Close()

	if _, err = io.Copy(dst, src); err != nil {
		return err
	}

	if dst.Sync() != nil {
		return err
	}

	return nil
}

func ext(path string) string {

	const dot = "."

	if path == "" {
		return ""
	}

	xs := strings.Split(path, dot)
	size := len(xs)

	if size == 1 {
		return ""
	}

	return xs[size-1]
}
<file_sep>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/elrzn/digest-uniq-files/file"
)

var (
	ext     *string
	fromDir *string
	toDir   *string
)

func init() {
	ext = flag.String("ext", "", "a comma separated values indicating the file extensions to look for")
	fromDir = flag.String("dir", "", "the directory containing the files")
	toDir = flag.String("out", "out", "the output directory")
}

func main() {

	flag.Parse()

	dir := workDir(*fromDir)
	out := targetDir(dir, *toDir)
	os.Mkdir(out, 0777)

	files := file.Find(dir, strings.Split(*ext, ","))

	cnt := map[string]int{}
	for _, f := range files {
		target := out + "/" + f.Hash() + "." + f.Ext
		err := f.Copy(target)
		die(err)
		cnt[f.Hash()]++
	}

	fmt.Printf("\t%v\t%v\n", len(files), len(cnt))
}

func die(err error) {
	if err != nil {
		log.Fatal(err.Error())
	}
}

func workDir(fromDir string) string {

	// Get the current directory. This can be useful even when the user provided a
	// working directory, as there is a chance it isn't an absolute path.
	dir, err := os.Getwd()
	die(err)

	// User provided a working directory.
	if fromDir != "" {

		// Absolute path.
		// TODO Possible issues in Windows.
		if strings.HasPrefix(fromDir, "/") {
			return fromDir
		}

		// Relative path.
		return dir + "/" + fromDir
	}

	// Default to working directory.
	return dir
}

func targetDir(wdir, toDir string) string {
	if strings.HasPrefix(toDir, "/") {
		return toDir
	}
	return wdir + "/" + toDir
}
<file_sep>package file

import "testing"

// TODO Show actual values.
func TestNameExtension(t *testing.T) {

	e := ext("")
	if e != "" {
		t.Fatal("extension should be empty")
	}

	e = ext("foo")
	if e != "" {
		t.Fatal("extension should be empty")
	}

	e = ext("foo.bar")
	if e != "bar" {
		t.Fatal("bad ext")
	}

	e = ext("foo.bar.baz")
	if e != "baz" {
		t.Fatal("bad ext")
	}
}
<file_sep># digest-uniq-files

[![Go Report Card](https://goreportcard.com/badge/github.com/elrzn/digest-uniq-files)](https://goreportcard.com/report/github.com/elrzn/digest-uniq-files)
[![License](https://img.shields.io/github/license/elrzn/digest-uniq-files.svg)](https://github.com/elrzn/digest-uniq-files/blob/master/LICENSE)

## Synopsis

    $ go get github.com/elrzn/digest-uniq-files
    $ ls | grep -E '(jpg|png)$' | wc -l
        37
    $ digest-uniq-files -ext 'jpg,png'
        37  35
    $ ls out/ | wc -l
        35

branch_name: refs/heads/master

languages: Markdown Go

repo_language: Markdown

repo_name: elrzn/digest-uniq-files


text:
<repo_name>HalimKareh/Contacts<file_sep>/main/java/com/example/halimk/contactsapplication/ContactDetails.java
package com.example.halimk.contactsapplication;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Created by HalimK on 1/1/2017.
 */

public class ContactDetails extends Activity{

    Contact ContactDetails;
    private String mContactName, mContactNumber, mContactEmail;
    private int mContactImage;
    TextView details_name, details_number, details_email;
    ImageView details_image;
    Button backButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contact_details);

        details_image = (ImageView) findViewById(R.id.details_image);

        backButton = (Button) findViewById(R.id.backButton);

        details_name = (TextView) findViewById(R.id.details_name);
        details_email = (TextView) findViewById(R.id.details_email);
        details_number = (TextView) findViewById(R.id.details_number);

        Intent intent9 = new Intent();
        intent9 = getIntent();
        ContactDetails = (Contact) intent9.getSerializableExtra("details");

        mContactImage = ContactDetails.getImgId();
        mContactNumber = ContactDetails.getNumber();
        mContactName = ContactDetails.getName();
        mContactEmail = ContactDetails.getEmail();

        details_name.setText(mContactName);

        details_number.setText(mContactNumber);
        details_email.setText(mContactEmail);
        details_image.setImageResource(mContactImage);

        backButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

<file_sep>/main/java/com/example/halimk/contactsapplication/Data.java
package com.example.halimk.contactsapplication;

import android.app.Activity;
import android.content.Intent;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

public class Data extends Activity {

    EditText editName, editEmail, editNumber;
    ImageView contactImage;
    Button save;
    private int mGetImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.data);

        editName = (EditText) findViewById(R.id.editName);
        editEmail = (EditText) findViewById(R.id.editEmail);
        editNumber = (EditText) findViewById(R.id.editNumber);

        contactImage = (ImageView) findViewById(R.id.ContactImage);

        save = (Button) findViewById(R.id.save);

        contactImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent2 = new Intent(Data.this, MediaStore.Images.class);

                startActivityForResult(intent2, 1);
            }
        });

        save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Contact contacts = new Contact(editName.getText().toString(),
                        editEmail.getText().toString(), editNumber.getText().toString(),
                        mGetImage);

                Intent intent5 = new Intent(Data.this, ListContactsActivity.class);

                intent5.putExtra("data", contacts);
                setResult(2, intent5);

                finish();
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        mGetImage = data.getExtras().getInt("img", 1);
        contactImage.setImageResource(mGetImage);

    }
}
<file_sep>/README.md
# Contacts
A simple android third party contact application.

languages: Java Markdown

repo_name: HalimKareh/Contacts


text:
<repo_name>LittleWat/easy-mnist-kerasjs<file_sep>/README.md
# easy-mnist-kerasjs

This app predict the label of input mnist image whose size is 28x28.

You can try this app [here](https://easy-mnist-kerasjs.herokuapp.com/)!

## How to use

```
$ npm install
$ node index.js
```

You can access `http://localhost:8000` and upload your image file.

## Reference

  -  https://github.com/danimal141/file_upload_app

repo_name: LittleWat/easy-mnist-kerasjs


text:
<repo_name>diegoazd/diegoazd-assesment<file_sep>/README.md
Backend assesment
-----------------------

#### Requeriments:
  * Java 8
  * Python(Installed in /usr/bin/python)

##### Example transaction json:
`{"amount":1.23,"description":"<NAME>","date":"2018-12-10","user_id":345}`

##### The application has 4 commands

    add: Appends a transaction to the user
       ./application <user_id> add <transaction_json>

       Example:
       ./application 39855 add {"amount":1.23,"description":"<NAME>","date":"2018-12-10","user_id":345}

    show: Query for a user transaction
        ./application <user_id> <transaction_id>

        Example:
        ./application 39855 3c8cb834-f6f7-4612-9ab8-dadd92afd6a9

    list: Show all the user transactions
        ./application <user_id> list

         Example:
         ./application 39855 list

    sum: Sum user transactions
        ./application <user_id> sum

        Example:
        ./application 39855 sum

Execute the following command to compile and package the project

    ./gradlew build

To run the application test execute:
`./gradlew test`

We can see the coverage reports en $PWD/build/reports/jacoco/test/html/index.html
<file_sep>/src/main/java/com/playclip/test/transactions/command/TransactionCommand.java
package com.playclip.test.transactions.command;

import java.io.IOException;
import java.util.Map;

public interface TransactionCommand {

    void execute(Map<String, String> arguments) throws IOException;
}
<file_sep>/src/main/java/com/playclip/test/transactions/service/impl/TransactionServiceImpl.java
package com.playclip.test.transactions.service.impl;

import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.dto.UserTotal;
import com.playclip.test.transactions.factory.TransactionGatewayFactory;
import com.playclip.test.transactions.gateway.TransactionGateway;
import com.playclip.test.transactions.service.TransactionService;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Queue;
import java.util.UUID;

public class TransactionServiceImpl implements TransactionService {

    TransactionGateway transactionGateway;

    public TransactionServiceImpl() {
        transactionGateway = TransactionGatewayFactory.getGateway();
    }

    @Override
    public Transaction add(Long userId, Transaction transaction) throws IOException {
        transaction.setTransactionId(UUID.randomUUID());
        transactionGateway.add(userId, transaction);

        return transaction;
    }

    @Override
    public Transaction show(Long userId, UUID transactionId) throws IOException {
        return transactionGateway.show(userId, transactionId);
    }

    @Override
    public Queue<Transaction> list(Long userId) throws IOException {
        return transactionGateway.list(userId);
    }

    @Override
    public UserTotal sum(Long userId) throws IOException {
        Queue<Transaction> transactions = transactionGateway.list(userId);

        if(transactions == null) {
            return null;
        }
        return getUserTotal(transactions, userId);
    }

    private UserTotal getUserTotal(Queue<Transaction> transactions, Long userId) {
        BigDecimal total = BigDecimal.ZERO;
        while(!transactions.isEmpty()) {
            Transaction t = transactions.remove();
            total = total.add(t.getAmount());
        }

        return new UserTotal(userId, total);
    }
}
<file_sep>/src/main/java/com/playclip/test/transactions/dto/UserTotal.java
package com.playclip.test.transactions.dto;

import java.math.BigDecimal;

public class UserTotal {
    private Long userId;
    private BigDecimal  sum;

    public UserTotal(Long userId, BigDecimal sum) {
        this.userId = userId;
        this.sum = sum;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public BigDecimal getSum() {
        return sum;
    }
}
<file_sep>/src/test/java/com/playclip/test/transactions/factory/TransactionGatewayFileSystemTest.java
package com.playclip.test.transactions.factory;

import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.gateway.TransactionGateway;
import com.playclip.test.transactions.gateway.TransactionGatewayFileSystem;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.Queue;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Stream;

import static org.junit.Assert.*;

public class TransactionGatewayFileSystemTest {

    TransactionGateway transactionGateway;
    Long userId;

    @Before
    public void setup() {
        transactionGateway = new TransactionGatewayFileSystem();
        userId = new Random().nextLong();
    }

    @After
    public void teardown() {
        File file = new File(userId.toString());
        if(file.exists()) {
            file.delete();
        }

    }

    @Test
    public void shouldAddTransaction() throws IOException {
        Transaction transaction = new Transaction(userId,
                LocalDate.of(2015,12,21), BigDecimal.TEN,
                "description");
        transaction.setTransactionId(UUID.randomUUID());

        Transaction transaction2 = new Transaction(userId,
                LocalDate.of(2015,12,21), BigDecimal.ONE,
                "description2");
        transaction2.setTransactionId(UUID.randomUUID());
        transactionGateway.add(userId, transaction);
        transactionGateway.add(userId, transaction2);

        try (Stream<String> lines = Files.lines(Paths.get(userId.toString()))) {
            assertTrue(2l == lines.count());
        }
    }

    @Test
    public void shouldReturnNullWhenFileNotFound() throws IOException {
        assertNull(transactionGateway.show(userId, UUID.randomUUID()));
    }

    @Test
    public void shouldReturnNullWhenTransactionNotFound() throws IOException {
        Transaction transaction = new Transaction(userId,
                LocalDate.of(2015,12,21), BigDecimal.ONE,
                "description2");
        UUID uuid = UUID.randomUUID();
        transaction.setTransactionId(uuid);
        transactionGateway.add(userId, transaction);
        assertNull(transactionGateway.show(userId, UUID.randomUUID()));
    }

    @Test
    public void shouldReturnTransactionWhenFoundIt() throws IOException {
        UUID uuid = buildTransactions();

        Transaction response  = transactionGateway.show(userId, uuid);
        assertNotNull(response);
        assertEquals(uuid, response.getTransactionId());
        assertEquals(userId, response.getUserId());
        assertEquals(LocalDate.of(2015,12,21), response.getDate());
        assertEquals(BigDecimal.ONE, response.getAmount());
        assertEquals("description2", response.getDescription());
    }

    @Test
    public void shouldGetTransactionList() throws IOException {
        buildTransactions();
        Queue<Transaction> transactions = transactionGateway.list(userId);

        assertNotNull(transactions);
        assertTrue(transactions.size() == 2);
        Transaction transaction = transactions.remove();
        assertEquals(transaction.getDate(), LocalDate.of(2015,12,23));
        assertEquals(transaction.getAmount(), BigDecimal.TEN);
        assertEquals("description", transaction.getDescription());

        transaction = transactions.remove();
        assertEquals(transaction.getDate(), LocalDate.of(2015,12,21));
        assertEquals(transaction.getAmount(), BigDecimal.ONE);
        assertEquals("description2", transaction.getDescription());

        assertTrue(transactions.isEmpty());
    }

    @Test
    public void shouldReturnNullListWhenFileNotFound() throws IOException {
        assertNull(transactionGateway.list(userId));
    }

    private UUID buildTransactions() throws IOException {
        Transaction transaction = new Transaction(userId,
                LocalDate.of(2015,12,23), BigDecimal.TEN,
                "description");
        transaction.setTransactionId(UUID.randomUUID());

        Transaction transaction2 = new Transaction(userId,
                LocalDate.of(2015,12,21), BigDecimal.ONE,
                "description2");
        UUID uuid = UUID.randomUUID();
        transaction2.setTransactionId(uuid);
        transactionGateway.add(userId, transaction);
        transactionGateway.add(userId, transaction2);

        return uuid;
    }

}<file_sep>/build.gradle
buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.6.3'
        classpath 'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
        classpath 'org.ajoberstar:gradle-git:1.3.2'
        classpath 'org.kordamp.gradle:stats-gradle-plugin:0.2.0'
        classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
        classpath 'net.nemerosa:versioning:2.1.0'
    }
}

apply plugin: 'idea'
apply plugin: 'java'
apply plugin: 'com.github.kt3k.coveralls'
apply plugin: 'build-dashboard'
apply plugin: 'org.kordamp.gradle.stats'
apply plugin: 'com.github.ben-manes.versions'
apply from: 'gradle/publishing.gradle'
apply from: 'gradle/code-coverage.gradle'
apply from: 'gradle/code-quality.gradle'

archivesBaseName = 'diegoazd-assesment'
version = '1.0'

repositories {
    jcenter()
}

jar {
    manifest {
        attributes 'Main-Class': 'com.playclip.test.transactions.presenter.TransactionInput'
    }
    doFirst {
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}

dependencies {
    compile 'commons-io:commons-io:2.6'
    compile "com.beust:jcommander:1.71"
    compile 'com.fasterxml.jackson.core:jackson-databind:2.8.6'
    compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.6"

    testCompile 'junit:junit:4.12'
}

task sourcesJar(type: Jar) {
    group 'Build'
    description 'An archive of the source code'
    classifier 'sources'
    from sourceSets.main.allSource
}

jar.finalizedBy sourcesJar
test.finalizedBy jacocoTestReport

artifacts {
    sourcesJar
}

gradle.taskGraph.whenReady {
    def createIfNotExists = { File dir ->
        if (!dir.exists()) {
            dir.mkdirs()
        }
    }

    String sourceSetName = project.plugins.hasPlugin('groovy') ? 'groovy' : 'java'
    sourceSets.main[sourceSetName].srcDirs.each(createIfNotExists)
    sourceSets.test[sourceSetName].srcDirs.each(createIfNotExists)
    sourceSets.main.resources.srcDirs.each(createIfNotExists)
    sourceSets.test.resources.srcDirs.each(createIfNotExists)
}
<file_sep>/src/main/java/com/playclip/test/transactions/presenter/JsonPrinter.java
package com.playclip.test.transactions.presenter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.dto.UserTotal;

public class JsonPrinter {
    ObjectMapper mapper;

    public JsonPrinter() {
        mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }

    public void printTransactionJson(Transaction transaction) throws JsonProcessingException {
        System.out.println(mapper.writeValueAsString(transaction));
    }

    public void printTotalJson(UserTotal total) throws JsonProcessingException {
        System.out.println(mapper.writeValueAsString(total));
    }
}
<file_sep>/src/test/java/com/playclip/test/transactions/service/impl/TransactionServiceImplTest.java
package com.playclip.test.transactions.service.impl;

import com.playclip.test.transactions.config.StorageInterfaceType;
import com.playclip.test.transactions.config.StorageState;
import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.dto.UserTotal;
import com.playclip.test.transactions.service.TransactionService;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Queue;
import java.util.UUID;

import static org.junit.Assert.*;

public class TransactionServiceImplTest {
    TransactionService transactionService;

    @Before
    public void setUp() {
        StorageState.setStorageInterfaceType(StorageInterfaceType.MOCK);
        transactionService = new TransactionServiceImpl();
    }

    @Test
    public void shouldAddTransaction() throws IOException {
        Transaction transaction = new Transaction(1l, LocalDate.of(2018, 04,18),
                BigDecimal.valueOf(150.00d), "test description");
        Transaction response = transactionService.add(1l, transaction);
        assertNotNull(response.getTransactionId());
        assertEquals(transaction.getAmount(), response.getAmount());
        assertEquals(transaction.getDate(), response.getDate());
        assertEquals(transaction.getDescription(), response.getDescription());
        assertEquals(transaction.getUserId(), response.getUserId());
    }

    @Test
    public void shouldShowTransaction() throws IOException {
        Transaction transaction = transactionService.show(1l, UUID.randomUUID());
        assertNotNull(transaction);
    }

    @Test
    public void shouldNotFoundTransaction() throws IOException {
        Transaction transaction = transactionService.show(2l, UUID.randomUUID());
        assertNull(transaction);
    }

    @Test
    public void shouldListTransactions() throws IOException {
        Queue<Transaction> transactions = transactionService.list(1l);
        assertNotNull(transactions);
        Transaction transaction = transactions.remove();
        assertEquals(LocalDate.of(2018,04,17),
                transaction.getDate());
        assertEquals(BigDecimal.valueOf(150.00d), transaction.getAmount());
        assertEquals("test description", transaction.getDescription());

        transaction = transactions.remove();
        assertEquals(LocalDate.of(2018,04,16),
                transaction.getDate());
        assertEquals(BigDecimal.valueOf(152.00d), transaction.getAmount());
        assertEquals("test description3", transaction.getDescription());

        transaction = transactions.remove();
        assertEquals(LocalDate.of(2018,04,16),
                transaction.getDate());
        assertEquals(BigDecimal.valueOf(151.00d), transaction.getAmount());
        assertEquals("test description2", transaction.getDescription());
    }

    @Test
    public void shouldReturnNull() throws IOException {
        Queue<Transaction> transactions = transactionService.list(2l);
        assertNull(transactions);
    }

    @Test
    public void shouldGetTotalFromTransactions() throws IOException {
        UserTotal userTotal = transactionService.sum(1l);
        assertNotNull(userTotal);
        assertEquals(userTotal.getUserId(), Long.valueOf(1l));
        assertEquals(userTotal.getSum(), BigDecimal.valueOf(453.00d));
    }

    @Test
    public void shouldGetTotalZeroWhenUserNotFound() throws IOException {
        UserTotal userTotal = transactionService.sum(2l);
        assertNull(userTotal);
    }

}<file_sep>/src/main/java/com/playclip/test/transactions/gateway/TransactionGateway.java
package com.playclip.test.transactions.gateway;

import com.playclip.test.transactions.dto.Transaction;

import java.io.IOException;
import java.util.Queue;
import java.util.UUID;

public interface TransactionGateway {

    void add(Long userId, Transaction transaction) throws IOException;
    Transaction show(Long userId, UUID transactionId) throws IOException;
    Queue<Transaction> list(Long userId) throws IOException;
}
<file_sep>/src/test/java/com/playclip/test/transactions/dto/TransactionTest.java
package com.playclip.test.transactions.dto;

import org.junit.Before;
import org.junit.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.*;

public class TransactionTest {
    Transaction transaction;
    Map<String, String> map;

    @Before
    public void setup() {
        transaction = new Transaction();
        map = new HashMap<>();
    }

    @Test(expected = RuntimeException.class)
    public void shouldThrowExceptionWhenAmountIsNotPresent() {
       transaction.getTransactionFromMap(map);
    }

    @Test(expected = RuntimeException.class)
    public void shouldThrowExceptionWhenUserIdIsNotPresent() {
        map.put("amount", "120.00");
        transaction.getTransactionFromMap(map);
    }

    @Test(expected = RuntimeException.class)
    public void shouldThrowExceptionWhenDescriptionsNotPresent() {
        map.put("amount", "120.00");
        map.put("user_id", "1");
        transaction.getTransactionFromMap(map);
    }

    @Test(expected = RuntimeException.class)
    public void shouldThrowExceptionWhenDateNotPresent() {
        map.put("amount", "120.00");
        map.put("user_id", "1");
        map.put("description", "<NAME>");
        transaction.getTransactionFromMap(map);
    }

    @Test
    public void shouldReturnTransaction() {
        map.put("amount", "120.00");
        map.put("user_id", "1");
        map.put("description", "<NAME>");
        map.put("date", "2018-12-30");
        Transaction t = transaction.getTransactionFromMap(map);
        assertNotNull(t);
        assertEquals(new BigDecimal("120.00"), t.getAmount());
        assertEquals(Long.valueOf(1l), t.getUserId());
        assertEquals("<NAME>", t.getDescription());
        assertEquals(LocalDate.of(2018,12,30), t.getDate());
    }

}<file_sep>/src/main/java/com/playclip/test/transactions/gateway/TransactionGatewayMock.java
package com.playclip.test.transactions.gateway;

import com.playclip.test.transactions.dto.Transaction;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;

public class TransactionGatewayMock implements TransactionGateway {

    Queue<Transaction> transactions;

    public TransactionGatewayMock() {
        buildTransactions();
    }

    private void buildTransactions() {
        transactions = new PriorityQueue<>();
        Transaction transaction = new Transaction(1l, LocalDate.of(2018, 04,17),
                BigDecimal.valueOf(150.00d), "test description");
        transaction.setTransactionId(UUID.randomUUID());
        Transaction transaction2 = new Transaction(1l, LocalDate.of(2018, 04,16),
                BigDecimal.valueOf(151.00d), "test description2");
        transaction.setTransactionId(UUID.randomUUID());
        Transaction transaction3 = new Transaction(1l, LocalDate.of(2018, 04,16),
                BigDecimal.valueOf(152.00d), "test description3");
        transaction.setTransactionId(UUID.randomUUID());
        transactions.add(transaction);
        transactions.add(transaction2);
        transactions.add(transaction3);
    }

    @Override
    public void add(Long userId, Transaction transaction) throws IOException {
        if(userId.equals(3l)) {
            throw new IOException();
        }
    }

    @Override
    public Transaction show(Long userId, UUID transactionId) throws IOException {
        if(userId.equals(1l)) {
            return transactions.peek();
        }else if(userId.equals(3l)) {
            throw new IOException();
        }else {
          return null;
        }
    }

    @Override
    public Queue<Transaction> list(Long userId) throws IOException {
        if(userId.equals(1l)) {
            return this.transactions;
        }else if(userId.equals(3l)) {
            throw  new IOException();
        }else {
            return null;
        }
    }
}
<file_sep>/src/test/java/com/playclip/test/transactions/presenter/TransactionInputTest.java
package com.playclip.test.transactions.presenter;

import com.playclip.test.transactions.config.StorageInterfaceType;
import com.playclip.test.transactions.config.StorageState;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

public class TransactionInputTest {
    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
    private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();

    @Before
    public void setup() {
        StorageState.setStorageInterfaceType(StorageInterfaceType.MOCK);
        System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));
    }

    @After
    public void tearDown() {
        System.setOut(System.out);
        System.setErr(System.err);
    }

    @Test(expected = RuntimeException.class)
    public void shouldCallAddService() throws IOException {
        String[] input = {"-DuserId=1","-Dcmd=add"};
        TransactionInput.main(input);
    }

    @Test
    public void shouldPrintTransactionForAddOperation() throws IOException {
        String[] input = {"-DuserId=1","-Dcmd=add", "-Duser_id=50",
            "-Ddescription=Joes tacos", "-Damount=150.00",
            "-Ddate=2018-01-25"};
        TransactionInput.main(input);
        String json = "{\"amount\":150.00,\"description\":\"Joes tacos\",\"date\":\"2018-01-25\",\"userId\":50,\"transactionId\":";
        assertEquals(json, outContent.toString().substring(0,92));
    }

    @Test(expected = IOException.class)
    public void shouldThrowsIOExceptionInAddoperation() throws IOException {
        String[] input = {"-DuserId=3","-Dcmd=add", "-Duser_id=50",
                "-Ddescription=Joes tacos", "-Damount=150.00",
                "-Ddate=2018-01-25"};
        TransactionInput.main(input);
    }

    @Test
    public void shouldNotFoundTransaction() throws IOException {
        String[] input = {"-DuserId=2","-Dcmd=2299ce24-9eaf-417f-82d6-e57f93777dc4"};
        TransactionInput.main(input);
        assertEquals("Transaction not found\n", outContent.toString());
    }

    @Test
    public void shouldPrintTransactionForShowOperation() throws IOException {
        String[] input = {"-DuserId=1","-Dcmd=2299ce24-9eaf-417f-82d6-e57f93777dc4"};
        TransactionInput.main(input);
        String json = "{\"amount\":150.0,\"description\":\"test description\",\"date\":\"2018-04-17\",\"userId\":1,\"transactionId\":";
        assertEquals(json, outContent.toString().substring(0,96));
    }

    @Test(expected = IOException.class)
    public void shouldThrowExceptionForShow() throws IOException {
        String[] input = {"-DuserId=3","-Dcmd=2299ce24-9eaf-417f-82d6-e57f93777dc4"};
        TransactionInput.main(input);
    }

    @Test
    public void shouldPrintEmptyListWhenUserNotFound() throws IOException {
        String[] input = {"-DuserId=2","-Dcmd=list"};
        TransactionInput.main(input);
        assertEquals("[\n]\n", outContent.toString());
    }

    @Test
    public void shouldPrintTransactionList() throws IOException {
        String[] input = {"-DuserId=1","-Dcmd=list"};
        TransactionInput.main(input);
        assertNotEquals("[\n]\n", outContent.toString());
    }

    @Test(expected = IOException.class)
    public void shouldThrowExceptionForList() throws IOException {
        String[] input = {"-DuserId=3","-Dcmd=list"};
        TransactionInput.main(input);
    }

    @Test
    public void shouldPrintEmptyTransactionSum() throws IOException {
        String[] input = {"-DuserId=2","-Dcmd=sum"};
        TransactionInput.main(input);
        assertEquals("{}\n", outContent.toString());
    }

    @Test
    public void shouldPrintUserSumOfTransactions() throws IOException {
        String[] input = {"-DuserId=1","-Dcmd=sum"};
        TransactionInput.main(input);
        assertEquals("{\"userId\":1,\"sum\":453.0}\n", outContent.toString());
    }

    @Test(expected = IOException.class)
    public void shouldThowExceptionForSum() throws IOException {
        String[] input = {"-DuserId=3","-Dcmd=sum"};
        TransactionInput.main(input);
    }
}<file_sep>/settings.gradle
rootProject.name = 'diegoazd-assesment'
<file_sep>/application
#!/usr/bin/python

import sys
import os
from subprocess import call

total = len(sys.argv)
cmdargs = str(sys.argv)

if total < 3:
    print ("Invalid number arguments")
    os._exit(1)

userId = sys.argv[1]
cmd = sys.argv[2]

arg1='-DuserId='+userId
arg2='-Dcmd='+cmd
javaExec=["java", "-jar", "lib/diegoazd-assesment-1.0.jar", arg1, arg2]

if cmd == 'add' and total < 4:
    print ('Invalid numner arguments')
    os._exit(1)
elif cmd == 'add':
    javaExec.append(arg2)
    for i in range(3,len(sys.argv)):
        current=sys.argv[i].split(":")
        currentArg='-D'+current[0]+'='+current[1]
        javaExec.append(currentArg)

call(javaExec)

<file_sep>/gradle.properties
version=0.1.0-SNAPSHOT
group=com.payclip.assesment.transactions
sourceCompatibility=1.7
targetCompatibility=1.7

project_vendor=diegoazd---assesment
project_description=props.project_name
project_url=https://github.com/diegoazd/diegoazd---assesment
project_scm=https://github.com/diegoazd/diegoazd---assesment.git
project_issues=https://github.com/diegoazd/diegoazd---assesment/issues
project_bintray_repo=maven
project_bintray_org=diegoazd
<file_sep>/src/main/java/com/playclip/test/transactions/factory/TransactionGatewayFactory.java
package com.playclip.test.transactions.factory;

import com.playclip.test.transactions.config.StorageState;
import com.playclip.test.transactions.gateway.TransactionGateway;
import com.playclip.test.transactions.gateway.TransactionGatewayFileSystem;
import com.playclip.test.transactions.gateway.TransactionGatewayMock;

import static com.playclip.test.transactions.config.StorageInterfaceType.MOCK;

public class TransactionGatewayFactory {

    public static TransactionGateway getGateway() {
       if(StorageState.getStorageInterfaceType() == MOCK)
           return new TransactionGatewayMock();
        else
          return new TransactionGatewayFileSystem();
    }
}
<file_sep>/src/main/java/com/playclip/test/transactions/service/TransactionService.java
package com.playclip.test.transactions.service;

import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.dto.UserTotal;

import java.io.IOException;
import java.util.Queue;
import java.util.UUID;

public interface TransactionService {

    Transaction add(Long userId, Transaction transaction) throws IOException;
    Transaction show(Long userId, UUID transactionId) throws IOException;
    Queue<Transaction> list(Long userId) throws IOException;
    UserTotal sum(Long userId) throws IOException;

}
<file_sep>/src/main/java/com/playclip/test/transactions/command/impl/ListTransactionCommand.java
package com.playclip.test.transactions.command.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.playclip.test.transactions.command.TransactionCommand;
import com.playclip.test.transactions.dto.Transaction;
import com.playclip.test.transactions.presenter.JsonPrinter;
import com.playclip.test.transactions.service.TransactionService;
import com.playclip.test.transactions.service.impl.TransactionServiceImpl;

import java.io.IOException;
import java.util.Map;
import java.util.Queue;

public class ListTransactionCommand implements TransactionCommand {

    TransactionService transactionService;
    JsonPrinter jsonPrinter;

    public ListTransactionCommand() {
        transactionService = new TransactionServiceImpl();
        jsonPrinter = new JsonPrinter();
    }

    @Override
    public void execute(Map<String, String> arguments) throws IOException {
        System.out.println("[");
        printTranasctions(transactionService.list(Long.valueOf(arguments.get("userId"))));
        System.out.println("]");
    }

    private void printTranasctions(Queue<Transaction> transactions) throws JsonProcessingException {
        while (transactions != null && !transactions.isEmpty()) {
            Transaction t = transactions.remove();
            jsonPrinter.printTransactionJson(t);
        }
    }
}

languages: INI Java Markdown Gradle Python

repo_language: INI

repo_name: diegoazd/diegoazd-assesment


text:
<file_sep># study-notes
notes while working, saved in here for memory

# 测试标题
- 测试列表1
- 测试列表2
- 测试列表3

1. 测试有序列表1
2. 测试有序列表2
3. 测试有序列表3

>测试引用1
>>测试引用2
>>>测试引用3

[测试连接](https://www.github.com)

![测试图片](http://ww4.sinaimg.cn/bmiddle/aa397b7fjw1dzplsgpdw5j.jpg)
<file_sep>手势编辑器

该应用通过识别手势，编辑一个模型，可以精确拖动模型中暴露的点改变模型的样子。

该应用需要用到LeapMotion，请确保在运行该应用前LeapMotion安装正常并打开对应程序检测。

languages: Markdown Text

repo_name: tornadory/study-notes