001package ball.game.scrabble; 002/*- 003 * ########################################################################## 004 * Game Applications and Utilities 005 * $Id: Bag.java 5285 2020-02-05 04:23:21Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-game/trunk/src/main/java/ball/game/scrabble/Bag.java $ 007 * %% 008 * Copyright (C) 2010 - 2020 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import java.util.LinkedList; 024import java.util.Locale; 025import java.util.ResourceBundle; 026import java.util.SortedMap; 027import java.util.TreeMap; 028 029import static java.util.Collections.unmodifiableSortedMap; 030import static java.util.Objects.requireNonNull; 031 032/** 033 * Scrabble {@link Bag}. 034 * 035 * {@bean.info} 036 * 037 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 038 * @version $Revision: 5285 $ 039 */ 040public class Bag extends LinkedList<Tile> implements Cloneable { 041 private static final long serialVersionUID = -1363859449887620815L; 042 043 /** @serial */ private final Locale locale; 044 /** @serial */ private final SortedMap<Character,Integer> frequencies; 045 /** @serial */ private final SortedMap<Character,Integer> points; 046 047 /** 048 * No-argument constructor. 049 */ 050 public Bag() { this(Locale.ENGLISH); } 051 052 /** 053 * @param language The {@link Locale} language. 054 */ 055 public Bag(String language) { this(new Locale(language)); } 056 057 private Bag(Locale locale) { 058 super(); 059 060 this.locale = requireNonNull(locale, "locale"); 061 062 frequencies = unmodifiableSortedMap(new Frequencies()); 063 points = unmodifiableSortedMap(new Points()); 064 065 for (Character key : frequencies.keySet()) { 066 for (int i = 0, n = frequencies.get(key); i < n; i += 1) { 067 add(new Tile(key, points.get(key))); 068 } 069 } 070 } 071 072 /** 073 * Method to get the {@link Locale} for this {@link Bag}. 074 * 075 * @return The {@link Locale} for this {@link Bag}. 076 */ 077 public Locale getLocale() { return locale; } 078 079 /** 080 * Method to get the frequency {@link SortedMap} for this {@link Bag}. 081 * 082 * @return The frequency {@link SortedMap} for this {@link Bag}. 083 */ 084 public SortedMap<Character,Integer> frequencies() { return frequencies; } 085 086 /** 087 * Method to get the points {@link SortedMap} for this {@link Bag}. 088 * 089 * @return The points {@link SortedMap} for this {@link Bag}. 090 */ 091 public SortedMap<Character,Integer> points() { return points; } 092 093 /** 094 * Method to draw the next {@link Tile} in the {@link Bag}. 095 * 096 * @return The next {@link Tile}. 097 * 098 * @see #pollFirst() 099 */ 100 public Tile draw() { return pollFirst(); } 101 102 /** 103 * Method to draw a specific {@link Tile} from the {@link Bag}. 104 * 105 * @param letter The name of the requested {@link Tile}. 106 * 107 * @return The requested {@link Tile}; {@code null} if no matching 108 * {@link Tile} is available. 109 * 110 * @see #remove(int) 111 */ 112 public Tile draw(char letter) { 113 int index = -1; 114 115 for (int i = 0, n = size(); i < n; i += 1) { 116 if (get(i).getLetter() == letter) { 117 index = i; 118 break; 119 } 120 } 121 122 return (0 <= index && index < size()) ? remove(index) : null; 123 } 124 125 @Override 126 public Tile[] toArray() { return toArray(new Tile[] { }); } 127 128 @Override 129 public Bag clone() { return (Bag) super.clone(); } 130 131 private abstract class MapImpl extends TreeMap<Character,Integer> { 132 private static final long serialVersionUID = -9083183924608405152L; 133 134 protected MapImpl() { super(); } 135 136 protected void load(String name) { 137 ResourceBundle bundle = 138 ResourceBundle.getBundle(name, getLocale()); 139 140 for (String key : bundle.keySet()) { 141 put(key.charAt(0), Integer.valueOf(bundle.getString(key))); 142 } 143 } 144 } 145 146 private class Frequencies extends MapImpl implements Cloneable { 147 private static final long serialVersionUID = -5133821366028022851L; 148 149 public Frequencies() { 150 super(); 151 152 load(getClass().getName()); 153 } 154 155 @Override 156 public Frequencies clone() { return (Frequencies) super.clone(); } 157 } 158 159 private class Points extends MapImpl implements Cloneable { 160 private static final long serialVersionUID = 6515810713447725344L; 161 162 public Points() { 163 super(); 164 165 load(getClass().getName()); 166 } 167 168 @Override 169 public Points clone() { return (Points) super.clone(); } 170 } 171}