How could i make my app learn like a keyboard? - java

So I've made an app that makes sentences, much like a keyboard of words and pictures, what I'd like to achieve is a kind of predictive text where if a user chooses X they are shown Y and Z, user doesnt want either of these and chooses A.
The next time the user picks X they are shown A, Y and Z, so it learns like your keyboard would, my words are stored in a database and right now i have a crude solution where if the user chooses X they are shown Y and Z, and I also track how many times each card is clicked and show them too but it has no context of full sentences or previously made sentences, i hope this is making sense as I've no idea where to start I've been looking at maybe a hashmap full of essentially TAGS as key value pairs and adding to it but I need to research this, I've also looked at candidate view but that would mean declaring my app as an Input Method I believe and I need the normal keyboard for other things, but I'm not sure how that works or if it's remotely viable so I'm hoping someone can educate me here or point to a better solution.
Below I'll post excerpts of what I'm doing thus far
//Check what card was pressed and update predictedCardActivityDB example
//to carry on like this would mean a lot of typing
//and not a lot of smart results
if (cardsChoice.predictive == true) {
String item = cardWriter.getCardSpeech();
switch(item){
case " I":
String[] I_String = {"LIKE","LOVE","WANT"};
predictedCardActivityDB.prepareCardData
(I_String,getActivity(),prefString);
break;
case " I'm":
String[] Im_String =
{"HAPPY","SAD","ANGRY","HUNGRY","FEELING"};
predictedCardActivityDB.prepareCardData
(Im_String,getActivity(),prefString);
break;
And this is the prepareCardData method excerpt nothing to see here just updates the lists based on the string array
public static void prepareCardData
(String[] predictionArray, Context context ,String prefString){
//boring database stuff
DaoMaster.DevOpenHelper helper =
new DaoMaster.DevOpenHelper(context, "ADD_NEW_CARD", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
addNewCardDao leaseDao = daoSession.getAddNewCardDao();
QueryBuilder qb = leaseDao.queryBuilder()
.orderDesc(addNewCardDao.Properties.Clicked);
QueryBuilder qb2 = leaseDao.queryBuilder()
.orderDesc(addNewCardDao.Properties.Clicked);
predictsList.clear();
String[] strings1 = {"ORIGINAL","SIMPLE","PHOTOS", "USER"};
switch (prefString){
case "PHOTOS":
if (predictionArray != null){
//qb gets any card clicked >2
//qb gets all favourites tagged by a boolean
qb.where(addNewCardDao.Properties.CardIconType.in(strings1),
qb.or(addNewCardDao.Properties.Clicked.ge(2),
addNewCardDao.Properties.Fav.ge(true)));
predictsList = qb.list();
//qb2 gets any card that matches a word from the passed in
//string array predictionArray
qb2 = leaseDao.queryBuilder();
qb2.where(addNewCardDao.Properties.CardIconType.in(strings1),
qb2.or(addNewCardDao.Properties.CardName.in(predictionArray),
addNewCardDao.Properties.CardTitle.in(predictionArray)));
temptList = qb2.list();
db.close();
temptList.addAll(predictsList);
predicts_card_adapter.notifyItemInserted(predictedCardActivityDB.temptList.size());
predicts_card_adapter.notifyDataSetChanged();
predicts_card_adapter = new predictsCardAdapter(temptList,itemTouchListener);
predictsrecyclerView.setAdapter(predicts_card_adapter);
}else{
qb.where(addNewCardDao.Properties.CardIconType.in(strings1),
qb.or(addNewCardDao.Properties.Clicked.ge(2),
addNewCardDao.Properties.Fav.ge(true)));
predictsList = qb.list();
//this should work
predicts_card_adapter.notifyDataSetChanged();
predicts_card_adapter = new predictsCardAdapter(predictsList,itemTouchListener);
predictsrecyclerView.setAdapter(predicts_card_adapter);
db.close();
System.out.println("else, predictsList size " + predictsList.size());
}
break;
}
//should be able t delete this and use the two commented out piecess of code above
//the result being the predicted cards coming first in the list
/*
predicts_card_adapter.notifyItemInserted(predictedCardActivityDB.temptList.size());
predicts_card_adapter.notifyDataSetChanged();
predicts_card_adapter = new predictsCardAdapter(temptList,itemTouchListener);
predictsrecyclerView.setAdapter(predicts_card_adapter);
*/
}

Related

JAVA seperate class method not incrementing a variable in my main class method

so this is the main code for my text-based game.
import java.util.Scanner;
public class D_M_RPG {
public static void main(String[] args) {
//Creating the class to call on my toolbox
D_M_RPGtoolbox toolbox = new D_M_RPGtoolbox();
//Creating the scanner class for user input
Scanner input = new Scanner(System.in);
//Initiating variables and final variables aswell as arrays
//token variable to validate open spots in an array
int slotCounter = 0;
int inventoryExpander = 11;
//First initiated will be the character creation variables
String hairColor = "";
String eyeColor = "";
String skinColor = "";
String gender = "";
//Initiating the arrays for character inventory slots
String[] weaponSlots = new String[10];
//initiating the arrays for the character creation
String[] hairColorARR = {"black","Green","Yellow","Brown","Blue","Blonde","Grey","White"};
String[] eyeColorARR = {"Green","Brown","Blue","Grey",};
String[] skinColorARR = {"White","brown","Black",};
String[] genderARR = {"Male","Female"};
//Creating the introduction title and introduction
System.out.println("Welcome to, COLD OMEN.");
System.out.println("\nNOVEMBER 12th, 2150: ONTARIO, CANADA");
System.out.println("\nYou hear loud shouts and gun fire all around you but can't pinpoint the location of anything, you feel a bit dazed until someone grabs you and you open your eyes and snap out of it.");
System.out.println("\nUnknown: 'Get up, its time to move out. Take this.'");
System.out.println("\nUnknown hands you a 'M4-A4 RIFLE'");
System.out.println("\nyou manage to catch a small glimpse of him before you get up.");
//Character creation screen
System.out.println();
//ONLY WORKS ONCE WONT INCREMEMENT THE SLOTCOUNTER
toolbox.insert(weaponSlots, slotCounter, inventoryExpander, "M4-A4 RIFLE");
System.out.println("\n" + weaponSlots[0]);
toolbox.insert(weaponSlots, slotCounter, inventoryExpander, "ak47");
System.out.println(weaponSlots[0]);
}
}
so I have this method I made to basically add an "item" to the weaponSlots array (the inventory) but whenever I run it it will add to the first element in the array [0] but it wont incremement the slotcounter which should go up by one every time the method is used so that I dont replace any items in the array It should just add items until its full which is checked using the inventoryExpander variable. at the moment I have it printing the element at 0 and 0 for the array but i have checked 1 aswell and 1 is just null no item added it only just replaces the element at 0. heres the code for the method to increment etc:
public class D_M_RPGtoolbox {
//method for random number generating to be used for crit hits, turns, loot generation etc
public int randomGen(){
int x = (int) (Math.random()*((20-0)+1)+0);
return x;
}
//method for inserting into an array ONLY WORKS ONCE WONT INCREMEMENT THE SLOTCOUNTER FIX
public void insert(String[] a, int b, int d , String c) {
if(b < d) {
a[b] = c;
b++;
}//end of if statement
}//end of method
}
What you are actually performing the ++ operation on in b is a copy of the value in slotCounter.
The variable slotCounter is passed into insert "by-value".
This unlike what you probably imagine, that it is passed "by-reference".
One solution would be to do the slotCounter++ from the call row instead; and another would be to let the toolbox own the slotCounter variable completely.
This question uses the image of passing a copy of document content (by value) where changes to the document would not be seen by the sender; or as a link to a shared document (by reference), where changes could be made to the same page that the sender sees.
Its always going to be zero since you are passing zero and incrementing the local variable b.
Try calling the method as below with post increment ++ to slotCounter and see if it works for you,
toolbox.insert(weaponSlots, slotCounter++, inventoryExpander, "M4-A4 RIFLE");

JAVA - Menu running in loop - How can I print out all choices?

I'm trying to learn JAVA and I'm working on a simple pizza order assignment running purely in text/console format.
I've made the user chose a pizza, but they need the option to add extra ingredients.
My thought was to use a for loop to show a toppings menu and then ask for a numbered input matching the ingredient they want to add.
I want them to be able to select several ingredients, why I'm doing it in a loop.
My code as of now looks like this:
for (int i = 0; ingredientInput>0; i++ ){
toppingsMenu();
ingredientInput = ingredientScan.nextInt();
ingredientScan.nextLine();
System.out.println("Type your choice here:");
}
System.out.println(ingredientInput);
Everything works great, but I'd like to add a system.out.println() telling the user, what they've chosen as:
"You've added extra cheese - Would you like to add more?"
If so, I would like to expand that sentence: "You've added extra cheese & pepperoni - Would you like to add more?"
Could you help me by pointing me in a direction that might work? I'm not into any object related part of JAVA yet, purely text-based so far.
Thanks.
Solution provided by Adeel Ahmad
ArrayList<Integer> ingredients = new ArrayList<>();
for (int i = 0; ingredientInput>0; i++ ){
toppingsMenu();
ingredientInput = ingredientScan.nextInt();
ingredientScan.nextLine();
ingredients.add(ingredientInput);
System.out.println("Type your choice here:");
}
System.out.println(ingredientInput);
Looking back it's so interesting to see which problems I struggled to solve, as now, a few months later, this seems so basic. But thanks anyway to everyone who helped :D
First off, you need to be able to store all the added ingredients in data container (e.g ArrayListor HashMap). Whenever user inputs an ingredient, just added that in your ArrayList
ArrayList<Integer> ingredients = new ArrayList<>();
for (int i = 0; ingredientInput>0; i++ ){
toppingsMenu();
ingredientInput = ingredientScan.nextInt();
ingredientScan.nextLine();
ingredients.add(ingredientInput);
System.out.println("Type your choice here:");
}
System.out.println(ingredientInput);
Once you have collected all the user selected ingredients in your ArrayList, you can then iterate over it in a loop and construct your final message.
You could use something like this
String orderedSoFar = "";
boolean done = false;
do {
// read next ingredient from user
String currentIngredient = scanner.nextLine();
// if first extra ingredient
if(orderedSoFar.equals("")){
orderedSoFar += currentIngredient;
// if not first extra ingredient
} else {
orderedSoFar += " & " + currentIngredient;
}
System.out.println("Ingredients so far " + orderedSoFar);
System.out.println("Add more extra ingredients?");
// read choice to continue or not from user
done = Boolean.valueOf(scanner.nextLine());
}while(!done);

Java: Adding two random array elements for each category of a custom arraylist

I am providing the user with two random videos for each category they have selected.
I have an ArrayList of strings for the user preferences.
I also have an ArrayList of all of the videos in the database.
So I am trying to search through each of those category preferences one by one and find two random videos that fit into it those category.
I have implemented a solution that works (On a small dataset). But I am not sure it is optimal method considering there will soon be 500 videos, 50 categories and the user will be able to select 5 category preferences:
This is how I worked it out:
//Create a new array to store the videos
ArrayList<Video> videos = new ArrayList<>();
// Create counter for the position in the user preference array
int userPrefernceArrayIndex = 0;
// Create counter for number of successful category guesses
int numberOfSuccessfulGuesses = 0;
// Keep running until we have 2 videos for each of the user preferences
while (videos.size() < MainActivity.userPrefrencesStaticArraylist.size() * 2){
// Generate a random integer to get an entry random integer from the database array
Random rand = new Random();
int randomAlarmVidInt = rand.nextInt(MainActivity.allVideosFromDatabaseStaticArray.size());
// Find the category of the random video that was chosen
String categoryForRandomGuess = MainActivity.allVideosFromDatabaseStaticArray.get(randomAlarmVidInt).getVideoCategory();
// Find the current user video category we are testing for
String currentCategoryPreference = MainActivity.userPrefrencesStaticArraylist.get(userPrefernceArrayIndex);
// Check if category of the random video we got is the same as the category user
// preference we are testing for
if (categoryForRandomGuess.equals(currentCategoryPreference)){
// If it the the preference and the random video categories match add it to the video array
videos.add(MainActivity.allVideosFromDatabaseStaticArray.get(randomAlarmVidInt));
numberOfSuccessfulGuesses++;
// If the number of successful guesses is divisible by two then we have added two correct videos
// for that category so iterate to the next category
if (numberOfSuccessfulGuesses % 2 == 0){
userPrefernceArrayIndex++;
}
}
Because of the possibility for problems I hardly ever use a while loop or random unless necessary. I also see that guessing the number may not be the best solution memory wise. So I just want to make sure I am doing it the best way to avoid issues.
Thanks for your help
Yes you can optimize your solution as following:
Currently your iterations of while loop are getting wasted: Say categoryForRandomGuess and currentCategoryPreference both are equal to "Category 1".
So numberOfSuccessfulGuesses becomes 1, but userPrefernceArrayIndex stays 0. So if in next iteration if categoryForRandomGuess is "Category 4", the iteration will be wasted even if currentCategoryPreference can become equal to "Category 4" for some other value of userPrefernceArrayIndex, that is value other than 0.
I would Suggest using a HashMap<String,Integer> where String stores the video category and Integer stores the index of first video found in database of the category.
if the Integer value is -1, it will mean we have 2 videos and we are done with the category.
Now you can eliminate the variable userPrefernceArrayIndex and your code will be a lot shorter
So your code would be:
HashMap<String,Integer> mymap = new HashMap<>();
while (videos.size() < MainActivity.userPrefrencesStaticArraylist.size() * 2)
{
// Generate a random integer to get an entry random integer from the database array
Random rand = new Random();
int randomAlarmVidInt = rand.nextInt(MainActivity.allVideosFromDatabaseStaticArray.size());
// Find the category of the random video that was chosen
String categoryForRandomGuess = MainActivity.allVideosFromDatabaseStaticArray.get(randomAlarmVidInt).getVideoCategory();
//check if the hashmap has the category
if(mymap.get(categoryForRandomGuess) == null)
{
mymap.put(categoryForRandomGuess,randomAlarmVidInt);
videos.add(MainActivity.allVideosFromDatabaseStaticArray.get(randomAlarmVidInt));
}
else
{//-1 means we already have 2 videos of the category.
if(mymap.get(categoryForRandomGuess) == -1)
continue;
//if following condition is true, then its a duplicate video
if(mymap.get(categoryForRandomGuess) == randomAlarmVidInt)
continue;//skip the rest of loop and get new value of randomAlarmVidInt
else
{
mymap.put(categoryForRandomGuess,-1);//second video added
videos.add(MainActivity.allVideosFromDatabaseStaticArray.get(randomAlarmVidInt));
}
}
}

Java: Is This Code Safe?

I'm making an Android App and have currently created some code to be used to generate a code. The generated code will be checked agaisnt the database to see if the code is in use. If it is it will re-generate another code until it finds a code which is not in use. This is done using a do-while loop, whilst there are no codes there will be no noticeable delay to the user. However if there are loads of codes there will be a noticeable delay won't there? The code is below:
public static String generateCode(DBAdapter myDB, String mgrName){
String[] name = mgrName.split(" +");
String fName = name[0];
String lName = name[1];
String fLetter = fName.substring(0, 1).toUpperCase();
String lLetter = lName.substring(0, 3).toUpperCase();
int randomPIN = (int) (Math.random() * 9000) + 1000;
String pin = String.valueOf(randomPIN);
String letters = new StringBuilder().append(fLetter).append(lLetter).append(pin).toString();
Boolean result = checkCode(myDB, letters);
if(result == true){
return(letters);
}
else{
String code = "";
Boolean resultfail = false;
do{
int randomPINFail = (int) (Math.random() * 9000) + 1000;
String generatedCode = new StringBuilder().append(fLetter).append(lLetter).append(randomPINFail).toString();
Boolean check = checkCode(myDB, generatedCode);
if(check){
resultfail = true;
code = generatedCode;
}
}while(!resultfail);
return code;
}
}
public static Boolean checkCode(DBAdapter myDB, String code){
Cursor cursor = myDB.getRowComplaint(code);
if(cursor.getCount() == 0){
return true;
}
else{
return false;
}
}
My Question is what is the chance that the generator will choose a code that is already in use so many times that the user will notice a delay? Bearing in mind the generator will use different manager names as well as different numbers. And is this code safe to use? If not what can be done to make it safe?
EDIT: I can't use UUID as the user has requested the code to contain four letters and four digits. The code is used to retrieve data from the db and that's why it needs to be unique.
As with any performance related question, there's no way for us to answer - you should profile it yourself by creating a large number of existing rows and then seeing how slow it is.
In terms of safety, that's a very broad term and I don't know anything about what you're using these codes for, so I couldn't comfortably tell you that the code is safe. But there don't seem to be any horrible problems with the way you're accessing the database.
Just use UUID class or any other built-in pseudo-random number generator - don't reinvent the wheel. In theory, they will provide such a small collision rate that in absolute most cases you'll generate unique id on a first try. But once again, it depends on your use case. I assume that you're doing something sane and not generating&storing millions of millions of those codes on mobile device.
Be sure to not invoke this routine from the main thread - in this case use might notice the delay even if your DB is empty.

Another Android Activity or an iterative JAVA method?

I am new to Android application development and am trying to find a way to proceed through a series of screens that take in user input. I'm making a small math game where the user would answer basic two integer addition problems. So far the main menu is created. It has a New Game button which launches my GameActivity and it runs just fine for one math problem. However, after the user inputs their answer to the simple math problem, I would like to be able to continue on to another math problem once the user had answered the current problem and the method would return a correct/incorrect value. Initially I thought of doing something like a basic FOR loop from within the GameActivity :
for(int i = 0; i < 10; i++){ gameMethod(); }
gameMethod() is a JAVA method that simply generates 2 random numbers, adds them to get the correct answer and then prompts the user using an EditText field to type in their guess. It displays the random numbers and answer using TextView boxes created in an XML layout file.
Each call to the gameMethod would, at least I think, just re-input the randomized numbers into the TextView fields displayed on the screen each iteration. I really don't care what the previous numbers were so I figured I would just overwrite them. I wan't able to get the code to do that though. I put in a Log.d() statement or two and found that the FOR loop was in fact running through correctly 10 times, but it was not waiting for user input before firing off its next gameMethod().
In doing some looking around, I found the startActivityForResult() and wondered if this was a more appropriate way of approaching this. So in this way, I foresee having three Activities, the Main menu which calls the GameActivity which would then iterate through, say 10 times, each iteration calling yet another activity GameScreenActivity which would actually put the numbers on the screen, read in user input and then return 1 for a correct answer and 0 for an incorrect answer. So far in reading up on StarActivityForResult() I'm getting somewhat confused by the process and wondered if this was even a plausible path to be exploring.
Again, I'm very new at this Android programming and appreciate any and all help that I can get.
Thank you.
Sorry for not including the gameMethod() initially, I've added it below.
// Create and initialize arrays of integers
int[] a = {0,1,2,3,4,5,6,7,8,9,10};
int[] b = {0,1,2,3,4,5,6,7,8,9,10};
// Creates random number generator
Random randy = new Random();
// Generates two random values to add
int r1 = randy.nextInt(10);
int r2 = randy.nextInt(10);
// Calculates correct answer
int an = a[r1] + a[r2];
// Displays 1st number
TextView number1 = (TextView) findViewById(R.id.firstNumber);
number1.setText(Integer.toString(a[r1]));
// Displays 2nd number
TextView number2 = (TextView) findViewById(R.id.secondNumber);
number2.setText(Integer.toString(b[r2]));
// Displays correct answer
TextView answer1 = (TextView) findViewById(R.id.answerNumber);
//hide answer until user puts in theirs
answer1.setVisibility(View.INVISIBLE);
answer1.setText(Integer.toString(an));
//hide the answer place holder value
TextView uAnswerDisplay = (TextView) findViewById(R.id.userAnswerNumber);
uAnswerDisplay.setVisibility(View.INVISIBLE);
//Get the EditText field that the user will input their answer to
EditText inputText = (EditText) findViewById(R.id.userInput);
//set up a listener to run once the ENTER key is hit after their answer has been entered
inputText.setOnKeyListener(new EditText.OnKeyListener(){
public boolean onKey(View v, int keyCode, KeyEvent event){
//only go on the ENTER key when pressed DOWN
if((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)){
EditText innerInputText = (EditText) findViewById(R.id.userInput); //get the EditText box reference
TextView innerUAnswerDisplay = (TextView) findViewById(R.id.userAnswerNumber); //get the TextView box that the answer will go in
String inputString = innerInputText.getText().toString(); //capture the user's input
int uAnswer = Integer.parseInt(inputString); //parse user answer to an integer
int cAnswer = Integer.parseInt((((TextView) findViewById(R.id.answerNumber)).getText()).toString());
innerUAnswerDisplay.setText(Integer.toString(uAnswer)); //display the string after converting from integer
//change colors of text based on correctness
if (uAnswer == cAnswer){ innerUAnswerDisplay.setTextColor(Color.GREEN); } //green for correct
else { innerUAnswerDisplay.setTextColor(Color.RED); } //red for incorrect
innerUAnswerDisplay.setVisibility(View.VISIBLE); //make the user input answer visible
TextView innerAnswer1 = (TextView) findViewById(R.id.answerNumber);
innerAnswer1.setVisibility(View.VISIBLE); //hide answer until user puts in theirs
} //end of if
return false; //return false
} //end of onKey
}); //end of setOnKeyListener
Sorry for all the edits, I couldn't get the edits to include the code and post correctly so I broke it up into chunks and added a little at a time.
From what you say, I'd consider two ways of letting the user answer questions:
have an onclick listener on the input EditText that triggers a new loop;
have a dialog activity that gets started in the beginning of the loop, which prompts the user for a new answer, your game activity would receive the answer via its onActivityResult.

Categories