Hi,
I am trying to create a simon-says type game, where there are four icons of different colors. One icon lights up. The user clicks it. Next, a new icon lights up. The user clicks the sequence... etc, etc, etc.
Right now, the first round works. Unfortunately, the icons do not change after that point. Any help would be appreciated. Thanks!

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class IanSays extends JFrame implements ActionListener
{
    ImageIcon dark [] = {new ImageIcon("darkRed.png"),
                  new ImageIcon("darkBlue.png"), new ImageIcon("darkGreen.png"),
                                             new ImageIcon("darkYellow.png")};
    ImageIcon light [] = {new ImageIcon("red.png"),
                  new ImageIcon("blue.png"), new ImageIcon("green.png"),
                                             new ImageIcon("yellow.png")};
    JButton btns [] = {new JButton(dark[0]),new JButton(dark[1]),
                    new JButton(dark[2]), new JButton(dark[3])};
    
    Container cont;
    
    String code = "";
    
    String guess = "";
    
    int guesses = 0;
    
    public IanSays()
    {
        super("Ian Says");
        setSize(415,425);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        
        cont = getContentPane();
        cont.setLayout(null);
        
        for(int i = 0; i < btns.length; i++)
        {
            cont.add(btns[i]);
            btns[i].addActionListener(this);
            if(i<2)
            {
                btns[i].setBounds(i*200,0,200,200);
            }
            else
            {
                btns[i].setBounds((i-2)*200,200,200,200);
            }
        }
        play();
    }
    
    public void play()
    {
        System.out.println("play");
        for(int i = 0; i < code.length(); i++)
        {
            System.out.println(" in play loop");
            reset();
            
            cont.validate();
            
            try
            {
                Thread.sleep(250);
            }
            catch(Exception e){}
            
            char letter = code.toCharArray()[i];
            if(letter=='r')
            {
                System.out.println("    RED");
                btns[0].setIcon(light[0]);
            }
            if(letter=='b')
            {
                System.out.println("    BLUE");
                btns[1].setIcon(light[1]);
            }
            if(letter=='g')
            {
                System.out.println("    GREEN");
                btns[2].setIcon(light[2]);
            }
            if(letter=='y')
            {
                System.out.println("    YELLOW");
                btns[3].setIcon(light[3]);
            }
            
            cont.validate();

            try
            {
                Thread.sleep(250);
            }
            catch(Exception e){}
        }
        
        try
        {
            Thread.sleep(250);
        }
        catch(Exception e){}

        newColor();

        try
        {
            Thread.sleep(250);
        }
        catch(Exception e){}
        reset();
        System.out.println("    end of play");
    }
    
    public void newColor()
    {
        int rand = (int)(Math.random()*4);
        if(rand==0)
        {
            btns[rand].setIcon(light[rand]);
            code+="r";
        }
        if(rand==1)
        {
            btns[rand].setIcon(light[rand]);
            code+="b";
        }
        if(rand==2)
        {
            btns[rand].setIcon(light[rand]);
            code+="g";
        }
        if(rand==3)
        {
            btns[rand].setIcon(light[rand]);
            code+="y";
        }
        cont.validate();
    }
    
    public void reset()
    {
        for(int i = 0; i < btns.length; i++)
        {
            btns[i].setIcon(dark[i]);
        }
    }
    
    public void actionPerformed(ActionEvent e)
    {
        for(int i = 0; i < btns.length; i++)
        {
            if(e.getSource()==btns[i])
            {
                if(i==0)
                    guess+="r";
                if(i==1)
                    guess+="b";
                if(i==2)
                    guess+="g";
                if(i==3)
                    guess+="y";
                guesses++;
                break;
            }
        }
        
        String codeSeg = code.substring(0,guesses);
        System.out.println("code "+code);
        System.out.println("codeseg "+codeSeg);
        System.out.println("guess "+guess);
        if(!codeSeg.equals(guess))
        {
            System.out.println("lose!");
            //You Lose
        }
        else
        {
            if(guesses==code.length())
            {
                System.out.println("next rnd!");
                guess = "";
                guesses = 0;
                play();
            }
        }
    }
    
    public static void main (String[]args)
    {
        new IanSays();
    }
}

Try using Util.Random class for your random generator. Something like:

java.util.Random randomGen = new java.util.Random(System.currentTimeMillis());
int rand = randomGen.nextInt(4);

will create a new seeded random generator every time. I think this should be more stable than using Math.random() but let us know if that's not the problem.

Thanks, but I'm pretty sure that is not the problem. I think the problem has to do with the JFrame or JButtons not updating... Thanks!

Ah, sorry. I misunderstood what you meant. I think maybe you may need to call the repaint() method on the JFrame in the newColor() and reset() methods?

I tried that, but it did not work. The odd thing is that it works on the first round... but not any of the others.
Thanks for your help!

The odd thing is that it works on the first round... but not any of the others.

Do you mean that a full sequence of colours runs correctly the first time and then the next time the sequence is the same?

The first time, there is only one blink in the sequence. The next time, there are two blinks... and so on.
Only the first blink works correctly

Actually, the game is played like this:
*The computer lights up 1 button.
*All buttons go dark
*The player clicks the button the computer lit
*The computer re-lights the original button, and then all buttons go dark, and then the computer lights a new button.
*All buttons go dark.
*The player clicks the previously lit buttons in the correct order.
The process repeats until the player messes up.

Sorry Ghost, I was at work but now I'm at home and can look more closely at your code.

I'm thinking that your problem lies in the reading of the second (and subsequent possibly) characters to your code string. Instead of

char letter = code.toCharArray()[i];

try

char letter = code.charAt(i);

I'm not sure if this will make any difference but I can't see anything wrong with the rest of your code. Does

cont.validate();

repaint the buttons? Do they return to dark after the first round?

EDIT: I just compiled your code on my PC, it looks like the code follows what I press rather than the other way around. On the very first pass, code.length() = 0, so there is no code to guess. I pressed yellow, and the second pass had a code of 'y'.

Hey darkagn, I have a very similar problem to the one you guys have been discussing. My code worked 2 days ago, now it doesn't, and I don't quite understand what's changed.

What I want to do is real simple, when the user clicks a button, change the icon on the button (from an up arrow, to a down arrow). I simply set the icon inside the action command. However, I can't get the icon to switch on the display. I've debugged it, and the call's being made. I've tried repaint(), paintImmediatly(), validate(), everything I can think of.

The only difference in the code, that I can see, is that the button's nested into about 3 JPanels, where it was nested into two - but I don't see how that really matters.

I've tried other calls on the button, setting text, setting color, nothing seems to be updating the button display.

If you have any ideas as to what could be causing this, I'd really appreciate it. Any help is much appreciated.

Thanks, Bryant P.

bryantpurdin, highjacking post is considered rude so please in future don't do that.
Regarding your problem can you please post your code so we can have look at it?

Sorry, didn't mean to hijack - I just figured since we were both having the same exact problem, I'd let you know I was interested in anything you found out.

Unfortunately, I can't really paste my code. It's about 800 lines long, and I'm not really allowed to by my work.

What I can tell you though is that all I want to do is set the icon inside of the action command, and it's not working. I've tried setting the text, icon, background color - nothing seems to work. Nothing updates the display. I've even made these calls later, sequentially in the code, and the GUIs not getting updated.

It's really frustrating. I don't know how my code got this way. Any ideas on what's going on when you make calls to a component, and that component doesn't display the latest call?

use a version control system to keep track of changes, that way you can always revert back to an earlier version.

And oh, an 800 line class is almost always way too large and is just asking to be split into different classes among functional lines.

Sorry, didn't mean to hijack - I just figured since we were both having the same exact problem, I'd let you know I was interested in anything you found out.

Unfortunately, I can't really paste my code. It's about 800 lines long, and I'm not really allowed to by my work.

What I can tell you though is that all I want to do is set the icon inside of the action command, and it's not working. I've tried setting the text, icon, background color - nothing seems to work. Nothing updates the display. I've even made these calls later, sequentially in the code, and the GUIs not getting updated.

It's really frustrating. I don't know how my code got this way. Any ideas on what's going on when you make calls to a component, and that component doesn't display the latest call?

Then just post the action command code. I have a feeling you are not setting the properties on the button you think you are, since calling button.setIcon() in an action does generally update the icon without needing any other calls i.e.

private class ButtonAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            JButton btn = (JButton)e.getSource();
            btn.setIcon(btn.getIcon()==ico1 ? ico2 : ico1);
        }
    }

Will toggle between each icon as the button is pressed.

That's it. Thanks. Man, I knew something really wierd was going on with my code. It's been driving me carzy all day. I put in the call to "getSource()" and it worked. Your comment about not having the right button was correct, and it got me searching.

In my re-organizing of the GUI, I came to call the "buildBottomPanel()" method twice - this was where the button was being created. So, I had two copies of it.

Thank you so much for your help. You salvaged my day.

- Bryant P.

This article has been dead for over six months. Start a new discussion instead.