d2jsp
Log InRegister
d2jsp Forums > Off-Topic > Computers & IT > Programming & Development > Help Me Code Better
Prev1234Next
Add Reply New Topic New Poll
Member
Posts: 3,580
Joined: Aug 17 2013
Gold: 275.01
Feb 22 2014 12:50pm
Ok so I finally sat down and started working on my Simon Says game on Android. I feel like I'm going in a pretty bad direction atm but I'm not too commited yet. Here's what I've got so far, along with an explanation:

I run entirely off of a single Activity atm, is this bad?

Code
private int level;
private Vector<Integer> sequence;
private Vector<Integer> playerSequence;
private Random randomInt;
private boolean gameOver;
private TextView txtView;
private Button btnRed;
private Button btnGreen;
private Button btnBlue;
private Button btnYellow;


Most of these are self explanatory, the textview is for testing purposes atm though. My layouts are xml configured.

My onCreate():

Code
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
level = 0;
sequence = new Vector<Integer>();
playerSequence = new Vector<Integer>();
gameOver = false;
txtView = (TextView)findViewById(R.id.txtView);
btnRed = (Button)findViewById(R.id.redButton);
btnBlue = (Button)findViewById(R.id.blueButton);
btnGreen = (Button)findViewById(R.id.greenButton);
btnYellow = (Button)findViewById(R.id.yellowButton);
randomInt = new Random();
Toast toast = Toast.makeText(getApplicationContext(), "The Game Will Now Show You /n" +
"A Sequence Of Colors.", Toast.LENGTH_LONG);
toast.show();
startSequence();
}


An example of a button's onClick() function:

Code
public void onBtnRedClicked(View v){
playerSequence.add(1);
}


And my sequencing function:

Code
public void startSequence(){
++level;
sequence.clear();
while(sequence.size() != level){
int i = randomInt.nextInt(3) + 1;
Toast toast = Toast.makeText(getApplicationContext(), i, Toast.LENGTH_LONG);
toast.show();
sequence.add(i);
}
}


I don't have any design plan towards this, I'm just going in with my pants down basically. I think most of the above code makes sense, if there's any questions please ask.
My concern is the following; I'm not sure how to leave a window of time for the player to press the right sequence of buttons after the startSequence() function has run. I think once that's out of the way, a quick comparison of both vectors side by side to see if the integers match. If they all do, you run startSequence() again, if they don't well, gameOver, reset all variables, etc. Lmk what you guys think.

/e I messed up the text in the Toast at the beginning -.- Just noticed

This post was edited by SCVonSteroids on Feb 22 2014 12:54pm
Member
Posts: 11,637
Joined: Feb 2 2004
Gold: 434.84
Feb 22 2014 02:43pm
Avoid using Vector in Java. If you need a thread-safe Collection use Collections.synchronizedList or a CopyOnWriteArrayList. In your case you probably should just stick with an ArrayList because I doubt you need thread safety for this.
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Feb 22 2014 04:17pm
Quote (rockonkenshin @ Feb 22 2014 03:43pm)
Avoid using Vector in Java. If you need a thread-safe Collection use Collections.synchronizedList or a CopyOnWriteArrayList. In your case you probably should just stick with an ArrayList because I doubt you need thread safety for this.


Tacking onto rockonkenshin's point, the only place you ever really see usage of the Vector class in Java is in the classroom.

The main difference between ArrayList and Vector is that Vector is synchronized. You may think well doesn't that make it the better choice for concurrency? The answer is no. Vector is inherently flawed in the design of its syncronization. It synchronizes on every operation, creating a mess of problems when trying to access the list at the same time. For this reason, the class has been unofficially deprecated and rendered obsolete. It is only ever used by students, but very few students are ever told the difference between the two so they either use Vector because it is similar to vectors in C++, or it takes less characters to write so why not?

Member
Posts: 3,580
Joined: Aug 17 2013
Gold: 275.01
Feb 22 2014 08:15pm
Quote (rockonkenshin @ Feb 22 2014 05:43pm)
Avoid using Vector in Java. If you need a thread-safe Collection use Collections.synchronizedList or a CopyOnWriteArrayList. In your case you probably should just stick with an ArrayList because I doubt you need thread safety for this.


Quote (Minkomonster @ Feb 22 2014 07:17pm)
Tacking onto rockonkenshin's point, the only place you ever really see usage of the Vector class in Java is in the classroom.

The main difference between ArrayList and Vector is that Vector is synchronized. You may think well doesn't that make it the better choice for concurrency? The answer is no. Vector is inherently flawed in the design of its syncronization. It synchronizes on every operation, creating a mess of problems when trying to access the list at the same time. For this reason, the class has been unofficially deprecated and rendered obsolete. It is only ever used by students, but very few students are ever told the difference between the two so they either use Vector because it is similar to vectors in C++, or it takes less characters to write so why not?


I wasn't aware of this o.o Thanks for the headsup guys! I ended changed it up, still stuck on this problem:

Quote
My concern is the following; I'm not sure how to leave a window of time for the player to press the right sequence of buttons after the startSequence() function has run. I think once that's out of the way, a quick comparison of both vectors side by side to see if the integers match. If they all do, you run startSequence() again, if they don't well, gameOver, reset all variables, etc. Lmk what you guys think.
Member
Posts: 32,925
Joined: Jul 23 2006
Gold: 3,804.50
Feb 22 2014 08:18pm
Quote
My concern is the following; I'm not sure how to leave a window of time for the player to press the right sequence of buttons after the startSequence() function has run.


how about a timer?
Member
Posts: 3,580
Joined: Aug 17 2013
Gold: 275.01
Feb 22 2014 08:23pm
Quote (carteblanche @ Feb 22 2014 11:18pm)
how about a timer?


Yep, sounds about right, chaining everything together, from startSequence() all the way to a (theoretical) checkSequences() that'll either bring the game back to it's initial state, or keep looping back to startSequence() until the player's game over. Not working anymore on it today but I'll keep all of this in mind.
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Feb 22 2014 08:41pm
Using a Timer introduces the need for threading. After you show the user the sequence that needs to be pressed presumably you will have Simon sleep/wait a certain time before checking if the user entered them correctly. This means you need separate threads for Simon and the User. Otherwise if they are the same thread, if you sleep it, the User can't do anything. You are also going to need a thread for the UI. Because if you have the control logic and the UI on the same thread, when the Control sleeps, the UI can't update.

Fun fun fun with concurrency :)
Member
Posts: 3,580
Joined: Aug 17 2013
Gold: 275.01
Feb 23 2014 08:12am
Code
public void startSequence(View v){
btnStart.setEnabled(false);
++level;
sequence.clear();
while(sequence.size() < level){
handler.postDelayed(new Runnable(){
@Override
public void run(){
onSequence();
}
}, 1000);
}
startPlayerSequence(v);
}

public void startPlayerSequence(View v){
btnRed.setEnabled(true);
btnBlue.setEnabled(true);
btnGreen.setEnabled(true);
btnYellow.setEnabled(true);

handler.postDelayed(new Runnable(){
@Override
public void run(){
onPlayerSequence();
}
}, playerTimer);

compareSequences();
}

public void compareSequences(){
if(!Arrays.equals(sequence.toArray(), playerSequence.toArray())){
Toast toast = Toast.makeText(getApplicationContext(), "You entered the wrong sequence", Toast.LENGTH_LONG);
toast.show();
btnStart.setEnabled(true);
level = 0;
}else{
Toast toast = Toast.makeText(getApplicationContext(), "That's correct! Moving \n" +
"on to the next round!", Toast.LENGTH_LONG);
toast.show();
btnStart.setEnabled(true);
}
btnRed.setEnabled(false);
btnBlue.setEnabled(false);
btnGreen.setEnabled(false);
btnYellow.setEnabled(false);
}

public void onPlayerSequence(){
playerSequence.clear();
}

public void onSequence(){
Integer i = randomInt.nextInt(3) + 1;
txtView.setText(i.toString());
sequence.add(i);
}


This is the main logic of what I've added this morning. Buuuuut, when I hit Start Game, the app just goes unresponsive. Any ideas?
Member
Posts: 1,995
Joined: Jun 28 2006
Gold: 7.41
Feb 23 2014 02:42pm
This is rough psueodocode describing how you could use threads to handle the different components of your game.

Code
public class Simon implements Runnable
{
private Thread controlThread;

public Simon()
{
controlThread = new Thread(this);
controlThread,start();
}

public void run()
{
getSequence();

//sleep for 10 seconds
controlThread.sleep(10000);

checkSequence();
}
}


Code
public class Player implements Runnable
{
private Thread controlThread;

public Player()
{
controlThread = new Thread(this);
controlThread.start();
}

public void run()
{
getSequence();

}
}


Code
public class Game implements Runnable
{
private Thread controlThread;

public Game()
{
controlThread = new Thread(this);
controlThread.start();
}

public void run()
{
//Creates a new UI that spawns a new Thread that controls
//the repainting of the graphics to whichever object, presumably a Player,
//whenever either Simon or a Player makes a change to their state
UI ui = new UI();

//Creates a new Simon which spawns a new Thread to control Simon
//Simon will create a sequence and then wait a set time to check
Simon s = new Simon();

//Creates a new Player which spawns a new Thread controlled by the user
//presumably would generate the sequence and then post it back to the Game,
//which will then forward it to Simon
Player p = new Player();

}
}
Member
Posts: 3,580
Joined: Aug 17 2013
Gold: 275.01
Feb 28 2014 11:14am
Ok so after a bit of downtime I picked it up again and finished it off. I managed to get it running smoothly without seperating everything on it's own thread. Here's what I got

Code

private enum SimonColor{
RED(R.id.redButton),
GREEN(R.id.greenButton),
BLUE(R.id.blueButton),
YELLOW(R.id.yellowButton);

public final int id;

private SimonColor(int id){
this.id = id;
}

public static SimonColor getColorById(int id){
for(SimonColor sc:SimonColor.values()){
if(sc.id == id){
return sc;
}
}
return null;
}
}

private List<Button> gameButtons = new ArrayList<Button>();
private TextView txtView;
private TextView txtScore;
private Button btnStart;

private Handler handler = new Handler();
private static Random randomInt;
private ToneGenerator toneGen;

private enum State
{
PLAYER, SIMON;
}

private State state;
private int currentColorIndex;
private ArrayList<SimonColor> sequence = new ArrayList<SimonColor>();


These are what I ended up working with, and the logic to make it all work:

Code

public void startSimon(){
sequence.add(SimonColor.values()[randomInt.nextInt(SimonColor.values().length)]);
txtScore.setText("Score: " + Integer.toString(sequence.size()));
txtView.setText("Simon Says!");
playSequence();
}

public void playSequence(){
if(state == State.SIMON){
onColorPlayed(sequence.get(currentColorIndex));
currentColorIndex++;
if(currentColorIndex >= sequence.size()){
state = State.PLAYER;
txtView.setText("Your turn!");
btnStart.setEnabled(false);
activatePlayerButtons();
currentColorIndex = 0;
}else{
handler.postDelayed(new Runnable(){
@Override
public void run(){
playSequence();
}
}, 500);
}
}
}

public Boolean onColorPlayed(SimonColor colorPlayed){
if(sequence.get(currentColorIndex) == colorPlayed){
gameButtons.get(colorPlayed.ordinal()).setBackgroundResource(android.R.drawable.alert_dark_frame);
toneGen.playFreq((colorPlayed.ordinal() + 1)*300);
handler.postDelayed(new Runnable(){
@Override
public void run(){
resetButtons();
}
}, 250);
return true;
}else{
toneGen.playFreq(100);
return false;
}
}

public void onBtnClicked(View v){
SimonColor sc = SimonColor.getColorById(v.getId());
if(onColorPlayed(sc)){
currentColorIndex++;
if(currentColorIndex >= sequence.size()){
state = State.SIMON;
deactivatePlayerButtons();
currentColorIndex = 0;
handler.postDelayed(new Runnable(){
@Override
public void run(){
startSimon();
}
}, 250);
}
}
else{
resetGame();
}
}


I left out the redundant/obvious code so the post wouldn't get so fat. Let me know what you guys think!
Go Back To Programming & Development Topic List
Prev1234Next
Add Reply New Topic New Poll