I am tring to do a quiz app, there is a random flag and random 4 answers, one of them should be a correct answer and random 3.
For now I have only been able to random answers, but sometimes I have the same answer several times. Fails to random 3 different answers that will not repeat themselves and add to that the correct answer.
package com.example.guesstheflag;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.media.Image;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class startGame extends AppCompatActivity {
Integer[] flags ={
R.drawable.france,
R.drawable.england,
R.drawable.brazil,
R.drawable.belgium,
R.drawable.germany,
R.drawable.israel,
R.drawable.russia,
R.drawable.spain,
R.drawable.ukrain,
};
String []answers = {
"france",
"england",
"brazil",
"belgium",
"germany",
"israel",
"russia",
"spain",
"ukrain",
};
ListView listView;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_game);
listView = findViewById(R.id.myList);
imageView = findViewById(R.id.imagernd);
MyAdapter myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
//rnd image
Random rndImg = new Random();
int img = rndImg.nextInt(flags.length);
imageView.setImageResource(flags[img]);
}
// functions for answers list
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return 4;
}
@Override
public Object getItem(int i) {
return answers[i];
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
LayoutInflater layoutInflater = getLayoutInflater();
View row = layoutInflater.inflate(R.layout.custom, null);
TextView textView = row.findViewById(R.id.myText);
Random rnd = new Random();
int name = rnd.nextInt(answers.length);
textView.setText(answers[name]);
return row;
}
}
}
CodePudding user response:
You can use Collections.shuffle
.
List<String> answers = new ArrayList<>(Arrays.asList(
"france",
"england",
"brazil",
...
));
Map<String, Integer> flags = new HashMap<>(){{
put("france", R.drawable.france);
put("england", R.drawable.england);
put("brazil", R.drawable.brazil);
...
}};
At somewhere you want to shuffle the order of the ArrayList answers
:
Collections.shuffle(answers);
To set answer text of i
:
textView.setText(answers.get(i));
To set flag image of i
:
imageView.setImageResource(flags.get(answers.get(i)));
The point is not to draw an index randomly but to shuffle the ArrayList itself.
CodePudding user response:
Assumptions
- The correct answer for a
flags
array is equal to the same index in theanswers
array. - The random options (for an answer) also comes from the
answers
array.
Requirement
- For a given question, show 4 options. Out of which one has to be a correct answer and the other 3 has to be random options from the
answers
array. - The random options should not repeat
- The random options should not include the correct answer
Solution
You need to change your MyAdapter
class to be as follows
class MyAdapter extends BaseAdapter {
// Internal variable to hold the options
ArrayList<String> options = new ArrayList<>();
// Function to call which generates the random options
public void generateOptions(int correctAnswerIndex) {
// Clear the internal options variable
this.options = new ArrayList<>();
// Start a random generator
Random rnd = new Random();
// Keep generating options till we have 4 random selected options
while(this.options.size()<4) {
// Get a random number
int name = rnd.nextInt(answers.length);
// Check if random number is equal to correctAnswerIndex, if so, skip this round
if(name==correctAnswerIndex)
continue;
// Get the text for the random option
String optionText = answers[name];
// A flag to indicate if the correct answer should be used for this option position
int chanceToAddCorrectAnswer = 0;
// Generate a random number from 0 to 100
chanceToAddCorrectAnswer = rnd.nextInt(100);
// Check if the random number is an odd number (divisible by 3) and
// the correct answer is not already added to the options
if(chanceToAddCorrectAnswer%3==0 && this.options.indexOf(answers[correctAnswerIndex])==-1) {
// Add the correct answer
this.options.add(answers[correctAnswerIndex]);
}
else {
// Check if we already have 3 random options selected and the correct answer has not be added, then add it
if(this.options.size()==3 && this.options.indexOf(answers[correctAnswerIndex])==-1) {
// Add the correct answer as the last option
this.options.add(answers[correctAnswerIndex]);
}
else {
// Check if the current selected random option is already added or not
if (this.options.indexOf(optionText) == -1) {
// Add this random option
this.options.add(optionText);
}
}
}
}
}
@Override
public int getCount() {
return 4;
}
@Override
public Object getItem(int i) {
return this.options.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
LayoutInflater layoutInflater = getLayoutInflater();
View row = layoutInflater.inflate(R.layout.custom, null);
TextView textView = row.findViewById(R.id.myText);
textView.setText(this.options.get(i));
return row;
}
}
Than change the onCreate
method to do the following
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.myList);
imageView = findViewById(R.id.imagernd);
MyAdapter myAdapter = new MyAdapter();
listView.setAdapter(myAdapter);
//rnd image
Random rndImg = new Random();
int img = rndImg.nextInt(flags.length);
myAdapter.generateOptions(img); // Tell your adapter to generate random options
imageView.setImageResource(flags[img]);
}
Explanation
Basically you need to ensure the following conditions
- The correct answer is ignored while trying to pick random options from the
answers
array. - The options which are already picked are also ignored for consecutive random option.
In the above MyAdapter
we create a function to generate the random options called generateOptions
whenever this function is called it will generate the random number while ensuring the above conditions are met.
I have extensively commented the code but if you need more clarity, feel free to comment.
Suggestions
- Always include the list inside the Adapter class to ensure your dependency is internal and not external, since usually these are to be declared in their own files. (try to stay with one class per file)
- For a game, performance is key and I would suggest to generate all the list of questions and it's associated random options before the game starts. Allowing the user to go from question to question quickly. This is to be done in the
startGame
class with a function likeSetupGame
which is called in theonCreate
or whenever the user taps "Start" or "Restart"