All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sfuhrm.sudoku.client.Client Maven / Gradle / Ivy

There is a newer version: 5.0.1
Show newest version
/*
Sudoku - a fast Java Sudoku game creation library.
Copyright (C) 2017  Stephan Fuhrmann

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA  02110-1301, USA.
*/
package de.sfuhrm.sudoku.client;

import de.sfuhrm.sudoku.Creator;
import de.sfuhrm.sudoku.GameMatrix;
import de.sfuhrm.sudoku.Riddle;
import de.sfuhrm.sudoku.Solver;
import de.sfuhrm.sudoku.output.GameMatrixFormatter;
import de.sfuhrm.sudoku.output.LatexTableFormatter;
import de.sfuhrm.sudoku.output.MarkdownTableFormatter;
import de.sfuhrm.sudoku.output.PlainTextFormatter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

/**
 * A Sudoku CLI client.
 * @author Stephan Fuhrmann
 */
public class Client {

    /** The number of outputs to create. */
    @Option(name = "-n",
            aliases = {"-count"},
            usage = "The number of outputs to create")
    private int count = 1;

    /** The operator for the command. */
    enum Op {
        /** Create a fully filled Sudoku. */
        Full,
        /** Create a partly filled Sudoku for a riddle. */
        Riddle,
        /** Create a riddle and the solution. */
        Both,
        /** Solve a Sudoku. */
        Solve
    };

    /** The possible formatters that can be used. */
    enum Formatter {
        /** The {@link PlainTextFormatter}. */
        PlainText(PlainTextFormatter.class),
        /** The {@link MarkdownTableFormatter}. */
        MarkDownTable(MarkdownTableFormatter.class),
        /** The {@link LatexTableFormatter}. */
        LatexTable(LatexTableFormatter.class);

        /** The class of the formatter to create an instance of. */
        private final Class clazz;

        /** Constructs a new instance.
         * @param inClazz the class to construct formatters with.
         */
        Formatter(final Class inClazz) {
            this.clazz = inClazz;
        }

        /** Constructs a new instance of the formatter.
         * @return the freshly created formatter.
         */
        public GameMatrixFormatter newInstance() {
            try {
                return clazz.newInstance();
            } catch (IllegalAccessException | InstantiationException ex) {
                throw new IllegalStateException(ex);
            }
        }
    };

    /** The output format to use. */
    @Option(name = "-f",
            aliases = {"-format"},
            usage = "The output format to use")
    private Formatter format = Formatter.PlainText;

    /** The operation to perform. */
    @Option(name = "-e",
            aliases = {"-exec"},
            usage = "The operation to perform")
    private Op op = Op.Full;

    /** Show timing information. */
    @Option(name = "-t",
            aliases = {"-time"},
            usage = "Show timing information")
    private boolean timing;

    /** No output. */
    @Option(name = "-q",
            aliases = {"-quiet"},
            usage = "No output")
    private boolean quiet;

    /** Input file to read for solving. */
    @Option(name = "-i",
            aliases = {"-input"},
            usage = "Input file to read for solving")
    private Path input;

    /** Show this command line help. */
    @Option(name = "-h",
            aliases = {"-help"},
            usage = "Show this command line help")
    private boolean help;

    /** Solves a Sudoku.
     * @param formatter the formatter to print the solved Sudoku with.
     * @throws FileNotFoundException if the referenced file does not exist.
     * @throws IOException for other errors related to file IO.
     */
    private void solve(final GameMatrixFormatter formatter)
            throws FileNotFoundException, IOException {
        if (op == Op.Solve && input == null) {
            throw new IllegalArgumentException(
                    "Expecting input file for Solve");
        }

        List lines = Files.readAllLines(input);
        lines.stream()
                .filter(l -> !l.isEmpty())
                .map(l -> l.replaceAll("[_?.]", "0"))
                .collect(Collectors.toList());

        byte[][] data = GameMatrix.parse(lines.toArray(new String[0]));

        Riddle riddle = new Riddle();
        riddle.setAll(data);
        Solver solver = new Solver(riddle);
        List sollutions = solver.solve();
        if (!quiet) {
            for (Riddle r : sollutions) {
                System.out.println(formatter.format(r));
            }
        }
    }

    /**
     * Runs the client with the parsed command line options.
     * Performs the actions requested by the user.
     * @throws IOException if some IO goes wrong.
     */
    private void run() throws IOException {
        GameMatrixFormatter formatter = format.newInstance();
        long start = System.currentTimeMillis();

        if (!quiet) {
            System.out.print(formatter.documentStart());
        }

        if (op == Op.Solve) {
            solve(formatter);
        } else {
            for (int i = 0; i < count; i++) {
                GameMatrix matrix;
                Riddle riddle;
                switch (op) {
                    case Full:
                        matrix = Creator.createFull();
                        if (!quiet) {
                            System.out.print(formatter.format(matrix));
                        }
                        break;
                    case Riddle:
                        matrix = Creator.createFull();
                        riddle = Creator.createRiddle(matrix);
                        if (!quiet) {
                            System.out.print(formatter.format(riddle));
                        }
                        break;
                    case Both:
                        matrix = Creator.createFull();
                        riddle = Creator.createRiddle(matrix);
                        if (!quiet) {
                            System.out.print(formatter.format(riddle));
                        }
                        if (!quiet) {
                            System.out.print(formatter.format(matrix));
                        }
                        break;
                    default:
                        throw new IllegalStateException("Unhandled case "
                                + op);
                }
            }
        }
        long end = System.currentTimeMillis();
        if (!quiet) {
            System.out.print(formatter.documentEnd());
        }


        if (timing) {
            System.err.println("Took total of " + (end - start) + "ms");
            System.err.println("Each iteration took "
                    + (end - start) / count + "ms");
        }
    }

    /** The program entry for the client.
     * @param args the command line arguments.
     * @throws CmdLineException if command line parsing went wrong.
     * @throws IOException if file IO went wrong.
     */
    public static void main(final String[] args)
            throws CmdLineException, IOException {
        Client client = new Client();
        CmdLineParser parser = new CmdLineParser(client);
        parser.parseArgument(args);
        if (client.help) {
            parser.printUsage(System.out);
            return;
        }

        client.run();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy