All pastes #502924 Raw Edit

Mine

public text v1 · immutable
·published 2007-05-22 17:41 UTC
rendered paste body
package net.sourceforge.ppf.plugin.countdownplugin;

import java.util.HashMap;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import net.sourceforge.ppf.PPF;
import net.sourceforge.ppf.PPFPlugin;
import net.sourceforge.ppf.util.PPFHelp;
;

public class CountdownPlugin extends PPFPlugin {

    private static final String PLUGIN_VERSION = "1.0";
    private static final String PLUGIN_ID = "COUNTDOWN";

    static final String commandCountdown = "countdown";

    public static final byte NOOP = 0;
    public static final byte ADD = 1;
    public static final byte SUBTRACT = 2;
    public static final byte MULTIPLY = 3;
    public static final byte DIVIDE = 4;

    private int _target = 0;
    private int[] _numbers = new int[0];
    private long _startTime = -1;
    private long _successTime = -1;
    private long _endTime = -1;
    private int _solutionCount = 0;
    private String _solution = null;
    private int maxNums = 6;
    private HashMap chosenNumbers = new HashMap();
    private HashMap channelCountdowns = new HashMap();

    private static final Random random = new Random();
    Timer timer;
    
    public CountdownPlugin() {
        // plugin version information
        setVersion(PLUGIN_VERSION);

        // build the help for this plugin
        setHelp(commandCountdown, new PPFHelp(commandCountdown, 
            "Start a countdown number puzzle", PPF.AUTH_NONE));
   	}

    // respond to channel messages
	public void onMessage(String channel, String sender, String login,
		String hostname, String message) {

        if(message.equalsIgnoreCase(commandCountdown)) {
            if(channelCountdowns.containsKey(channel)) {
                getBot().sendMessage(channel, "There is already a countdown in progress.");
            } else {
                int numLarges = random.nextInt(2) + 1;  // 1 or 2 large numbers
                int numSmalls = maxNums - numLarges;  // 4 or 5 small numbers
                int[] numbers = new int[maxNums];
                // get random large numbers
                for(int x = 0; x < numLarges; x++) {
                    int val = (random.nextInt(4) + 1) * 25;
                    if(chosenNumbers.containsKey(val +"")) {
                        x--;
                    } else {
                        numbers[x] = val;
                        chosenNumbers.put(val +"", null);
                    }
                }
                // get random small numbers
                for(int x = numLarges; x < maxNums; x++) {
                    int val = random.nextInt(10) + 1;
                    if(chosenNumbers.containsKey(val +"")) {
                        x--;
                    } else {
                        numbers[x] = val;
                        chosenNumbers.put(val +"", null);
                    }
                }
                // get target number
                int target = random.nextInt(899) + 100;
                // make number output string
                StringBuffer outNums = new StringBuffer();
                for(int x=0; x < numbers.length; x++) {
                    outNums.append(numbers[x]);
                    if(x < numbers.length-1) {
                        outNums.append(", ");
                    }
                }
                
                getBot().sendMessage(channel, numToWord(numLarges) +" large and "+ numToWord(numSmalls) +
                        " small numbers: "+ outNums.toString() +". Your target is "+ target +
                        ". You have thirty seconds, tick, tock, tick, tock...");
                
                TimedCountdownTask tct = new TimedCountdownTask(channel, numbers, target);
                timer = new Timer();
                timer.schedule(tct, 30 * 1000);  // 30 seconds
                channelCountdowns.put(channel, timer);
                play(numbers, target);
                chosenNumbers.clear();
            }
        }
    }

    private String numToWord(int num) {
        if(num == 1) {
            return "One";
        } else if(num == 2) {
            return "Two";
        } else if(num == 4) {
            return "four";
        } else if(num == 5) {
            return "five";
        }
        
        return num +"";  // fall through
    }
    /**
     * Take an array of numbers and the target to seek.
     */
    public void play(int[] numbers, int target) {
        _startTime = System.currentTimeMillis();
        _target = target;
        _numbers = numbers;
        _solutionCount = 0;
        _solution = null;
        findSubsets(numbers, new boolean[numbers.length]);
        _endTime = System.currentTimeMillis();
    }
    
    /**
     * Find all subsets of the numbers we have been given before then
     * using the permutate method to find all permutations of these.
     */
    private void findSubsets(int[] numbers, boolean[] members) {
        for (int setNum = 0; setNum < Math.pow(2, numbers.length); setNum++) {
            int size = 0;
            for (int i = 0; i < numbers.length; i++) {
                if (members[i]) {
                    size++;
                }
            }
            int[] playset = new int[size];
            
            // fill the array
            int pos = 0;
            for (int i = 0; i < numbers.length; i++) {
                if (members[i]) {
                    playset[pos] = numbers[i];
                    pos++;
                }
            }
            
            if (playset.length > 0) {
                permutate(playset, 0);
            }
            
            // jibble the bits to the next bit pattern
            int i = numbers.length - 1;
            while (i >= 0 && members[i]) {
                members[i] = false;
                i--;
            }
            if (i >= 0) {
                members[i] = true;
            }
        }
        
    }
    
    /**
     * Find all permutations of the numbers in the array.
     * For each permutation, we call the operate method.
     * (recursive)
     */
    private void permutate(int[] numbers, int k) {
        if (k == numbers.length) {
            operate(numbers, new byte[numbers.length - 1], 0);
        }
        else {
            for (int i = k; i < numbers.length; i++) {
                int temp = numbers[i];
                numbers[i] = numbers[k];
                numbers[k] = temp;
                permutate((int[])numbers.clone(), k + 1);
            }
        }
    }
    
    /**
     * Take a permutation of numbers and try all mathematical combinations.
     * Division is not allowed if there is a non-integral result.
     * If the target is found, then the solution is printed to the standard
     * output, using as few brackets as possible.
     * (recursive)
     */
    private void operate(int[] numbers, byte[] operands, int pos) {
        if (pos == numbers.length) {
            // calculate the answer
            int total = numbers[0];
            for (int i = 1; i < numbers.length; i++) {
                switch (operands[i - 1]) {
                    case ADD:
                        total += numbers[i];
                        break;
                    case SUBTRACT:
                        total -= numbers[i];
                        break;
                    case MULTIPLY:
                        total *= numbers[i];
                        break;
                    case DIVIDE:
                        if (total % numbers[i] != 0) {
                            // Can't allow non-integer divisions in this game!
                            return;
                        }
                        total /= numbers[i]; 
                        break;
                }
            }

            if (total == _target) {
                _solutionCount++;
                if (_solution == null) {
                    _successTime = System.currentTimeMillis();
                    StringBuffer solution = new StringBuffer();
                    byte lastOp = NOOP;
                    for (int i = 0; i < numbers.length - 1; i++) {
                        solution.append(numbers[i]);
                        if (lastOp != NOOP && operands[i] >= 3 && lastOp <= 2) {
                            solution.append(")");
                            solution.insert(0, "(");
                        }
                        lastOp = operands[i];
                        switch (operands[i]) {
                            case ADD:
                                solution.append(" + ");
                                break;
                            case SUBTRACT:
                                solution.append(" - ");
                                break;
                            case MULTIPLY:
                                solution.append("*");
                                break;
                            case DIVIDE:
                                solution.append("/");
                                break;
                        }
                    }
                    solution.append(numbers[numbers.length - 1]);
                    _solution = solution.toString();
                }
            }
        }
        else {
            if (pos == 0) {
                operate(numbers, operands, ++pos);
            }
            else {
                int newPos = pos + 1;
                int previousPos = pos - 1;
                operands[previousPos] = ADD;
                operate(numbers, operands, newPos);
                operands[previousPos] = SUBTRACT;
                operate(numbers, operands, newPos);
                operands[previousPos] = MULTIPLY;
                operate(numbers, operands, newPos);
                operands[previousPos] = DIVIDE;
                operate(numbers, operands, newPos);
            }
        }
    }
    
    public int getTarget() {
        return _target;
    }
    
    public int[] getNumbers() {
        return _numbers;
    }
    
    public long getStartTime() {
        return _startTime;
    }
    
    public long getSuccessTime() {
        return _successTime;
    }
    
    public long getEndTime() {
        return _endTime;
    }
    
    public int getSolutionCount() {
        return _solutionCount;
    }
    
    public String getSolution() {
        return _solution;
    }

    class TimedCountdownTask extends TimerTask {
        private String channel;
        private int[] numbers;
        private int target;
        
        public TimedCountdownTask(String channel, int[] numbers, int target) {
            this.channel = channel;
            this.numbers = numbers;
            this.target = target;
        }
        
        public void run() {
            getBot().sendMessage(channel, "Duh dum, duh dum, duh-da-da-dum! Your 30 seconds are up!");
            long t1 = getSuccessTime() - getStartTime();
            long t2 = getEndTime() - getStartTime();
            if(getSolutionCount() > 0) {
                getBot().sendMessage(channel, "I found a solution in approximately "+ t1 +
                        " milliseconds. I found all "+ t2 +" solutions in about "+ getSolutionCount() +" milliseconds.");
            } else {
                getBot().sendMessage(channel, "Oh dear, I can't solve that one.");
            }
            channelCountdowns.remove(channel);
        }
        
    }
}