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 */
021
022/**
023 * Sudoku {@link Cell}.
024 *
025 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
026 */
027public class Cell extends Digits {
028    private static final long serialVersionUID = -2029175165124035385L;
029
030    /**
031     * {@link #UNKNOWN} = {@value #UNKNOWN}
032     */
033    public static final String UNKNOWN = ".";
034
035    /**
036     * Sole constructor.  Construct with all possible digits.
037     */
038    public Cell() {
039        super();
040
041        addAll(ALL);
042    }
043
044    /**
045     * Method to determine if {@link.this} {@link Cell} is solved.
046     *
047     * @return  {@code true} if the {@link Cell} is solved; {@code false}
048     *          otherwise.
049     */
050    public boolean isSolved() { return (size() == 1); }
051
052    /**
053     * Method to get {@link.this} {@link Cell}'s solution.
054     *
055     * @return  The solution if the {@link Cell} is solved; {@code null}
056     *          otherwise.
057     */
058    public Integer solution() { return isSolved() ? first() : null; }
059
060    /**
061     * @return  The minimum value of the {@link Cell}.
062     *
063     * @see #first()
064     */
065    public Integer min() { return first(); }
066
067    /**
068     * @return  The maximum value of the {@link Cell}.
069     *
070     * @see #last()
071     */
072    public Integer max() { return last(); }
073
074    /**
075     * Method to determine if {@link.this} {@link Cell} is in the specified
076     * {@link Iterable} with {@code ==}.
077     *
078     * @param   iterable        The {@link Iterable} of {@link Object}s to
079     *                          test.
080     *
081     * @return  {@code true} if the {@link Cell} is in the {@link Iterable};
082     *          {@code false} otherwise.
083     */
084    public boolean isIn(Iterable<?> iterable) {
085        var isContained = false;
086
087        for (var object : iterable) {
088            isContained |= (this == object);
089
090            if (isContained) {
091                break;
092            }
093        }
094
095        return isContained;
096    }
097
098    @Override
099    public String toString() {
100        return isSolved() ? String.valueOf(first()) : toString(this);
101    }
102
103    private String toString(Cell cell) {
104        var buffer = new StringBuilder();
105
106        if (cell.size() == ALL.size()) {
107            buffer.append(".");
108        } else {
109            buffer.append("[");
110
111            for (int digit : cell) {
112                buffer.append(digit);
113            }
114
115            buffer.append("]");
116        }
117
118        return buffer.toString();
119    }
120}