Android Studio - Random Number within range and no duplicates - android

I was working on a quiz app in Android studio..
I have 2 tables which are the solutions and questions..
In my game, I wanna create a random number in the range of this table without duplicates..
with this random number I update my questions and answers..
I try this code now to create numbers (with duplicates):
Random rand = new Random();
n = rand.nextInt(QuestionLibrary.mChoices.length) + 1;
here is the photo of my game

If you don't have much numbers, you can make a collection with all of them, shuffle and then take one by one from it.
If you have a lot of numbers, then better aproach would be to make an empty collection and add every number that random function returns if it already does not exists. If number already exists, get another one, and so on.
Please read more here:
https://stackoverflow.com/a/4040014/7270175
EDIT: added code snippet that reproduces MAX number of different random numbers without duplicates.
private static int MAX = 1000;
private static boolean[] numbers;
public static void main(String[] args) {
Random generator = new Random();
numbers = new boolean[MAX + 1];
for (int i = 0; i < MAX; i++) {
System.out.println(getRandomWithoutDuplicates(generator));
}
}
private static int getRandomWithoutDuplicates(Random generator) {
int randomNum;
do {
randomNum = generator.nextInt(MAX);
} while (numbers[randomNum]);
numbers[randomNum] = true;
return randomNum;
}

Related

Non Repeated Extremly Secure Random Number Generator?

I want to genrate 5 digit extremly secure random numbers for some products verifications which should be always unique, their no limits how many times in day or how many times in a week i've to put this request for new generation of manual codes, and it can be in range of 1k - 20k, The main requirement is about to manual codes should have to be always UNIQUE(NON REPEATED) otherwise their would be a big clash.
so please assit me a better and secured way to genrated 5 digit unique codes,
Any recommendations would be very helpful.
for now i am using this reffrence :
private static final Random random = new Random();
private static final String CHARS = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ234567890!##$";
public static String getToken(int length) {
StringBuilder token = new StringBuilder(length);
for (int i = 0; i < length; i++) {
token.append(CHARS.charAt(random.nextInt(CHARS.length())));
}
return token.toString();
}

Creating resource reference ints programmatically

I am building a quiz app with questions in a string resource, as well as an answer. They are formatted by numbers like so:
<string name="ques1">What color is the sky?</string>
<string name="ques2">What sound does a cow make?</string>
The answers are also strings corresponding to the same number as the questions:
<string name="ans1">Blue</string>
<string name="ans2">Moo</string>
I have created a QA class for holding both a question and the answer, as well as the user's response from an EditText. At the "loading" of my app these classes are created and filled by reading from the strings resource.
I can programmatically enter these no problem, it is a lot of copy pasting but it will get the job done:
QA.setQuestion(getString(R.string.ques1));
QA.setAnswer(getString(R.string.ans1));
quizList.add(QA);
QA.setQuestion(getString(R.string.ques2));
QA.setAnswer(getString(R.string.ans2));
quizList.add(QA);
etc...
The problem is that I want to be able to add questions and answers to the xml at any time without having to add yet another repetition of the above method. What I want to do is essentially this:
String refBase = "R.string."
String ans = "ans";
String ques = "ques";
int numOfQues = 25; //only change when questions are added or removed
for (int i = 0; i < numOfQues; i++)
{
String referenceQ = refBase + ques + i;
String referenceA = refBase + ans + i;
QA.setQuestion(getString(referenceQ));
QA.setAnswer(getString(referenceA));
quizList.add(QA);
}
I cannot cast a string to an int like this obviously, but I am wondering if there is a way to implement a reference "builder", where I don't have to repeat many lines of code just to read another string with the same name but incremented number.
I understand that I can also just create an array.xml with one for questions and one for answers, making sure their position in each array corresponds. This would be easiest I think, but I guess I am wondering if it is possible to create references to string values through the code like my example?
You can use this method to get the question or answer String by its resource name:
String getQAString(boolean isQuestion, int index) {
String prefix = isQuestion? "ques" : "ans";
int resId = getResources().getIdentifier(prefix + index, "string", getPackageName());
return resId != 0? getString(resId) : "";
}
The loop to add questions and answers (assume they start from 1 and end at 25):
int numOfQues = 25;
for (int i = 1; i <= numOfQues; i++) {
String referenceQ = getQAString(true, i);
String referenceA = getQAString(false, i);
QA.setQuestion(referenceQ);
QA.setAnswer(referenceA);
quizList.add(QA);
}

payUmoney integration is giving an error

After logging in, it's generating a hash value, but still giving error "Some problem occurred! try again".
PayUmoneySdkInitilizer.PaymentParam.Builder builder =
new PayUmoneySdkInitilizer.PaymentParam.Builder();
builder.setAmount(10.0)
.setTnxId("0nf7" + System.currentTimeMillis())
.setPhone(<My phone>)
.setProductName("product_name")
.setFirstName(<My Name>)
.setEmail(<My email>)
.setsUrl("https://www.payumoney.com/mobileapp/payumoney/success.php")
.setfUrl("https://www.payumoney.com/mobileapp/payumoney/failure.php")
.setUdf1("").setUdf2("").setUdf3("").setUdf4("").setUdf5("")
.setIsDebug(false)
.setKey(<mykey>)
.setMerchantId(<my debug merchant id>);
String tnxId="0nf7" + System.currentTimeMillis();
PayUmoneySdkInitilizer.PaymentParam paymentParam = builder.build();
String hashSequence = "<...>|"+tnxId+"|10.0|product_name|<My name>|<My email>|||||||||||salt";
String serverCalculatedHash= hashCal("SHA-512", hashSequence);
Toast.makeText(getApplicationContext(),
serverCalculatedHash, Toast.LENGTH_SHORT).show();
paymentParam.setMerchantHash(serverCalculatedHash);
// calculateServerSideHashAndInitiatePayment(paymentParam);
PayUmoneySdkInitilizer.startPaymentActivityForResult(TrayActivity.this, paymentParam);
public static String hashCal(String type, String str) {
byte[] hashseq = str.getBytes();
StringBuffer hexString = new StringBuffer();
try {
MessageDigest algorithm = MessageDigest.getInstance(type);
algorithm.reset();
algorithm.update(hashseq);
byte messageDigest[] = algorithm.digest();
for (int i = 0; i<messageDigest.length; i++) {
String hex = Integer.toHexString(0xFF &messageDigest[i]);
if (hex.length() == 1) { hexString.append("0"); }
hexString.append(hex);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} return hexString.toString();
}
You use in the code:
.setTnxId("0nf7" + System.currentTimeMillis())
And then later:
String tnxId="0nf7" + System.currentTimeMillis();
Probably not the only problem, but do you really want to use two different values for these (the time may change between the two calls)? Didn't you want the same tnxId in both cases?
TransactionIdProvider.java:
import java.util.Locale;
public class TransactionIdProvider {
private final static String DEFAULT_PREFIX = "ID";
// Convenient prime number for incrementing the counter
private final static long ID_ADD = 0xF0AD; // "f*ck off and die"
// 64b counter with non-trivial start value
private static long idCounter = 0x0101F00DDEADBEEFL;
/**
* Returns ID consisting of prefix string and 64b counter interleaved
* with 32b per-4s-timestamp.
*
* May produce identical ID (collision) when:
* 1) class is reloaded within 4s
* (to fix: serialize "idCounter" upon shutdown/restart of VM, or
* modify prefix per start of VM)
* 2) more than 2^64 IDs are requested within 4s (no fix, unexpected)
* 3) more than 2^64 IDs are requested after cca. 550 years.
* (no fix, unexpected)
* 4) more than one static instance of TransactionIdProvider is used
* (two or more VMs running the app) (to fix put different prefix in
* every VM/server running this)
*
* Length of returned ID is prefix.length() + 24 alphanumeric symbols.
*/
public static synchronized String getNewId(final String prefix) {
idCounter += ID_ADD; // increment counter
// get 32b timestamp per ~4s (millis/4096) (good for ~550 years)
final int timeStamp = (int)(System.currentTimeMillis()>>12);
final int idPart1 = (int)(idCounter>>32);
final int idPart2 = (int)(idCounter);
return String.format(Locale.US, "%s%08X%08X%08X",
prefix, idPart1, timeStamp, idPart2);
}
public static String getNewId() {
return getNewId(DEFAULT_PREFIX);
}
}
Not sure how much usable is this one, and if the ID may be so long. Feel free to use/modify it any way you wish.
Also I wonder, whether I didn't forget about something important, but can't recall anything.
The security aspect of this one is still quite weak, as within 4s time span the ID will be like simple addition, but at least it's not producing 1, 2, 3... series.
Did found some SDK docs, looks like txnId may be 25 chars long, so you have 1 char for prefix only. Or cut down on timestamp, using %07X in format and masking value with 0x0FFFFFFF, that would make it repeat every ~34 years -> 2 letters for prefix. Or change counter to 32b int, should be still more than enough, unless you expect thousands of transactions per second -> that would remove 8 chars. Or base32/base64 the whole ID to shorten it (depends what alphabet is legal for content)...
Or whatever... already spent enough time with this. Hire a pro.

Array of methods

I am trying to randomly call methods to make it use a different animation every time to display a textview. I trie using an array but not sure how to implement it. My array looks like this (obviously I know it shouldn't be strings but not sure what data type or if even possible this way).
String [] mAnimations = {"Hinge","RollIn", "Landing",
"BounceIn", "BounceInDown", "BounceInLeft", "BounceInRight",
"BounceInUp", "FadeIn", "FadeInUp", "FadeInDown", "FadeInLeft",
"FadeInRight","FlipInX", "RotateIn", "RotateInDownLeft", "RotateInDownRight",
"RotateInUpLeft", "RotateInUpRight", "SlideInLeft", "SlideInRight",
"SlideInUp", "SlideInDown", "ZoomIn", "ZoomInDown", "ZoomInLeft",
"ZoomInRight", "ZoomInUp"};
Putting any of the correct animations by themselves it works fine (Note BounceInLeft):
YoYo.with(Techniques.BounceInLeft)
.duration(1000)
.playOn(textView);
But what I am trying to do is randomly pick an animation from the array something like this:
Random rand = new Random();
int n = rand.nextInt(mAnimations.length) + 1;
YoYo.with(Techniques.(mAnimations[n]))
.duration(1000)
.playOn(textView);
Thanks for your help
Nicholas
Best Directly Assign method based on Random numbers.Because (mAnimations[n]) value consider as String.
String [] mAnimations = {"Hinge","RollIn", "Landing",
"BounceIn", "BounceInDown", "BounceInLeft", "BounceInRight",
"BounceInUp", "FadeIn", "FadeInUp", "FadeInDown", "FadeInLeft",
"FadeInRight","FlipInX", "RotateIn", "RotateInDownLeft", "RotateInDownRight",
"RotateInUpLeft", "RotateInUpRight", "SlideInLeft", "SlideInRight",
"SlideInUp", "SlideInDown", "ZoomIn", "ZoomInDown", "ZoomInLeft",
"ZoomInRight", "ZoomInUp"};
Random rand = new Random();
int n = rand.nextInt(mAnimations.length);
if(n==0)
{
YoYo.with(Techniques.Hinge).duration(1000).playOn(textView);
}
if(n==1)
{
YoYo.with(Techniques.RollIn).duration(1000).playOn(textView);
}

BigInteger q = new BigInteger(8, 10, new Random()); is not producing expected result in Android

BigInteger q = new BigInteger(8, 10, new Random()); is giving me random numbers as expected every time while running from my Desktop but not in Android.
in Android I am always getting only same output instead of random number. Please help me to get random BigIntegr.
for your info:
int randQ = (int) (Math.random() * 9);
for (int r = 0; r < randQ; r++) {
q = q.nextProbablePrime();
}
is the quick fix that I did and I am not happy with this fix since it is consuming extra time.
your suggestions are highly appreciated
This is a very common problem, independent of language or platform.
You must reuse the instance of Random() to get random numbers each time. The default constructor will seed the pseudo-random number generator with the current time. The current time doesn't change very quickly with respect to your program, so you keep getting the same number until the clock ticks up.
If you don't re-seed, it will give you different numbers each time you ask for another value. You can avoid re-seeding by reusing the instance, and calling:
Random random = new Random(); // reuse this instance...
int value = random.nextInt(); // use these values instead of new Random()
See: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Random.html
EDITED
Instead use:
// creates random object with current instant as seed
Random generator = new Random((new Date()).getTime());
BigInteger q = new BigInteger(8, 10, generator);

Categories

Resources