001package ball.game.sudoku;
002/*-
003 * ##########################################################################
004 * Game Applications and Utilities
005 * %%
006 * Copyright (C) 2010 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import lombok.NoArgsConstructor;
022
023import static lombok.AccessLevel.PROTECTED;
024
025/**
026 * Sudoku {@link Puzzle} solution {@link Rule}.
027 *
028 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
029 */
030@NoArgsConstructor(access = PROTECTED)
031public abstract class Rule {
032
033    /**
034     * Method to apply {@link.this} {@link Rule} to the argument
035     * {@link Puzzle}.
036     *
037     * @param   puzzle          The {@link Puzzle} to solve.
038     *
039     * @return  {@code true} if {@link.this} {@link Puzzle} is modified;
040     *          {@code false} otherwise.
041     */
042    public abstract boolean applyTo(Puzzle puzzle);
043
044    /**
045     * Method to get the count of solved {@link Cell}s.
046     *
047     * @param   iterable        The {@link Iterable} of {@link Cell}s.
048     *
049     * @return  The count of solved {@link Cell}s.
050     */
051    protected int count(Iterable<Cell> iterable) {
052        var count = 0;
053
054        for (var cell : iterable) {
055            if (cell.isSolved()) {
056                count += 1;
057            }
058        }
059
060        return count;
061    }
062
063    /**
064     * Method to get the sum of solved {@link Cell}s.
065     *
066     * @param   iterable        The {@link Iterable} of {@link Cell}s.
067     *
068     * @return  The sum of solved {@link Cell}s.
069     */
070    protected int sum(Iterable<Cell> iterable) {
071        var sum = 0;
072
073        for (var cell : iterable) {
074            if (cell.isSolved()) {
075                sum += cell.solution();
076            }
077        }
078
079        return sum;
080    }
081
082    /**
083     * Method to get the solved {@link Digits}.
084     *
085     * @param   iterable        The {@link Iterable} of {@link Cell}s.
086     *
087     * @return  The solved {@link Digits}.
088     */
089    protected Digits solved(Iterable<Cell> iterable) {
090        var digits = new Digits();
091
092        digits.clear();
093
094        for (var cell : iterable) {
095            if (cell.isSolved()) {
096                digits.addAll(cell);
097            }
098        }
099
100        return digits;
101    }
102}