package forge.deck.generate; import forge.AllZone; import forge.Card; import forge.CardList; import forge.MyRandom; import forge.error.ErrorViewer; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * <p>GenerateThemeDeck class.</p> * * @author Forge * @version $Id: $ */ public class GenerateThemeDeck { private BufferedReader in = null; /** * <p>Constructor for GenerateThemeDeck.</p> */ public GenerateThemeDeck() { } /** * <p>getThemeNames.</p> * * @return a {@link java.util.ArrayList} object. */ public ArrayList<String> getThemeNames() { ArrayList<String> ltNames = new ArrayList<String>(); File file = new File("res/quest/themes/"); if (!file.exists()) throw new RuntimeException("GenerateThemeDeck : getThemeNames error -- file not found -- filename is " + file.getAbsolutePath()); if (!file.isDirectory()) throw new RuntimeException("GenerateThemeDeck : getThemeNames error -- not a direcotry -- " + file.getAbsolutePath()); String[] fileList = file.list(); for (int i = 0; i < fileList.length; i++) { if (fileList[i].endsWith(".thm")) ltNames.add(fileList[i].substring(0, fileList[i].indexOf(".thm"))); } return ltNames; } /** * <p>getThemeDeck.</p> * * @param ThemeName a {@link java.lang.String} object. * @param Size a int. * @return a {@link forge.CardList} object. */ public CardList getThemeDeck(String ThemeName, int Size) { CardList tDeck = new CardList(); ArrayList<Grp> Groups = new ArrayList<Grp>(); Map<String, Integer> CardCounts = new HashMap<String, Integer>(); String s = ""; int BLandPercentage = 0; boolean Testing = false; // read theme file String tFileName = "res/quest/themes/" + ThemeName + ".thm"; File tFile = new File(tFileName); if (!tFile.exists()) throw new RuntimeException("GenerateThemeDeck : getThemeDeck -- file not found -- filename is " + tFile.getAbsolutePath()); try { in = new BufferedReader(new FileReader(tFile)); } catch (Exception ex) { ErrorViewer.showError(ex, "File \"%s\" exception", tFile.getAbsolutePath()); throw new RuntimeException("GenerateThemeDeck : getThemeDeck -- file exception -- filename is " + tFile.getPath()); } s = readLine(); while (!s.equals("End")) { if (s.startsWith("[Group")) { Grp G = new Grp(); String ss[] = s.replaceAll("[\\[\\]]", "").split(" "); for (int i = 0; i < ss.length; i++) { if (ss[i].startsWith("Percentage")) { String p = ss[i].substring("Percentage".length() + 1); G.Percentage = Integer.parseInt(p); } if (ss[i].startsWith("MaxCnt")) { String m = ss[i].substring("MaxCnt".length() + 1); G.MaxCnt = Integer.parseInt(m); } } s = readLine(); while (!s.equals("[/Group]")) { G.Cardnames.add(s); CardCounts.put(s, 0); s = readLine(); } Groups.add(G); } if (s.startsWith("BasicLandPercentage")) BLandPercentage = Integer.parseInt(s.substring("BasicLandPercentage".length() + 1)); if (s.equals("Testing")) Testing = true; s = readLine(); } try { in.close(); } catch (IOException ex) { ErrorViewer.showError(ex, "File \"%s\" exception", tFile.getAbsolutePath()); throw new RuntimeException("GenerateThemeDeck : getThemeDeck -- file exception -- filename is " + tFile.getPath()); } String tmpDeck = ""; // begin assigning cards to the deck Random r = MyRandom.random; for (int i = 0; i < Groups.size(); i++) { Grp G = Groups.get(i); float p = (float) ((float) G.Percentage * .01); int GrpCnt = (int) (p * (float) Size); int cnSize = G.Cardnames.size(); tmpDeck += "Group" + i + ":" + GrpCnt + "\n"; for (int j = 0; j < GrpCnt; j++) { s = G.Cardnames.get(r.nextInt(cnSize)); int lc = 0; while (CardCounts.get(s) >= G.MaxCnt || lc > Size) // don't keep looping forever { s = G.Cardnames.get(r.nextInt(cnSize)); lc++; } if (lc > Size) throw new RuntimeException("GenerateThemeDeck : getThemeDeck -- looped too much -- filename is " + tFile.getAbsolutePath()); int n = CardCounts.get(s); tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer())); CardCounts.put(s, n + 1); tmpDeck += s + "\n"; } } int numBLands = 0; if (BLandPercentage > 0) // if theme explicitly defines this { float p = (float) ((float) BLandPercentage * .01); numBLands = (int) (p * (float) Size); } else // otherwise, just fill in the rest of the deck with basic lands numBLands = Size - tDeck.size(); tmpDeck += "numBLands:" + numBLands + "\n"; if (numBLands > 0) // attempt to optimize basic land counts according to color representation { CCnt ClrCnts[] = {new CCnt("Plains", 0), new CCnt("Island", 0), new CCnt("Swamp", 0), new CCnt("Mountain", 0), new CCnt("Forest", 0)}; // count each instance of a color in mana costs // TODO: count hybrid mana differently? for (int i = 0; i < tDeck.size(); i++) { String mc = tDeck.get(i).getManaCost(); for (int j = 0; j < mc.length(); j++) { char c = mc.charAt(j); if (c == 'W') ClrCnts[0].Count++; else if (c == 'U') ClrCnts[1].Count++; else if (c == 'B') ClrCnts[2].Count++; else if (c == 'R') ClrCnts[3].Count++; else if (c == 'G') ClrCnts[4].Count++; } } int totalColor = 0; for (int i = 0; i < 5; i++) { totalColor += ClrCnts[i].Count; tmpDeck += ClrCnts[i].Color + ":" + ClrCnts[i].Count + "\n"; } tmpDeck += "totalColor:" + totalColor + "\n"; for (int i = 0; i < 5; i++) { if (ClrCnts[i].Count > 0) { // calculate number of lands for each color float p = (float) ClrCnts[i].Count / (float) totalColor; int nLand = (int) ((float) numBLands * p); tmpDeck += "numLand-" + ClrCnts[i].Color + ":" + nLand + "\n"; CardCounts.put(ClrCnts[i].Color, 2); for (int j = 0; j < nLand; j++) tDeck.add(AllZone.getCardFactory().getCard(ClrCnts[i].Color, AllZone.getComputerPlayer())); } } } tmpDeck += "DeckSize:" + tDeck.size() + "\n"; if (tDeck.size() < Size) { int diff = Size - tDeck.size(); for (int i = 0; i < diff; i++) { s = tDeck.get(r.nextInt(tDeck.size())).getName(); while (CardCounts.get(s) >= 4) s = tDeck.get(r.nextInt(tDeck.size())).getName(); int n = CardCounts.get(s); tDeck.add(AllZone.getCardFactory().getCard(s, AllZone.getComputerPlayer())); CardCounts.put(s, n + 1); tmpDeck += "Added:" + s + "\n"; } } else if (tDeck.size() > Size) { int diff = tDeck.size() - Size; for (int i = 0; i < diff; i++) { Card c = tDeck.get(r.nextInt(tDeck.size())); while (c.isBasicLand()) c = tDeck.get(r.nextInt(tDeck.size())); tDeck.remove(c); tmpDeck += "Removed:" + s + "\n"; } } tmpDeck += "DeckSize:" + tDeck.size() + "\n"; if (Testing) ErrorViewer.showError(tmpDeck); return tDeck; } /** * <p>readLine.</p> * * @return a {@link java.lang.String} object. */ private String readLine() { //makes the checked exception, into an unchecked runtime exception try { String s = in.readLine(); if (s != null) s = s.trim(); return s; } catch (Exception ex) { ErrorViewer.showError(ex); throw new RuntimeException("GenerateThemeDeck : readLine error"); } }//readLine(Card) class CCnt { public String Color; public int Count; public CCnt(String clr, int cnt) { Color = clr; Count = cnt; } } class Grp { public ArrayList<String> Cardnames = new ArrayList<String>(); public int MaxCnt; public int Percentage; } }