Pick non-repeating random number from progressive list [closed] - java

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Here is my example - pick random number from 1-20, then from 2-21, 3-22 and so on, while
excluding previous picks. I am new to Java, and doing something wrong.
import java.util.Random;
import java.util.ArrayList;
import java.util.List;
public class RandomGenerator {
static int temp;
public static void main(String[] args) {
List<Integer> randomNumberArray = new ArrayList<Integer>();
Random RandomNumber = new Random();
for (int i = 0; i<=20; i++)
{
temp = RandomNumber.nextInt(i+20) +1+i;
if (!randomNumberArray.contains(temp))
{
{
randomNumberArray.add(temp);
}
}
System.out.println(randomNumberArray);
}

There are a couple of things to go over.
1) If your number sees that there is a duplicate then it will skip it and continue with the next number, for example if you run it 5 times and it finds a duplicate once, then the resulting list of numbers will have only 4 numbers not 5! since it skipped one. (Not sure if this is what you wanted or not)
2) Your randomly generated number doesn't grow the way you expect it to grow.
For example: At the sixth iteration over the loop your random number will generate as:
RandomNumber.nextInt(25) +6;
That means that the number range there isn't 6-26 but 6-30!
Because: nextInt will return an int between 0 and 24 and then that int is added another 6 to it.
EDIT :
To tackle your first problem you can continue to generate numbers until you generate one that is not a duplicate for that single cycle of the for loop.
For this you can utilize the do-while loop so that it executes the number generation at least once before checking whether the number is a duplicate within the for loop.
So you can adjust your for loop from:
for (int i = 0; i<=20; i++)
{
temp = RandomNumber.nextInt(20) +1+i;
if (!randomNumberArray.contains(temp))
{
{
randomNumberArray.add(temp);
}
}
System.out.println(randomNumberArray);
}
into:
for (int i = 0; i<=20; i++)
{
do {
temp = RandomNumber.nextInt(20) +1+i;
} while (randomNumberArray.contains(temp));
randomNumberArray.add(temp);
System.out.println(randomNumberArray);
}
Notice that the check in the while expression is the opposite (does not have the exclamation mark) of what was in the if expression in the for loop before, since we do want to continue generating new random numbers while our numbers are duplicates.
And since we are still looping within that one cycle of the for loop, it will always generate the number with the appropriate value of i which was set for that for cycle.

You aren't excluding previous picks. Something like this will print twenty random numbers (e.g. all random numbers from 1-20).
public static void main(String[] args) {
java.util.Set<Integer> picked = new TreeSet<Integer>();
Random rand = new Random();
while (picked.size() < 20) {
int temp = 1+rand.nextInt(20);
if (picked.contains(temp)) {
continue;
}
picked.add(temp);
System.out.println(temp);
}
}
I'm not sure I understand your "stepping" idea, but add this for temp and it will do that too -
int temp = 1+picked.size()+rand.nextInt(20+picked.size());

Since the range of allowed elements isn't too big, you can also hold the pool of all possible numbers and pick one of them. You can use e.g. RandomSet from this answer.
import java.util.*;
import java.lang.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
static class RandomSet<E> extends AbstractSet<E> {
List<E> dta = new ArrayList<E>();
Map<E, Integer> idx = new HashMap<E, Integer>();
public RandomSet() {
}
public RandomSet(Collection<E> items) {
for (E item : items) {
idx.put(item, dta.size());
dta.add(item);
}
}
#Override
public boolean add(E item) {
if (idx.containsKey(item)) {
return false;
}
idx.put(item, dta.size());
dta.add(item);
return true;
}
/**
* Override element at position <code>id</code> with last element.
* #param id
*/
public E removeAt(int id) {
if (id >= dta.size()) {
return null;
}
E res = dta.get(id);
idx.remove(res);
E last = dta.remove(dta.size() - 1);
// skip filling the hole if last is removed
if (id < dta.size()) {
idx.put(last, id);
dta.set(id, last);
}
return res;
}
#Override
public boolean remove(Object item) {
#SuppressWarnings(value = "element-type-mismatch")
Integer id = idx.get(item);
if (id == null) {
return false;
}
removeAt(id);
return true;
}
public E get(int i) {
return dta.get(i);
}
public E pollRandom(Random rnd) {
if (dta.isEmpty()) {
return null;
}
int id = rnd.nextInt(dta.size());
return removeAt(id);
}
#Override
public int size() {
return dta.size();
}
#Override
public Iterator<E> iterator() {
return dta.iterator();
}
}
public static void main (String[] args) throws java.lang.Exception
{
RandomSet<Integer> rs = new RandomSet<Integer>();
for (int i = 0; i < 20; ++i) {
rs.add(i);
}
int count = 50;
Random r = new Random();
for (int i = 0; i < count; i++) {
System.out.println(rs.pollRandom(r));
rs.remove(i);
rs.add(i + 20);
}
}
}
Using the smart structure the overall time complexity is O(N + K), where N is the number of requested polls and K is the size of the pool.
Running Ideone example : http://ideone.com/Sfltr7

The trick here is to use Collections.shuffle(List list):
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
Collections.shuffle(list);
System.out.println(list);
The progressive version goes something like this:
// Wrap it in an ArrayList so I can modify it.
List<Integer> list = new ArrayList(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20));
for (int i = 21; i < 25; i++) {
System.out.println(list);
// Shuffle it.
Collections.shuffle(list);
// Grab one.
Integer take = list.get(0);
list.remove(take);
System.out.println("Took " + take);
// Add my new candidate.
list.add(i);
}
Or you could go the whole hog and make it an Iterable:
public static class CreepingRandom implements Iterable<Integer> {
// The starting list.
private final List<Integer> start;
// How many steps to add.
private final int steps;
// What int to start adding.
private final int from;
public CreepingRandom(int initialSize, int from, int steps) {
// Make my start list.
start = new ArrayList<Integer>(initialSize);
// Fill it.
for (int i = 1; i <= initialSize; i++) {
start.add(i);
}
// Remember where to start from.
this.from = from;
// Remember how many steps.
this.steps = steps;
}
#Override
public Iterator<Integer> iterator() {
return new CreepingIterator();
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list = new ArrayList(start);
#Override
public boolean hasNext() {
return delivered < steps;
}
#Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}
private class CreepingIterator implements Iterator<Integer> {
// Track how many I've delivered.
int delivered = 0;
// The next number to add.
int add = from;
// My current list.
final ArrayList<Integer> list;
CreepingIterator() {
// Copy the start list - Use LinkedList for efficiency of add and removeFirst.
list = new ArrayList(start);
}
#Override
public boolean hasNext() {
return delivered < steps;
}
#Override
public Integer next() {
// Shuffle it.
Collections.shuffle(list);
// Pull one out.
Integer next = list.get(0);
// Add my new one in.
list.set(0, add++);
// Count them.
delivered += 1;
return next;
}
}
}
public void test() {
for (Integer i : new CreepingRandom(20, 21, 100)) {
System.out.println(i);
}
}

Related

Maintain index of days while recursing

In the following code i am trying to find which is the best day to buy and sell a stock. However i am only able to calculate the profit that i have from buying and selling at the correct days but i am not able to find the days (index) since they are lost in the recursion. I don't want to use any static variable. The only solution i am thinking is to add a new private method that will hold the correct days.
public class Stock {
public static int maximum(int[] half) {
int max=half[0];
int index=0;
for (int i=1; i<half.length; i++) {
if (half[i]>max) {
max = half[i];
index=i;
}
}
return max;
}
public static int minimum(int[] half) {
int min=half[0];
int index=0;
for (int i=1; i<half.length; i++) {
if (half[i]<min) {
min = half[i];
index=i;
}
}
return min;
}
private static int maxProfit(int[] stock) {
if (stock.length<= 1)
return 0;
int left[] = Arrays.copyOfRange(stock, 0, stock.length/2);
int right[] = Arrays.copyOfRange(stock, (stock.length/2), stock.length);
int maxLeft = maxProfit(left);
int maxRight = maxProfit(right);
int bothSides = maximum(right) - minimum(left);
return Math.max(Math.max(maxLeft,maxRight), bothSides);
}
public static void main(String[] args) {
int[] stock_t = { 13, 5, 2, 12, 3, 15 };
int fi = maxProfit(stock_t);
System.out.println(fi);
}
}
I want to retain the last updated value of days
You can add an instance variable to your class to retain the last updated value for days:
public class Stock{
private int days;
public int getDays(){
return days;
}
}
To retain the value for days after calculation, update the value before the method exits:
//In Stock class
public int maximum(int[] half) { //Make this an instance method (remove static)
int max=half[0];
int index=0;
for (int i=1; i<half.length; i++) {
if (half[i]>max) {
max = half[i];
index=i;
}
}
days = index; //update before method exits
return max;
}
You may also update days in whichever place that is appropriate.
To get the value for days:
public static void main(String[] args) {
int[] stock_t = { 13, 5, 2, 12, 3, 15 };
Stock s = new Stock(); //create Stock object
int fi = s.maxProfit(stock_t); //calculations will update days attribute
System.out.println(s.getDays()); //get days according to last calculation
}
All your methods are static which seems a little weird to me in terms implementation. If your Stock class is supposed to act as a template for creating Stock objects and each individual Stock object retains its own state, your methods and attributes are more appropriate to be declared as non-static.
If your Stock class is to be used as an utility class for just invoking methods, then those methods can be static. But according to your question, this doesn't seems to be the case.

random elements from a list DURING the addition

There are 20 names in my code.
my function has 2 options to add elements to a list I've:
1.
Inserting all the 20 names to the list:
public void addNames() {
list.add("name1");
list.add("name2");
...
list.add("name20");
}
2.
Adding only 5 random names(from the 20 names) to the list. For doing it, I thought about 2 ways. What's the best way to random 5 names from the 20? maybe you have a better way.
A.
Using a random set of indices (each value will be between 0 to 19 because there are 20 names) and before the 'add' I'll check if adding them or not by some counter:
public void addNames() {
// adding 5 random indices between 0 to 19 to the set
Set<Integer> set = new HashSet<Integer>();
Random r = new Random();
Set<Integer> indices = new HashSet<>(numRandomNames); //==5
for (int i = 0; i < numRandomNames; ++i) {
int index = r.nextInt(numNames - 0); //==19
indices.add(index);
}
int counter = 0;
if (indices.contains(counter)) {
list.add("name1");
}
counter++;
if (indices.contains(counter)) {
list.add("name2");
}
counter++;
if (indices.contains(counter)) {
list.add("name3");
}
...
}
B.
RandomList that extends List and overrides the 'add' function to do the same as 'A.' does BUT the override 'add' will decide whether adding the value inside the function so my function will look the same as 1. with the override 'add' function
Do you think about a better solution? if not, then which one is better? (A or B?). I just saw that people recommends not to extend the java collection but I think it's the best solution from these 2 solutions.
NOTE
====
my code can have 10000 names or more even so I don't want to add all the 10,000 names to this\other list and then random 5 of them to other list. I prefer to do it DURING the addition in order to avoid many places of the list while I don't really need them.
EDIT
an answer to ProgrammerTrond:
I'm not sure I'll do it but what I asked me to show is my suggestion of 2.B:
public class RandomList<Integer> implements List<Integer> {
private int addCallsCounter;
private Set<Integer> setIndices = null;
public RandomList(final int numElements, final int maxVal, final int minVal) {
addCallsCounter = 0;
setIndices = new HashSet<Integer>(numElements);
Random r = new Random();
while (setIndices.size() < numElements) {
int index = r.nextInt(maxVal - minVal + 1) + minVal;
if (setIndices.contains(index) == false) {
setIndices.add(index);
}
}
}
#Override
public boolean add(Integer object) {
if (setIndices.contains(addCallsCounter++)) {
this.add(object);
return true;
}
return false;
}
}
and from my code I'll do so:
RandomList randList = new RandomList(5);
randList.add("name1");
randList.add("name2");
randList.add("name3");
...
randList.add("name19");
randList.add("name20");
but my problem is that I need to implement MANY abstract methods of List pfff. RandomList cann't be abstract too because then it won't be able to be instantiated.
try this:
List<Integer> index = new ArrayList<>();
List<String> five_names = new ArrsyList<>();
List<String> allnames = new ArrayList<>();
store five random values
for(int i = 0;i < 5;i++){
int index_no = getrandomNumber();
index.add(index_no);
five_names.add(allnames.get(index_no));
}
getRandomNumber method:
public int getRandomNumber(){
Random rnd = new Random();
int x = rnd.nextInt(20);
if(index.contains(x)){
return getRandomNumber();
}else{
return x
}
}
Why not like this? You don't need the random index list in your list implementation. Didn't you just want a method that would add to a list 5 random names drawn from a set of available names?
import java.util.*;
public class ListAdding {
private static List<String> allNames = Arrays.asList("name1", "name2", "name3", "name4", "name5", "name6", "name7");
public static void main(String[] args) {
new Temp().test();
}
void test() {
List<String> list = new ArrayList<>();
list.add("Bernie");
addFiveRandom(list);
for (int i = 0; i < list.size(); i++) {
System.out.println(i + ": " + list.get(i));
}
// Example: 0: Bernie
// 1: name2
// 2: name3
// 3: name6
// and so on
}
void addFiveRandom(List<String> toBeAddedTo) {
List<Integer> indices = new ArrayList<>();
while (indices.size() < 5) {
int newIndex = new Random().nextInt(5);
if (!indices.contains(newIndex))
indices.add(newIndex);
}
for (Integer index : indices) {
toBeAddedTo.add(allNames.get(index));
}
}
}

Java: Create unique List from an existing List keeping index numbers constant

I have two ArrayLists.
List of dates
List of respective data.
Both are synchronized. I sometimes have more than one data on a same date. I need to create two lists: unique dates and the data (averaged) respectively. So far, I have tried the following methods
int i = 1;
for(int it =0; it < predatetime.size() - 1; it++){
//Compare each element with the next one
if(predatetime.get(it+1) == predatetime.get(it)){
i++;
weight = preweight.get(it+1) + weight;
//If equal, add weights and increment a divisor for averaging
}
else { //if not equal, add to the new lists
if(it == predatetime.size() - 2){ //if the last element is not equal to its previous one, just add it to the list
newDateTime.add(predatetime.get(it+1));
newWeight.add(preweight.get(it+1));
break;
}
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
weight = preweight.get(it+1); //re-initialize variables
i = 1;
}
if(it == predatetime.size() - 2){
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
}
}
There are a lot of problems with this code.
If the list has only one element, it fails. (I know I can write 2 more lines to care of this). Is there a better way to do this?
I know there are similar questions on this website, but still I'm unable to resolve the problem.
This is the full solution
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class CustomList {
public static void main(String[] args) {
ArrayList<String> date = new ArrayList<>();
date.add("1");
date.add("2");
date.add("2");
date.add("3");
System.out.println(date);
ArrayList<Integer> value = new ArrayList<>();
value.add(1);
value.add(2);
value.add(4);
value.add(3);
System.out.println(value);
new MyCls().createList(date, value);
}
}
class MyCls {
ArrayList uniqueDate = new ArrayList<String>();
ArrayList averageValue = new ArrayList<Integer>();
LinkedHashMap store = new LinkedHashMap<String, CountEntry>();
class CountEntry {
int value;
int count;
CountEntry() {
}
CountEntry(int v, int c) {
value = v;
count = c;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public void createList(ArrayList<String> date, ArrayList<Integer> value) {
for (int i = 0; i < date.size(); i++) {
CountEntry tmp = (CountEntry) store.get(date.get(i));
if (tmp == null) {
store.put(date.get(i), new CountEntry(value.get(i), 1));
} else {
int tmpVal = tmp.getValue();
int tmpCount = tmp.getCount();
store.put(date.get(i), new CountEntry(value.get(i) + tmpVal, ++tmpCount));
}
}
ArrayList<String> uniqueDate = new ArrayList<String>(store.keySet());
ArrayList<CountEntry> tempAvgList = new ArrayList<CountEntry>(store.values());
for (CountEntry ce : tempAvgList) {
averageValue.add(ce.getValue() / ce.getCount());
}
System.out.println("Output");
System.out.println(uniqueDate);
System.out.println(averageValue);
}
}
/*
OUTPUT Snap:
[1, 2, 2, 3]
[1, 2, 4, 3]
Output
[1, 2, 3]
[1, 3, 3]
*/
If you try to make your list elements unique why you not try to convert the list to set collection
Set<Foo> foo = new HashSet<Foo>(myList);
Why not create a Map instead with the dates as the key and have the value as a list. This will allow you to keep the dates unique, at the same allow you to have your data as a list.
Map<String, ArrayList<myData>> myMap = new HashMap<String, ArrayList<myData>>();
Then you can just find if your key exists, if it does add it to the array list by using the key to identify the correct list. If it doesnt exist it, add it to the map
Thanks to #Rambler and #JulianGurung, I created a HashMap and it works
HashMap<Integer, Float> hm = new HashMap<Integer,Float>();
int occurance = 0;
float weight = 0;
hm.put(predatetime.get(0), 0f); //initialize with the first value
for(Map.Entry m : hm.entrySet()){
for( int it = 0; it < predatetime.size(); it++){
if(m.getKey() == predatetime.get(it)){
weight = (Float) m.getValue() + preweight.get(it); //Sum all the same data in order to avg later
hm.put(predatetime.get(it), weight);
occurance++;
}
else{ //if it is not equal, add the new element to the map
hm.put(predatetime.get(it), preweight.get(it));
}
}
weight = weight / occurance;
hm.put((Integer) m.getKey(), weight);
weight = 0;
occurance = 0;
}

How to retrive substring of array elements withought using loop

I have a string array and i want to retrive 15 elements at one shot without using a loop. I'm not sure whether this is possible or not
here is my code snippet using loop
String8uilder sb= new String8uilder();
for(int x=0;x<15;x++)
sb.append(array1[x]);
System.out.println(sb);
Is it possible to access all the 15 elements at once without using a loop?
Consider that array array1 already has 100 elements in it.
Thanks in advance
Are you constrained to using an array? If not, you could use other data structures that let you slice subsets of data out of them (e.g. lists).
If you must use an array, you could create a custom Iterator that iterates over a slice of the array:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class WatIterator<A> implements Iterator<A> {
private int i = 0;
private final A[] as;
private final int start;
private final int count;
public WatIterator(A[] _as, int _start, int _count) {
as = _as;
start = _start;
count = _count;
}
public synchronized boolean hasNext() {
return (i < count) && (as.length > start + i);
}
public synchronized A next() {
if (hasNext()) {
A a = as[start + i];
i = i + 1;
return a;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
}
}
But to use it you're still going to have to do some kind of looping or recursion, even if you tuck it away in a toList converter:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Wat {
public static <A> List<A> toList(Iterator<A> it) {
List<A> as = new ArrayList<A>();
while (it.hasNext()) {
as.add(it.next());
}
return as;
}
public static void main(String[] args) {
String[] array = new String[100];
for (int i = 0; i < 100; i++) array[i] = Integer.toString(i);
WatIterator<String> watIterator = new WatIterator(array,0,15);
List<String> slice = toList(watIterator);
System.out.println(slice); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
}
}

How to check for a sequence of keystrokes

I'm making a game and want to implement cheat codes like the Konami code.
But how do I check for that sequence of keystrokes?
I want it to work so that if a player just types the code it will trigger.
Thanks in advance!
Below is a class that checks for the Konami code, including cases such as "UP, UP, UP, DOWN, etc."
This should work for any given sequence.
import java.util.Map;
import java.util.TreeMap;
public class Konami {
static private int[] code =
{UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B};
static private Map<Integer, Integer>[] graph;
static private int currentNode = 0;
public static void main(String args[]) {
//Create graph
graph = generateSequenceMap(code);
//Call checkKonami(key) whenever a key is pressed
}
static public boolean checkKonami(int keyPressed) {
Integer nextNode = graph[currentNode].get(keyPressed);
//Set currentNode to nextNode or to 0 if no matching sub-sequence exists
currentNode = (nextNode==null ? 0 : nextNode);
return currentNode == code.length-1;
}
static private Map<Integer, Integer>[] generateSequenceMap(int[] sequence) {
//Create map
Map<Integer, Integer>[] graph = new Map[sequence.length];
for(int i=0 ; i<sequence.length ; i++) {
graph[i] = new TreeMap<Integer,Integer>();
}
//i is delta
for(int i=0 ; i<sequence.length ; i++) {
loop: for(int j=i ; j<sequence.length-1 ; j++) {
if(sequence[j-i] == sequence[j]) {
System.out.println("If at Node "+j+" you give me seq["+(j-i+1)
+ "] OR " + (sequence[j-i+1]) + " , goto Node " + (j-i+1));
//Ensure that the longest possible sub-sequence is recognized
Integer value = graph[j].get(sequence[j-i+1]);
if(value == null || value < j-i+1)
graph[j].put(sequence[j-i+1], j-i+1);
}
else
break loop;
}
}
return graph;
}
}
EDIT:
See my other post for code that always works. The following doesn't detect the code if it overlaps with itself (for instance: "UP, UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B" wouldn't work)
Thanks to Gevorg for pointing this out.
If it's how to identify the sequence that you are concerned with only (I'll assume you know how to get input from the keyboard) then you can have something as follows.
int[] sequence = {UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B};
int currentButton = 0;
boolean checkKonami(int keyPressed) {
//Key sequence pressed is correct thus far
if(keyPressed == sequence[currentButton]) {
currentButton++;
//return true when last button is pressed
if(currentButton == sequence.length) {
//Important! Next call to checkKonami()
//would result in ArrayIndexOutOfBoundsException otherwise
currentButton = 0;
return true;
}
}
else {
//Reset currentButton
currentButton = 0;
}
return false;
}
Call this function whenever a key press is registered, passing the key that has been pressed. Of course modify the types where appropriate.
I'm sure you're past this project now, but I just implemented this into one of my assignments and wanted to leave it for others to find. This solution logs the last n keystrokes (defined here as 10) into a circular array and returns true when they match our code. You could just as easily pass in different lengths and codes as part of the method (but this implementation didn't require it). I used ^ ^ v v < > < > b a.
public class Code {
private static int[] history = new int[10];
private static int front = 0;
private static int size = 0;
// Here is the Code they must enter (ascii vals for konami).
private static int[] code = {38, 38, 40, 40, 37, 39, 37, 39, 66, 65};
// Static class. No constructor.
private Code(){}
// Adds key-press into history buffer. If code is matched, return true.
public static boolean add(int e){
// Write the value into our key history.
history[(front + size) % 10] = e;
// Stop growing at length 10 and overwrite the oldest value instead.
if (size < 10){
size++;
} else {
front = front + 1 % 10;
}
// Compare our history (from the current front) to the code (from 0)
for(int i = front; i < front + size; i++){
if (history[i % 10] != code[i-front]){
// Any 1 mismatch will abort
return false;
}
}
// Make sure we've logged enough keystrokes so it doesn't fire off
// if your first key press matches the code.
if (size < 10){
return false;
}
return true;
}
Enjoy! :D
I don't know what your needs are. Are you trying to create a game using System.in and System.out or are you trying to make a full visual GUI?
In the meantime, see interface java.awt.event.KeyListener. (Oracle Documentation) Also, see Oracle's Tutorial.
And based on personal experience, the code below approximates what you need.
import java.awt.event.*; //Specifically KeyListener and KeyEvent
import java.util.ArrayList;
public class Test implements KeyListener {
private final int[] cheatCode = {38, 38, 40, 40, 37, 39, 37, 39, 66, 65, 83, 84, 65, 82, 84} //assuming user types out "start"
private final ArrayList<Integer> KONAMI_CODE = createCheatCode(cheatCode);
private ArrayList<Integer> typedKeys = new ArrayList<Integer>();
public Test() {
//constructor goes here, if necessary
}
public /*static*/ ArrayList<Integer> createCheatCode(int[] code) { //uses Key Codes
ArrayList<Integer> temp = new ArrayList<Integer>();
for (int i = 0; i < code.length; i++)
temp.add(new Integer(code[i]));
return temp;
}
// Warning: MUST implement ALL KeyListener methods, or compiler will complain
public /*static*/ void keyPressed(KeyEvent e) {}
public /*static*/ void keyReleased(KeyEvent e) {
typedKeys.add(new Integer(e.getKeyCode()));
}
public /*static*/ void keyTyped(KeyEvent e) {}
public /*static*/ boolean cheatEntered() {
int cheatLen = KONAMI_CODE.size(); // or length, depending on what you use
int index = typedKeys.size() - cheatLen;
if (index < 0)
return false;
return typedKeys.get(index, typedKeys.size()).equals(KONAMI_CODE);
}
}
When using a runner method, just specify that
if (test.cheatEntered()) {
// do something
}
You can remove the /*static*/ if you want object-oriented programming; otherwise, get rid of the /* and */ pairs if you want to run it using static methods.
It might be interesting to look at the state pattern but you might try the trick below since this is a simple case:
Put the sequence to be recognized in a String secretCode
Create a StringBuilder userInput that will hold the keys pressed by the user
Every time a user presses a key append it to userInput
After each key that is appended in userInput check if the updated userInput contains the secretCode withthe following: userInput.indexOf(secretCode)>-1
You might want to empty the userInput from now and then based on time or after a sequence is recognized for instance.
why not just use string.contains?
public class Konami {
private static final String KONAMI_SEQUENCE = "↑↑↓↓←→←→BA";
StringBuilder sb = new StringBuilder();
public void character(char c) {
sb.append(c);
}
public boolean isKonami() {
return sb.toString().contains(KONAMI_SEQUENCE);
}
public static void main(String[] args) {
Konami konami = new Konami();
String str1 = "↑↑↓↓←→←→BA";
String str2 = "↑↑↑↑↓↓←→←→BA";
String str3 = "↑↑↓↓→↓←←→←→BA";
for(int i = 0 ; i < str3.length(); i ++) {
konami.character(str3.charAt(i));
}
System.out.println(konami.isKonami());
}
}

Categories