net.jetrix.filter.DownstackPuzzleGenerator.java Source code

Java tutorial

Introduction

Here is the source code for net.jetrix.filter.DownstackPuzzleGenerator.java

Source

/**
 * Jetrix TetriNET Server
 * Copyright (C) 2005  Emmanuel Bourg
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package net.jetrix.filter;

import static net.jetrix.config.Block.*;

import java.io.*;
import java.util.logging.*;
import java.util.*;

import net.jetrix.config.*;
import net.jetrix.*;
import org.apache.commons.lang.*;

/**
 * Puzzle generator supporting the puzzle format used by the 2ice server,
 * aka downstack.com. Each puzzle consists in two files, a <tt>.field</tt> file
 * containing the description of the field, and a <tt>.settings<tt> file
 * containing the game settings and the puzzle description. By default the
 * puzzle files are looked for in the <tt>data/puzzle</tt> sub directory, this
 * can be overridden by setting the <tt>path</tt> parameter.
 *
 * @since 0.3
 *
 * @author Emmanuel Bourg
 * @version $Revision$, $Date$
 */
public class DownstackPuzzleGenerator implements PuzzleGenerator {
    private Logger log = Logger.getLogger("net.jetrix");

    private static final String DEFAULT_PATH = "data/puzzle";

    /** The path where the puzzle fields and settings are located. */
    private String path = DEFAULT_PATH;

    /** The current level played. */
    private int level;

    /** The order or the specials used in the settings file. */
    public static final Block[] BLOCKS = { LEFTL, LEFTZ, SQUARE, RIGHTL, RIGHTZ, HALFCROSS, LINE };

    public void init(Configuration config) {
        path = config.getString("path", DEFAULT_PATH);
    }

    public Puzzle getNextPuzzle() {
        try {
            // load the field
            File[] levels = getLevels();
            File file = levels[level % levels.length];
            level = level + 1;

            Puzzle puzzle = loadPuzzle(new File(path),
                    file.getName().substring(0, file.getName().lastIndexOf(".")));
            puzzle.setKey(String.valueOf(level));

            return puzzle;
        } catch (IOException e) {
            log.log(Level.WARNING, e.getMessage(), e);
        }

        return null;
    }

    /**
     * Load a puzzle from the filesystem.
     * 
     * @param directory the directory containing the puzzle file
     * @param name      the name of the puzzle
     */
    protected Puzzle loadPuzzle(File directory, String name) throws IOException {
        Puzzle puzzle = new Puzzle();

        // load the field
        Field field = new Field();
        field.load(new File(directory, name + ".field").getAbsolutePath());
        puzzle.setField(field);

        // load the settings
        readSettings(puzzle, new File(directory, name + ".settings").getAbsolutePath());

        return puzzle;
    }

    /**
     * Find all levels in the puzzle directory.
     */
    protected File[] getLevels() {
        File directory = new File(path);
        File[] files = directory.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".field");
            }
        });

        // sort the list of files

        Arrays.sort(files, new FilenameComparator());

        return files;
    }

    /**
     * Parse the specified .settings file and update the puzzle.
     *
     * @param puzzle   the puzzle to update
     * @param filename the settings file to parse
     */
    private void readSettings(Puzzle puzzle, String filename) throws IOException {
        Settings settings = new Settings();
        puzzle.setSettings(settings);

        File file = new File(filename);
        if (file.exists()) {
            BufferedReader in = null;

            try {
                in = new BufferedReader(new FileReader(file));

                String line;
                while ((line = in.readLine()) != null) {
                    if (line.startsWith("NAME")) {
                        // parse the name and remove the leading and trailing quotes
                        String name = line.substring(4).trim();
                        if (name.startsWith("\"") && name.endsWith("\"")) {
                            name = name.substring(1, name.length() - 1);
                        }

                        puzzle.setName(name);
                    } else if (line.startsWith("COMMENT")) {
                        puzzle.setComment(line.substring(7).trim());
                    } else if (line.startsWith("DESIGNER")) {
                        puzzle.setAuthor(line.substring(8).trim());
                    } else if (line.startsWith("SPECIAL")) {
                        // parse the special occurancies
                        String[] values = StringUtils.split(line.substring(7).trim(), ' ');

                        Occurancy<Special> occurancy = new Occurancy<Special>();
                        for (Special special : Special.values()) {
                            occurancy.setOccurancy(special, Integer.parseInt(values[special.ordinal()]));
                        }
                        settings.setSpecialOccurancy(occurancy);
                    } else if (line.startsWith("BLOCK")) {
                        // parse the block occurancies
                        String[] values = StringUtils.split(line.substring(5).trim(), ' ');

                        // careful, it doesn't follow the standard order
                        Occurancy<Block> occurancy = new Occurancy<Block>();
                        for (int i = 0; i < BLOCKS.length; i++) {
                            occurancy.setOccurancy(BLOCKS[i], Integer.parseInt(values[i]));
                        }
                        settings.setBlockOccurancy(occurancy);
                    } else if (line.startsWith("SUDDENDEATHMSG")) {
                        settings.setSuddenDeathMessage(line.substring(14).trim());
                    } else if (line.startsWith("SUDDENDEATH")) {
                        String[] params = StringUtils.split(line.substring(11).trim(), ' ');

                        settings.setSuddenDeathTime(Integer.parseInt(params[0]));
                        settings.setSuddenDeathLinesAdded(Integer.parseInt(params[1]));
                        settings.setSuddenDeathDelay(Integer.parseInt(params[2]));
                    } else if (line.startsWith("RULES")) {
                        String[] params = StringUtils.split(line.substring(5).trim(), ' ');

                        settings.setStartingLevel(Integer.parseInt(params[0]));
                        settings.setLinesPerLevel(Integer.parseInt(params[1]));
                        settings.setLevelIncrease(Integer.parseInt(params[2]));
                        settings.setLinesPerSpecial(Integer.parseInt(params[3]));
                        settings.setSpecialAdded(Integer.parseInt(params[4]));
                        settings.setSpecialCapacity(Integer.parseInt(params[5]));
                        settings.setClassicRules(!"0".equals(params[6]));
                        settings.setAverageLevels(!"0".equals(params[7]));
                    }
                }
            } finally {
                // close the file
                if (in != null) {
                    in.close();
                }
            }
        }
    }
}