How to RESET the output data on a screen, and not merely clear the screen - reset

A couple of days ago, on a different thread, I asked the question as to how I can represent an output such as "#Grades As : 5" into the output "#Grade As : AAAAA". In other words, I wanted to represent the quantity 5 A's as a string of A's repeated five times. The user Sam Jones very helpfully pointed out to me that I should use a "for" loop:
String gradeLetterA = "A";
for (int i=0; i<tempAs; i++)
longStringA += gradeLetterA;
Now, let me show you my actionPerformed method :
if (e.getSource() == clearScreen) {
checkAndRecordData();
Graphics g = chartPanel.getGraphics();
g.setColor(Color.white);
g.fillRect(20,20,410,52);
g.setColor(Color.black);
g.drawRect(20,20,410,52);
g.setColor( Color.black );
g.drawString( "", chartLeftXA, chartTopYA );
if (e.getSource() == displayLongString) {
Graphics g = chartPanel.getGraphics();
g.setColor(Color.white);
g.fillRect(20,20,410,52);
g.setColor(Color.black);
g.drawRect(20,20,410,52);
g.setColor( Color.black );
g.drawString( "Grade As: " + longStringA, 100, 50 );
My question to you good folks is this : When I click on a JButton button to refresh the display of "AAAAA", the screen goes blank, as it's supposed to. However, when I then choose to input the value of (for example) 6 A's, the display does NOT give me 6 letter A's, but ELEVEN letter A's, ie. AAAAAAAAAAA. In other words, my RESET (or refresh) JButton only clears the screen, but it does NOT erase the previous value. Instead, it ADDS the previous value to the current value and I get the WRONG number of A's when I click the button a second time. Can someone please tell me what line of code I should add to the actionPerformed method to make it right? Or does this line have to go into the create GUI method? I'm completely lost. Any help would be gratefully welcome.

The problem doesn't seem to be in your actionPerformed. It's in the first section of code. You said yourself it doesn't erase the previous value. I think you aren't clearing longStringA
longStringA = "";
String gradeLetterA = "A";
for (int i=0; i<tempAs; i++) {
longStringA += gradeLetterA;
}
You are always writing to the same location on screen: (100, 50). If the problem was not erasing the previous value, then creating 5 As and then 6 As should draw AAAAAA, with the first 5 As perhaps being a little bit more bold than the last one (because AAAAAA was drawn on top of AAAAA).

Related

Unity - Everything freezes on " yield return new WaitForSeconds(); "?

Ok! all of my code in this scene is in one script and one manager object.
all of it is about 700 lines. so I can't put it here.
I tested different things:
1) switch platform from android to
pc/mac
2) test on a previous version
of unity( previous 2017, and current
on is 2018.1 )
none of them solve the problem.
then I change some part of the code that I suspected to cause the problem. ( none of them solve the solution ).
then I started to put Debug.Log()s everywhere. so I found where it freezes.
Here Is the code:
IEnumerator ShowSigns(int Button1State, int EqualState, int Button2State)
{
Debug.Log("ShowSigns");
if (Button1State == 1)
{
OperationOneCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (Button1State == 2)
{
OperationOneIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
if (EqualState == 1)
{
EqualCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (EqualState == 2)
{
EqualIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
if (Button2State == 1)
{
OperationTwoCorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
else if (Button2State == 2)
{
OperationTwoIncorrectSign.GetComponent<CanvasGroup>().alpha = 1;
}
Debug.Log("BeforeWaiting");
yield return new WaitForSeconds(0.3f);
Debug.Log("AfterWaiting");
OperationOneCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationOneIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
EqualCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
EqualIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationTwoCorrectSign.GetComponent<CanvasGroup>().alpha = 0;
OperationTwoIncorrectSign.GetComponent<CanvasGroup>().alpha = 0;
state = GameState.CreateNewProblem;
Debug.Log("EndSigns");
}
I found that it freezes on this:
yield return new WaitForSeconds(0.3f);
Very strange!!!
This is a picture of the game.
The game is a simple game that shows 2 math phrase and player should choose the bigger or equal.
The logic is this way:
1) make new phrases and change the game state to "ChooseAnswer"
2) player press one of 3 buttons and the answer checked and score and other things changes and the ShowSigns coroutine will start and ends after 0.3 seconds. and as you see at the end of the coroutine state changes to "CreateNewProblem".
3) in the Update when CreateNewProblem detects, the code call for the NewProblem() function to make new phrases and at the end of that game state changes to "ChooseAnswer".
this logic repeats over and over until time reaches zero.
a "step" variable increase and decrease by 1 by any correct and incorrect answer. and a variable level = steps/10 determines the difficulty of phrases.
the game works correctly on %98 click On buttons. but usually, it freezes somewhere after step 20. In 21, 23, 27, 34 ... very randomly. but always after 20 and some time no freeze until time ends. and always right before yield return. exactly at the same line.
I read many questions and answers but none of them was helpful. I have no while loop, no while(true), as long as I know and check my code no infinite loop, on StopAllCoroutines ... nothing. and I stuck for 2 days.
thanks all of you for helping.
OH,and Here Is the code file
The cause of the freezing is using Random.Range to control a while loop which is in the code linked in your question. One way to get random number without using the while loop is to generate them into List then remove each one you use. This should prevent Random.Range from freezing Unity.

Script is taking 11 - 20 seconds to lookup up an item in an 18,000 row data set

I have two Google sheets workbooks.
One is the "master" source of lookup data with a key based on manufacturer item #, which could be anything from 1234 to A-01/234-Name_1. This sheet, referenced via SpreadsheetApp.openByUrl, has 18,000 rows and 13 columns. The key column has been converted to plain text and the sheet is sorted by this column.
The second is the "template" where people enter item #s that they need to look up against the master, typically 20 - 1500 items at a time.
The script is in the template. It is very slow and routinely times out after 30 minutes. It was written by someone else and I am new to App Script, but I think I've managed to understand what the script is doing and where the bottleneck is occurring.
It does a bunch of stuff, but this is the meat of the lookup:
var numrows = master.getDataRange().getNumRows();
var masterdata = master.getDataRange().getValues();
var itemnumberlist = template.getDataRange().getValues();
var retreiveddata = [];
// iterate through the manf item number list to find all matches in the
// master and return those matches to another sheet
for (i = 1; i < template.getDataRange().getValues().length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][1].toString() === itemnumberlist[i][1].toString()) {
retreiveddata.push(data[j]);
anothersheet.appendRow(data[j]);
}
}
}
I used Logger.log() to determine that each time through the i loop is taking 11 - 19 seconds, which just seems insane.
I've been doing some google searching and I've tried a couple of different things...
First I tried moving the writing of found data out of the for loop so the script would be doing all of its reading first and then writing in one big chunk, but I couldn't get it exactly right. My two attempts are below.
var mycounter = 0;
for (i = 0; i < template.getDataRange().getValues().length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][0].toString() === itemnumberlist[i][0].toString()) {
retreiveddata.push(masterdata[j]);
mycounter = mycounter + 1;
}
}
}
// Attempt 1
// var myrange = retreiveddata.length;
// for(k = 0; k < myrange; k++) {
// anothersheet.appendRow(retreiveddata.pop([k]);
// }
//Attempt 2
var myotherrange = anothersheet.getRange(2,1,myothercounter, 13)
myotherrange.setValues(retreiveddata);
I can't remember for sure, because this was on Friday, but I think both attempts resulted in the script trying to write the entire master file into "anothersheet".
So I temporarily set this aside and decided to try something else. I was trying to recreate the issue in a couple of sample spreadsheets, but I was unable to do so. The same script is getting through my 15,000 row sample "master" file in less than 1 second per lookup. The only thing I can think of is that I used a random number as my key instead of a weird text string.
That led me to think that maybe I could use a hash algorithm on both the master data and the values to be looked up, but this is presenting a whole other set of issues.
I borrowed these functions from another forum post:
function GetMD5Hash(value) {
var rawHash = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5,
value);
var txtHash = '';
for (j = 0; j <rawHash.length; j++) {
var hashVal = rawHash[j];
if (hashVal < 0)
hashVal += 256;
if (hashVal.toString(16).length == 1)
txtHash += "0";
txtHash += hashVal.toString(16);
Utilities.sleep(100);
}
return txtHash;
}
function RangeGetMD5Hash(input) {
if (input.map) { // Test whether input is an array.
return input.map(GetMD5Hash); // Recurse over array if so.
Utilities.sleep(100);
} else {
return GetMD5Hash(input)
}
}
It literally took me all day to get the hash value for all 18,000 item #s in my master spreadsheet. Neither GetMD5Hash nor RangeGetMD5Hash will return a value consistently. I can only do a few rows at a time. Sometimes I get "Loading..." indefinitely. Sometimes I get "#Name" with a message about GetMD5Hash being undefined (despite the fact that it worked on the previous row). And sometimes I get "#Error" with a message about an internal error.
This method actually reduces the lookup time of each item to 2 - 3 seconds (much better, but not great). However, I can't get the hash function to consistently work on the input data.
At this point I'm so frustrated and behind on my other work that I thought I'd reach out to the smart people on these forums and hope for some sort of miracle response.
To summarize, I'm looking for suggestions on these three items:
What am I doing wrong in my attempt to move the write out of the for loop?
Is there a way to get my hash value faster or utilize a different method to accomplish the same goal?
What else can I try to help speed up the script?
Any suggestions you can offer would be greatly appreciated!
-Mandy
It sounds like you hit on the right approach with attempting to move the appendRow() call out of the loop. Anytime you are reading or writing to a spreadsheet you can expect the individual call to take 1 to 2 seconds, so this will eat up a lot of time when you get matches. Storing the matches in an array and writing them all at once is the way to go.
Another thing I notice is that your script calls getValues() in the actual for loop condition statement. The condition statement is executed each time on each iteration of the loop, so this is potentially wasting a lot of time even when you don't have matches.
A final tweak that may be helpful depending on your desired behaviour. You can stop the inner for loop after it finds the first match, which, if you only care about the first match or know there will only be one match, will save you a lot of iterations. To do this, put "break" immediately after the retreiveddata.push(masterdata[j]); line.
To fix the getValues issue, Change:
for (i = 1; i < template.getDataRange().getValues().length; i++) {
To:
for (i = 1; i < itemnumberlist.length; i++) {
And that fix along with the appendRow issue, and including the break call:
for (i = 1; i < itemnumberlist.length; i++) {
for (j = 0; j < numrows; j++) {
if (masterdata[j][0].toString() === itemnumberlist[i][0].toString()) {
retreiveddata.push(masterdata[j]);
break; //stop searching after first match, move on to next item
}
}
}
//make sure you have data to write before trying to write it.
if(retreiveddata.length > 0){
var myotherrange = anothersheet.getRange(2,1,retreiveddata.length, retreiveddata[0].length);
myotherrange.setValues(retreiveddata);
}
If you are re-using the same sheet for "anothersheet" on each execution, you may also want to call anothersheet.clear() to erase any existing data before you write your fresh results.
I would pass on the hashing approach altogether, comparing strings is comparing strings, so whether they are hashes or actual part numbers I wouldn't expect a significant difference.

Swift: how to change a integer variable name within a method and reassign its value

I am a complete beginner at Swift/programming and am making a noughts and crosses app as part of an online course. I wanted to do this on my own before I saw the solution so my logic may be a bit weird.
I have a function which is called each time a button is pressed (there are 9, one for each square). The function acts to:
i) update the number of turns (which allows me to see who's go it is)
ii) change the picture to X or O
iii) deactivate the button after each turn
iv) calculate is anyone has won by changing the value of that squares potential lines. The numbers I have chosen to do this are 3 and 4 (for noughts and crosses), hence the c = 3 or 4 below. This means that if any winning line adds up to 9 or 12, the game stops as someone has won.
I have 9 variables (Int) that hold the score for each square - they are a1o, a2o, a3o, b1o... i.e all end in "o". In the function I want to add the string of "a1" in front of the "o", meaning each button is only relevant to itself with only one line of code above the function (within the button parentheses).
The function looks like this at the moment; calling it by: button(a1, buttonValue: "a1")
func button(buttonName: UIButton, buttonValue: NSString) -> String {
let a = buttonName
var b = buttonValue
b = (b as String) + "o"
print(b)
// the above prints "a1o", the name of the variable, but it is a string...
index += 1
print("Go number \(index)")
if index % 2 == 0 {
// show a nought
a.setImage(UIImage(named: "nought.png"), forState: UIControlState.Normal)
c = 3
// the above line doesn't work as its a string, but I am attempting to set the squares value to 3 (i.e. a1o = 3)
winner()
a.userInteractionEnabled = false
} else {
// show a cross
a.setImage(UIImage(named: "cross.png"), forState: UIControlState.Normal)
c = 4
// the above line doesn't work as its a string
winner()
a.userInteractionEnabled = false
}
return "done"
}
What I can't figure out is how to change the common stem of the variable *a1*o by not making it a string, or if I do, how I convert it back to a variable.
I am struggling with definitions and as a result looking for an answer has been hard. The variable a1o is an integer, but how do I refer to a1o itself?
Thank you in advance,
Sam
It is not possible to access variables dynamically by name like you want to do. However, there are better ways to accomplish the same goal. How about a two-dimensional array?
var scores: [[Int]] = [[0,0,0], [0,0,0], [0,0,0]]
scores[0][1] = 4 //this is the new version of "a2o = 4"
Unlike with variable names, the indices to the array ("0" and "1" in this case) can be dynamically chosen. Or, if you really want to keep your buttons' values exactly the same, you could use a dictionary:
var scores: [String: Int] = [:]
scores[buttonValue as String] = 4

How to skip hidden rows while iterating through Google Spreadsheet w/ Google Apps Script

I have a Google Spreadsheet with many hidden rows in it, and I want to skip them when iterating through a list of rows in the spreadsheet.
It's mainly an efficiency issue, as I'm dealing with over half of my rows being hidden and in no need of being checked.
Any help would be appreciated.
New API as of 2018 that's useful for this problem: isRowHiddenByUser. See also isRowFilteredByUser.
There's no direct way of doing this in Apps Script, but there is a feature request open to provide a way get the show/hide status of a row, if you want to star it.
A workaround using SUBTOTAL. Create 2 columns A and B. A must always have a value and B has a set of formulas. These 2 columns look like this:
A | B
---------------------------
1 | =NOT(SUBTOTAL(103, A1))
1 | =NOT(SUBTOTAL(103, A2))
1 | =NOT(SUBTOTAL(103, A3))
SUBTOTAL returns a subtotal using a specified aggregation function. The first argument 103 defines the type of function used for aggregation. The second argument is the range to apply the function to.
3 means COUNTA and counts the number of values in the range
+100 means ignore hidden cells in the range.
The result of SUBTOTAL with a range of 1 cell will be 0 when the cell is hidden and 1 when the cell is shown. NOT inverts it.
Now you can read the column B with your script to know if a row is hidden.
Here's the transposed question and answer: https://stackoverflow.com/a/27846180/1385429
The issue tracker holds that request since Aug 3, 2010 with a Medium priority and just a "Triaged" status. More than 3 years and no signs of solution from the GAS team.
My workaround was to use a special leading character that would indicate the visibility state of the row/column, it is a leading backtick (`) in the cells of top header row/column.
In case if merged cells are used in column headers, then an empty top row should be dedicated just for that functionality until the google engineers will improve the API.
Same applies if there are formulas in the 1st row/column cell(s).
These dedicated rows/columns itself can be hidden.
After starting to use this functionality each show/hide column/row command should be performed from a customized menu, otherwise there'll be errors when iterating through the range programmatically, because of the missing/excessive backtick.
e.g. to hide rows of selected cells the following function is invoked
function hideSelectedRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = SpreadsheetApp.getActiveRange();
// hide rows and add a ` backtick to the header cell
for (var row = range.getRow(); row <= range.getLastRow(); row++)
{
// add backtick only if it isn't there (that may happen when manually unhiding the rows)
var cellHeader = sheet.getRange(row, 1)
var cellHeaderValue = cellHeader.getValue()
if ( !cellHeaderValue.match(/^`/) ) {
cellHeader.setValue('`' + cellHeaderValue)
}
// hide rows of selected range
sheet.hideRows( row );
}
}
and the menu
SpreadsheetApp.getActiveSpreadsheet()
.addMenu("Show/Hide", [
{ name : "Hide Selected Rows", functionName : "hideSelectedRows" },
{ name : "Hide Selected Columns", functionName : "hideSelectedColumns" },
null,
{ name : "Hide Rows", functionName : "hideRows" },
{ name : "Hide Columns", functionName : "hideColumns" },
null,
{ name : "Show Rows", functionName : "showRows" },
{ name : "Show Columns", functionName : "showColumns" },
null,
{ name : "Show All Rows", functionName : "unHideAllRows" },
{ name : "Show All Columns", functionName : "unHideAllColumns" }
])
Once google engineers find the time to improve the onChange event, it will be possible to put those backticks automatically. Currently the changeType is limited to EDIT, INSERT_ROW, INSERT_COLUMN, REMOVE_ROW, REMOVE_COLUMN, INSERT_GRID, REMOVE_GRID, OTHER without any details on which Row/Column was inserted/removed. Looks like the team behind GAS is scanty. I wish they could hire more programmers (khm khm)
As for workaround, it is possible by using SUBTOTAL function which can returns a subtotal for a vertical range of cells.
Syntax is:
SUBTOTAL(function_code, range1, [range2, ...])
where hidden values can be skipped for any of these codes by prepending 10 (to the single-digit codes).
For example 102 for COUNT while skipping hidden cells, and 110 for VAR while doing so.
Related: Google Spreadsheets sum only shown rows at Webapps SE

iPhone context: How do i extract palette information from an image?

Hi everybody: i want to take a picture and retrieve the main color analyzing its palette (i think this should be the easiest way), but i don't know really where to start.
Assuming you have a raw 24 bit RGB image and you want to find the number of times each color appears:
there are really 2 simple ways of doing this:
my favourite is just to create an array of ints for each possible color, then just index into that array and ++ that method does use like 64 meg of memory tho.
another method is to create a linked list, adding to it each time a new color is encountered, the structs stored in the list would store the color and the number of times encountered, its slow to do all the accumulating cause you have to search the whole list for each pixel, but it would be quicker to sort by number of times used, as only colors actually used are in the list (making it more ideal for small images too)
I like a compromise between the two:
take say, red and green to index into an array of linked lists, that way the array is only 256k (assuming it just stores a pointer to the list) and the lists to search will be relatively short because its only the blue variants of the Red,Green color. if you were only interested in the SINGLE MOST used color, I would just store this in a "max color" variable, that I would compare with each time I iterated over a pixel and incremented a color, that way you don't have to go through the whole structure searching for the most used at the end.
struct Pixel
{
byte R,G,B;
}
const int noPixels = 1024*768; // this is whatever the number of pixels you have is
Pixel pixels[noPixels]; // this is your raw array of pixels
unsinged int mostUsedCount = 0;
Pixel mostUsedColor;
struct ColorNode
{
ColorNode* next;
unsigned int count;
byte B;
}
ColorNode* RG = new ColorNode[256*256];
memset(RG,0,sizeof(ColorNode)*256*256);
for(int i = 0; i<noPixels; i++)
{
int idx = pixels[i].R + pixels[i].G*256;
ColorNode*t;
for(t=RG[idx]; t; t = t->next)
{
if(t->B == pixels[i].B)
{
break;
}
}
if(!t)
{
t = new ColorNode;
t->next = RG[idx];
RG[idx] = t;
t->B = pixels[i].B;
t->count = 0;
}
t->count++;
if(t->count > mostUsedCount)
{
mostUsedCount = t->count;
mostUsedColor = pixels[i];
}
}
you might consider using a Binary Tree, or Tree of some kind too, rather than just searching through a list like that. but I'm not too knowledgeable on that type of thing...
Oh yeah... I forgot about memory management.
you could just go through the whole array and delete all the nodes that need deleting, but that would be boring.
if possible, allocate all the memory you would possibly need at the beginning, that would be 256k + sizeof(ColorNode) *noPixels ~= 256 + 2 to 3 times the size of your raw image data.
that way you can just pull nodes out using a simple stack method, and then delete everything in one foul swoop.
another thing you could do is also add the nodes to another link list for ALL allocated nodes as well, this increases the iterating process, adds data to Color node, and just saves having to iterate through the entire array to find lists to delete.