001package ball.game.crossword;
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 java.util.List;
022import java.util.stream.Collectors;
023
024import static java.lang.Character.isDigit;
025import static java.lang.Character.isLetter;
026import static java.lang.Character.isLowerCase;
027import static java.lang.Character.toLowerCase;
028import static java.lang.Character.toUpperCase;
029
030/**
031 * Crossword {@link Puzzle} {@link Cell}.
032 *
033 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
034 */
035public class Cell implements Cloneable {
036    private static final Block BLOCK = new Block();
037
038    private final Boolean special;
039    private Character solution = null;
040
041    private Cell(boolean special) { this.special = special; }
042
043    private Cell(boolean special, Character solution) {
044        this(special);
045
046        setSolution(solution);
047    }
048
049    public boolean isBlock() { return false; }
050
051    public boolean isSpecial() { return special; }
052
053    public boolean isSolved() { return solution != null; }
054
055    public Character getSolution() { return solution; }
056    public void setSolution(Character solution) { this.solution = solution; }
057
058    @Override
059    public Cell clone() throws CloneNotSupportedException {
060        return (Cell) super.clone();
061    }
062
063    @Override
064    public String toString() {
065        char representation = '.';
066
067        if (isSolved()) {
068            representation = getSolution();
069
070            if (isSpecial()) {
071                representation = toLowerCase(representation);
072            } else {
073                representation = toUpperCase(representation);
074            }
075        }
076
077        return String.valueOf(representation);
078    }
079
080    /**
081     * Factory method to produce a {@link Cell}.
082     *
083     * @param   character       The {@code char} representing the
084     *                          {@link Cell}.
085     *
086     * @return  The new {@link Cell}.
087     */
088    public static Cell getInstance(char character) {
089        Cell cell = null;
090
091        switch (character) {
092        case '.':
093            cell = new Cell(false);
094            break;
095
096        case '#':
097            cell = BLOCK;
098            break;
099
100        default:
101            if (isLetter(character)) {
102                cell = new Cell(isLowerCase(character), toUpperCase(character));
103            } else if (isDigit(character)) {
104                cell = new Cell(false, character);
105            } else {
106                throw new IllegalArgumentException(String.valueOf(character));
107            }
108            break;
109        }
110
111        return cell;
112    }
113
114    public static List<Cell> getRowFrom(String line) {
115        return (line.chars()
116                .mapToObj(c -> getInstance((char) c))
117                .collect(Collectors.toList()));
118    }
119
120    private static class Block extends Cell {
121        private Block() { super(false); }
122
123        @Override
124        public boolean isBlock() { return true; }
125
126        @Override
127        public boolean isSolved() { return true; }
128
129        @Override
130        public void setSolution(Character solution) {
131            throw new IllegalStateException();
132        }
133
134        @Override
135        public String toString() { return "#"; }
136    }
137}