// Copyright (C) 2007 Perdita Stevens // UNDER DEVELOPMENT - aka UNFINISHED. However, // This 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, or (at your option) // any later version. //package com.stevens_bradfield.game; import javax.swing.*; import javax.swing.border.Border; import java.applet.AudioClip; import java.awt.*; import java.awt.event.*; import java.util.*; // Import the JLayer classes import javazoom.jl.player.*; import javax.sound.sampled.*; import java.io.*; import java.net.URL; /** * @author perdita * */ public class Game extends JApplet implements ActionListener { private static int MAXMUSICS = 10; private int maximum; private boolean offerAddition; private boolean offerSubtraction; private JDialog settings; private JSlider maximumSlider; private JCheckBox additionBox; private JCheckBox subtractionBox; private String theSum; private String theAnswer; private int correctAnswer; private Music chosenSound; private Random r = new Random(); private boolean addition; private JTextField t1, question, answer; private LinkedList answerButtons; private LinkedList musicButtons; private Border empty; public void init() { //get default parameter values try { maximum = Integer.parseInt(getParameter("maximum")); } catch (NumberFormatException nfe) { System.out.println("parameter maximum was invalid, defaulting to 9"); maximum = 9; } String operators = getParameter("operators"); offerAddition = operators.contains("+"); offerSubtraction = operators.contains("-"); //give the user the chance to change settings userSetup(); } public void start() { //hmm, do we actually want to do anything at all here? } private void userSetup() { settings = new JDialog(); settings.setSize(300,300); //think about this settings.setVisible(true); JPanel settingsPanel = new JPanel(new GridLayout(4,1)); settings.add(settingsPanel); maximumSlider = new JSlider(JSlider.HORIZONTAL, 0, 29, maximum); maximumSlider.setMajorTickSpacing(5); maximumSlider.setMinorTickSpacing(1); maximumSlider.setPaintTicks(true); maximumSlider.setPaintLabels(true); settingsPanel.add(maximumSlider, BorderLayout.NORTH); additionBox = new JCheckBox("+", offerAddition); additionBox.setMnemonic(KeyEvent.VK_P); settingsPanel.add(additionBox); subtractionBox = new JCheckBox("-", offerSubtraction); subtractionBox.setMnemonic(KeyEvent.VK_S); settingsPanel.add(subtractionBox); JButton ok = new JButton("OK"); ok.setActionCommand("OK"); ok.addActionListener(this); settingsPanel.add(ok, BorderLayout.SOUTH); settings.setVisible(true); } private void getUserSettings() { System.out.println("getUserSettings"); maximum = maximumSlider.getValue(); offerAddition = additionBox.isSelected(); offerSubtraction = subtractionBox.isSelected(); settings.dispose(); //now set up the real screen addition = offerAddition; //start with an addition, if it's offered at all setupGui(); } //answer must be between 0 and maximum (inclusive) private void setupSum() { int i = r.nextInt(maximum+1); if (addition) { int j = r.nextInt(maximum+1 - i); theSum = Integer.toString(i) + " + " + Integer.toString(j) + " = "; correctAnswer = i + j; } else { //subtraction int k = r.nextInt(i+1); theSum = Integer.toString(i) + " - " + Integer.toString(k) + " = "; correctAnswer = i - k; } question.setText(theSum); answer.setText(""); setEnabledAnswerButtons(true); } private String[] getMusic() { String music = getParameter("music"); if (music == null) { System.out.println("music parameter null"); return null; } return music.split("\\s*,\\s*",MAXMUSICS); } private void setupGui() { System.out.println("setupGui"); setLayout(new BorderLayout()); //necessary? JPanel musicPanel = new JPanel(); //enough for 3 rows of buttons: otherwise, only the first gets space. //Right way to get decent layout for any reasonable music collection? //Not GridLayout since want buttons to get natural width. musicPanel.setPreferredSize(new Dimension(0,160)); musicButtons=new LinkedList(); String[] musics = getMusic(); if (musics == null) { System.out.println ("No music found!"); } else { for (int i=0; i < musics.length; i++) { String m = musics[i]; String label = m; if (label.endsWith(".mp3")) { label=label.substring(0,label.length()-4); } else { System.out.println ("Couldn't parse "+label); } MyJButton b = new MyJButton(label); musicButtons.add(b); b.setActionCommand(m); b.addActionListener(this); musicPanel.add(b); } } //operator choice if (offerAddition && offerSubtraction) { JPanel operatorChoicePanel = new JPanel(new GridLayout(0,1)); MyJButton plus = new MyJButton("+"); MyJButton minus = new MyJButton("-"); plus.setActionCommand("+"); plus.addActionListener(this); minus.setActionCommand("-"); minus.addActionListener(this); operatorChoicePanel.add(plus); operatorChoicePanel.add(minus); add(operatorChoicePanel, BorderLayout.WEST); } //the sum display question = new JTextField(); answer = new JTextField(); JPanel sumPanel = new JPanel(new GridLayout(1,2)); sumPanel.add(question); sumPanel.add(answer); question.setEditable(false); answer.setEditable(false); question.setFont(new Font(null, Font.PLAIN, 50)); answer.setFont(new Font(null, Font.PLAIN, 50)); question.setHorizontalAlignment(JTextField.RIGHT); empty = BorderFactory.createEmptyBorder(); question.setBorder(empty); answer.setBorder(empty); //answer buttons //bizarrely, JDK1.6 docs state that number of cols (10) only affects //layout when number of rows is 0!! So 0 it must be. JPanel answerButtonPanel = new JPanel(new GridLayout(0,10)); answerButtons=new LinkedList(); for (int i = 0; i <= maximum; i++) { String iAsString = Integer.toString(i); MyJButton b = new MyJButton(iAsString); b.setActionCommand(iAsString); b.addActionListener(this); answerButtons.add(b); answerButtonPanel.add(b); } add(musicPanel, BorderLayout.NORTH); add(sumPanel, BorderLayout.CENTER); add(answerButtonPanel, BorderLayout.SOUTH); validate(); setVisible(true); } public void actionPerformed(ActionEvent e) { String s = e.getActionCommand(); // What is the right way to do this? It's horrible having this all in one method // if s is "OK", it's the settings // if s is a number, it's an answer, // if it's +/- it's an operator change, // otherwise it's a tune try{ if (s=="OK") {getUserSettings();} else if (s=="+") {addition=true;} else if (s=="-") {addition=false;} else { int i = Integer.parseInt(s); if (checkAnswer(i)){ answer.setText(e.getActionCommand()); chosenSound.play(); //chosenSound will not be null! setEnabledMusicButtons(true); setEnabledAnswerButtons(false); } } } catch (NumberFormatException nfe) { try { chosenSound = new Music(getCodeBase(), "Music/"+s); } catch (Exception ce) { System.out.println (ce+" Failed to get music from "+s); return; } setEnabledMusicButtons(false); setupSum(); } } private void setEnabledAnswerButtons(boolean b) { for (MyJButton j : answerButtons) j.setEnabled(b); } private void setEnabledMusicButtons(boolean b) { for (MyJButton j : musicButtons) j.setEnabled(b); } public boolean checkAnswer (int ans){ return (ans == correctAnswer); } } class MyJButton extends JButton { public MyJButton(String s) { super(s); setFont(new Font(null, Font.PLAIN, 30)); } } class Music { private Player player; private InputStream is; URL url; public Music (URL codebase, String filename) { try { url = new URL(codebase.toString() + filename); } catch (Exception e) { System.out.println("failed to make URL, exception " + e.toString()); } } public void play() { try { InputStream is = url.openStream(); player = new Player(is); MusicThread mt = new MusicThread(); mt.start(); } catch(Exception e) { e.printStackTrace(); } } class MusicThread extends Thread { public void run() { try { player.play(); } catch( Exception e ) { e.printStackTrace(); } } } }