brians Posted April 11, 2012 Share Posted April 11, 2012 I'm attempting to randomly fill 2 out of 8 possible facts into my layout. I've tried to pick apart the Bingo template without much luck. Each fact will feature a variable within the string, but this part hasn't been a problem. The problem I'm having is I don't want the facts to duplicate on a single record. Does anyone out there have a suggestion on how to approach this. Right now I'm running a random number generator as a single rule and then reference this rule in two other 2 rules. Below are the two rules (I've simplified the facts for the example). To avoid duplicates I'm pulling the facts from two seperate pools of facts. It works but isn't a prefered method as it limits the possabilities and requires more facts. Any help would be greatly appreciated. if (Rule("Number1") == "0") { return RawText("Fact 1"); } if (Rule("Number1") == "1") { return RawText("Fact 2"); } if (Rule("Number1") == "2") { return RawText("Fact 3"); } if (Rule("Number1") == "3") { return RawText("Fact 4"); } else { return RawText("Fact 5"); } return ""; ----------------------------------- if (Rule("Number1") == "1") { return RawText("Fact 6"); } if (Rule("Number1") == "2") { return RawText("Fact 7"); } if (Rule("Number1") == "3") { return RawText("Fact 8"); } if (Rule("Number1") == "0") { return RawText("Fact 9"); } else { return RawText("Fact 10"); } return ""; ----------------------------------- Quote Link to comment Share on other sites More sharing options...
step Posted April 11, 2012 Share Posted April 11, 2012 Hi Brian, If I understand correctly what you're trying to accomplish, I think this code should be able to help you: var facts = ["fact1","fact2","fact3","fact4","fact5","fact6","fact7","fact8"]; // Create an array of facts var result = []; // Create an array to hold the facts at random for (var i=0; i<2; i++){ var number = Math.floor(Math.random()*facts.length); // generate a random number between 0 and length of the array result.push(facts[number]); // push the fact into the result array facts.splice(number,1); // remove that fact from the Facts array so that it won't be pulled again } return result; Quote Link to comment Share on other sites More sharing options...
brians Posted April 11, 2012 Author Share Posted April 11, 2012 I'm missing something. I assume it's something I should just know to add to this but I can't figure it out. When I try this in my rule it returns an error - "line 5: ReferenceError: result is not defined". Quote Link to comment Share on other sites More sharing options...
step Posted April 11, 2012 Share Posted April 11, 2012 Did you copy and paste the entire block of code? "result" is the array that's being returned. It's defined here (line 2): var result = []; // Create an array to hold the facts at random Quote Link to comment Share on other sites More sharing options...
brians Posted April 11, 2012 Author Share Posted April 11, 2012 You hit the nail on the head. Somehow I copied it from the forum and managed to delete the one line. After making the correction I received the exact result I was looking for. Thank you very much. You just made my day. Quote Link to comment Share on other sites More sharing options...
brians Posted April 12, 2012 Author Share Posted April 12, 2012 One final sticking point. I need each fact on a seperate line without the commas. I added \r\n to add the returns but connot seem to get rid of the commas. var facts = ["fact1","fact2","fact3","fact4","fact5","fact6","fact7","fact8"]; // Create an array of facts var result = []; // Create an array to hold the facts at random for (var i=0; i<3; i++){ var number = Math.floor(Math.random()*facts.length); // generate a random number between 0 and length of the array result.push(facts[number]+"\r\n"); // push the fact into the result array facts.splice(number,1); // remove that fact from the Facts array so that it won't be pulled again } return result; Quote Link to comment Share on other sites More sharing options...
step Posted April 12, 2012 Share Posted April 12, 2012 Just modify the return code: return result.join("<br>"); And make sure you have "Treat returned strings as tagged text" checked. Quote Link to comment Share on other sites More sharing options...
brians Posted April 12, 2012 Author Share Posted April 12, 2012 Thanks step. I'm on to the next template which uses the same type of random facts however for this one I need to return the facts to seperate frames and flowing them from one frame to the next won't work due to variable lengths and being multi-line in some cases. Is there a way to access the random facts on an individual basis from the original rule below? Quote Link to comment Share on other sites More sharing options...
esmith Posted April 12, 2012 Share Posted April 12, 2012 Put the rule in an OnRecordStart callback rule and remove the term "var" from the 2nd line. Then you can call custom-named text frames from OnRecordStart to auto-populate the various frames in your template, or create multiple text rules that return the various elements from the global array. Quote Link to comment Share on other sites More sharing options...
brians Posted April 12, 2012 Author Share Posted April 12, 2012 Can you give an example of how one of the text rules might look? This is where I'm having difficulty is in understanding how to grab just the first fact or just the second. Actually I thought I had a way in using the commas but that became a problem when the fact contained a comma. Quote Link to comment Share on other sites More sharing options...
step Posted April 12, 2012 Share Posted April 12, 2012 Sure. you can call custom-named text frames from OnRecordStart to auto-populate the various frames in your template FindTextFrame("Fact1").content = result[0]; FindTextFrame("Fact2").content = result[1]; Where the text frames are named "Fact1" and "Fact2" respectively. You access the elements within the array with the brackets and define its position. 0 is the first position, 1 is the second, etc. In this case, the array only has two of the positions filled (your two random facts). or create multiple text rules that return the various elements from the global array Similarly, you could create a rule called "Fact1" (for example) and return the first position in the array: return result[0]; Quote Link to comment Share on other sites More sharing options...
brians Posted April 12, 2012 Author Share Posted April 12, 2012 That's it. Worked perfectly. Thanks for all your help. Quote Link to comment Share on other sites More sharing options...
brians Posted June 12, 2012 Author Share Posted June 12, 2012 I'm now trying to add one more level of complexity to this project. We want to take this script and make it possible for the orderer to fill in up to 20 facts but only make 5 required. If they leave a fact blank the script would skip it and randomly place only those that contain text. Below is the script in it's current state. Can one of you please assist? FusionPro.Composition.repeatRecordCount = Field("Quantity"); var facts = [TaggedDataField("Fact1"),TaggedDataField("Fact2"),TaggedDataField("Fact3"),TaggedDataField("Fact4"),TaggedDataField("Fact5"),TaggedDataField("Fact6"),TaggedDataField("Fact7"),TaggedDataField("Fact8"),TaggedDataField("Fact9"),TaggedDataField("Fact10"),TaggedDataField("Fact11"),TaggedDataField("Fact12"),TaggedDataField("Fact13"),TaggedDataField("Fact14"),TaggedDataField("Fact15"),TaggedDataField("Fact16"),TaggedDataField("Fact17"),TaggedDataField("Fact18"),TaggedDataField("Fact19"),TaggedDataField("Fact20")]; // Create an array of facts result = []; // Create an array to hold the facts at random for (var i=0; i<3; i++){ var number = Math.floor(Math.random()*facts.length); // generate a random number between 0 and length of the array result.push(facts[number]); // push the fact into the result array facts.splice(number,1); // remove that fact from the Facts array so that it won't be pulled again } FindTextFrame("Fact1").content = result[0]; FindTextFrame("Fact2").content = result[1]; FindTextFrame("Fact3").content = result[2]; Quote Link to comment Share on other sites More sharing options...
esmith Posted June 12, 2012 Share Posted June 12, 2012 Not sure if this will work, but how about: FusionPro.Composition.repeatRecordCount = Field("Quantity"); result = []; // global variable containing random facts var facts = []; // Create an array for the provided facts // push only provided fact values into the array for (f=0; f<20; f++) { var currFact = "Fact" + f; if (TaggedDataField(currFact) != "") facts.push(TaggedDataField(currFact)); } for (var i=0; i<5; i++){ var number = Math.floor(Math.random()*facts.length); // generate a random number between 0 and length of the array result.push(facts[number]); // push the fact into the result array facts.splice(number,1); // remove that fact from the Facts array so that it won't be pulled again } FindTextFrame("Fact1").content = result[0]; FindTextFrame("Fact2").content = result[1]; FindTextFrame("Fact3").content = result[2]; FindTextFrame("Fact4").content = result[3]; FindTextFrame("Fact5").content = result[4]; I added a FOR loop to populate the facts array with only fields that actually contain a value. This way your facts array may contain between 5 (assuming you require 5 filled values) and 20 facts to choose from in step's previous code. Quote Link to comment Share on other sites More sharing options...
brians Posted June 12, 2012 Author Share Posted June 12, 2012 I had to make on adjustment to get the expression to pass which was, I changed f=0 to f=1 otherwise it would error ("Error: In Field(), no field named Fact0"). Once this was changed the expression passed but empty variables were still returned during preview. Quote Link to comment Share on other sites More sharing options...
esmith Posted June 13, 2012 Share Posted June 13, 2012 (edited) I had to make on adjustment to get the expression to pass which was, I changed f=0 to f=1 otherwise it would error ("Error: In Field(), no field named Fact0"). Once this was changed the expression passed but empty variables were still returned during preview. Changing the start point of f from 0 to 1 would only process 19 possible facts for insertion. See if the following helps: FusionPro.Composition.repeatRecordCount = Field("Quantity"); result = []; // global variable containing random facts var facts = []; // Create an array for the provided facts // push only provided fact values into the array for (f=1; f<21; f++) { var currFact = "Fact" + f; if (TaggedDataField(currFact) != "") facts.push(TaggedDataField(currFact)); for (var i=0; i<5; i++){ var number = Math.floor(Math.random()*facts.length); // generate a random number between 0 and length of the array result.push(facts[number]); // push the fact into the result array facts.splice(number,1); // remove that fact from the Facts array so that it won't be pulled again } FindTextFrame("Fact1").content = result[0]; FindTextFrame("Fact2").content = result[1]; FindTextFrame("Fact3").content = result[2]; FindTextFrame("Fact4").content = result[3]; FindTextFrame("Fact5").content = result[4]; If this still returns "empty" values, could you upload some sample data to help me determine where I'm going wrong for your specific situation? My guess is that "empty" values still pass something in the field value which causes the IF loop to add false positives. Edited June 13, 2012 by esmith fixed code Quote Link to comment Share on other sites More sharing options...
brians Posted June 13, 2012 Author Share Posted June 13, 2012 The error went away but the result is nearly the same. Blank facts are still being returned and now duplicates are showing up as well. Any additional thoughts? Quote Link to comment Share on other sites More sharing options...
esmith Posted June 13, 2012 Share Posted June 13, 2012 I altered the code in my last post. Give it another try. If you still get blank facts, I will need to see some sample data to understand how "blanks" are slipping through. Quote Link to comment Share on other sites More sharing options...
brians Posted June 13, 2012 Author Share Posted June 13, 2012 The blanks are now gone but duplicates are being returned again. I've attached a simplified project and data file for you to test with. It's very basic for testing purposes.randomfacts.txtRandomTest.pdf Quote Link to comment Share on other sites More sharing options...
esmith Posted June 13, 2012 Share Posted June 13, 2012 In the sample job you provided, you still have the facts array pre-defined with all 20 facts. If you look at my code, you'll see that the array is initially unpopulated. When I made this change in the sample template, the results looked to be what you are expecting. Quote Link to comment Share on other sites More sharing options...
brians Posted June 14, 2012 Author Share Posted June 14, 2012 Sorry about that. I had assumed you just left that for me to fill in. Now I understand how your pulling the facts from the data. It's working as expected. Thanks and sorry for the added confusion. Quote Link to comment Share on other sites More sharing options...
ricky10ss Posted September 10, 2015 Share Posted September 10, 2015 Hello, I was able to use the original code to generate random facts but I need to make an adjustment and wanted to see if someone has a recommendation. This is for a Bingo card where there are questions and the answers will be printed on the Bingo card. So column B should only have 15 answers that are different from the 15 answers in column I for example. I have a data file that has B,I,N,G,O answers separated out and there is a total of 15 answers for each column? Thanks Rick Quote Link to comment Share on other sites More sharing options...
step Posted September 10, 2015 Share Posted September 10, 2015 This is for a Bingo card where there are questions and the answers will be printed on the Bingo card. So column B should only have 15 answers that are different from the 15 answers in column I for example. I have a data file that has B,I,N,G,O answers separated out and there is a total of 15 answers for each column? What does your data file look like? Assuming your B,I,N,G, and O fields contain a list of answers separated by a comma, you could do something like this: var answers = Field("B").split(','); // Create an array of answers var result = []; // Create an array to hold the facts at random for (var i=0; i<15; i++){ var number = Math.floor(Math.random()*answers.length); // generate a random number between 0 and length of the array result.push(answers[number]); // push the fact into the result array answers.splice(number,1); // remove that fact from the Answers array so that it won't be pulled again } return result.join('<br>'); The above code will generate 15 random answers from the 'B' field separated by a break tag (<br>). The idea being that you would apply that rule to a text frame that will make up the "B" column. If you wanted to, you could name all of the "column" text frames by the data field they correspond to (B-O), check "Re-evaluate this rule for every text flow," and apply this rule to each frame: [color="Red"]var column = FusionPro.Composition.CurrentFlow.name; var answers = Field(column).split(','); // Create an array of answers[/color] var result = []; // Create an array to hold the facts at random for (var i=0; i<15; i++){ var number = Math.floor(Math.random()*answers.length); // generate a random number between 0 and length of the array result.push(answers[number]); // push the fact into the result array answers.splice(number,1); // remove that fact from the Answers array so that it won't be pulled again } return result.join('<br>'); Of course you could use a table as well. If you supply a copy of your template, data, or intended output, I'd be able to give you a better idea of how to accomplish this. Quote Link to comment Share on other sites More sharing options...
ricky10ss Posted September 10, 2015 Share Posted September 10, 2015 Hi Step, Attached is the template and data file. Would not want any duplicate answers in any of the Bingo columns. I have text fields for each box as well. ThanksCanstruction Bingo.pdfBINGO Questions.txt Quote Link to comment Share on other sites More sharing options...
step Posted September 10, 2015 Share Posted September 10, 2015 Rather than drawing 25 text frames, you'd be better off generating a table and displaying it in one big text frame. Here's what that would look like: // Link as external data file var ex = new ExternalDataFileEx('BINGO Questions.txt','\t'); // Create an object of each field value var cols = {}; for (var n=0; n<ex.fieldCount; n++) { var col = ex.GetFieldValue(0, n); cols[col] = []; for (var i=1; i<=ex.recordCount; i++) cols[col].push(ex.GetFieldValue(i,col)); } // Shuffle the fields and then take 5 values for (var i in cols) cols[i] = shuffle(cols[i]).splice(0,5); cols['N Answers'][2] = ''; // Free space // Create 1.5" x 1.5" spaces in a 5x5 table var table = new FPTable; table.AddColumns(10800,10800,10800,10800,10800) for (var i=0; i<5; i++) { var row = table.AddRow(); var cell = row.Cells[0]; row.minHeight = 10800; cell.VAlign = "Middle"; cell.HAlign = "Center"; cell.SetBorders('Thin','White','Left','Right','Top','Bottom'); row.CopyCells(0,1,2,3,4); row.SetContents(cols['B Answers'][i],cols['I Answers'][i],cols['N Answers'][i],cols['G Answers'][i],cols['O Answers'][i]); } return table.MakeTags(); /*============================================ / || Shuffle function || http://bost.ocks.org/mike/shuffle/ / ===========================================*/ function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex ; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.