001package ball.game.scrabble; 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 ball.util.stream.Combinations; 022import java.util.LinkedList; 023import java.util.List; 024import java.util.stream.Stream; 025import lombok.NoArgsConstructor; 026 027import static java.util.Objects.requireNonNull; 028import static java.util.stream.Collectors.toList; 029 030/** 031 * Scrabble {@link Rack}. 032 * 033 * {@bean.info} 034 * 035 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 036 */ 037@NoArgsConstructor 038public class Rack extends LinkedList<Tile> implements Cloneable { 039 private static final long serialVersionUID = -888967675416820573L; 040 041 private static final int CAPACITY = 7; 042 043 /** 044 * Method to determine if the {@link Rack} has any remaining capacity 045 * (should draw). 046 * 047 * @return {@code true} if the {@link Rack} contains less than its 048 * maximum capacity; {@code false} otherwise. 049 */ 050 public boolean hasCapacity() { return (size() < CAPACITY); } 051 052 /** 053 * Method to draw {@link Tile}s from a {@link Bag}. 054 * 055 * @param bag The {@link Bag} from which to draw. 056 * 057 * @return The {@link List} of {@link Tile}s drawn. 058 */ 059 public List<Tile> draw(Bag bag) { 060 int from = size(); 061 062 synchronized (bag) { 063 while (hasCapacity() && (! bag.isEmpty())) { 064 add(bag.draw()); 065 } 066 } 067 068 return subList(from, size()).stream().collect(toList()); 069 } 070 071 /** 072 * Method to get the {@link Stream} of all possible combinations. 073 * 074 * @return The {@link Stream} of combinations (each a {@link List} 075 * of {@link Tile}s). 076 * 077 * @see Combinations 078 */ 079 public Stream<List<Tile>> combinations() { 080 return Combinations.of(size(), 1, null, this); 081 } 082 083 @Override 084 public boolean add(Tile tile) { 085 if (! hasCapacity()) { 086 throw new IllegalStateException(); 087 } 088 089 requireNonNull(tile); 090 091 return super.add(tile); 092 } 093 094 @Override 095 public Tile[] toArray() { return toArray(new Tile[] { }); } 096 097 @Override 098 public Rack clone() { return (Rack) super.clone(); } 099}