How can I read a random line from a notecard in LSL? - linden-scripting-language

I have a notecard with a different word on each line, and I'd like to be able to select from the lines randomly. How can I do that?

First, as you mention, you need a notecard. For this example, I'm using one named "colors" with the following contents:
red
blue
green
yellow
orange
purple
With that notecard present, the following script will read and chat a random line from the card each time the prim is touched.
//this script will grab and chat a random line from the "colors" notecard each time the prim is touched.
string card = "colors";
key linecountid;
key lineid;
integer linemax;
integer random_integer( integer min, integer max )
{
return min + (integer)( llFrand( max - min + 1 ) );
}
default
{
state_entry()
{
//get the number of notecard lines
linecountid = llGetNumberOfNotecardLines(card);
}
touch_start(integer total_number)
{
lineid = llGetNotecardLine(card, random_integer(0, linemax));
}
dataserver(key id, string data)
{
if (id == linecountid)
{
linemax = (integer)data - 1;
}
else if (id == lineid)
{
llSay(0, data);
}
}
}

It's not clear why you do such unnecessary math with adding one and then substracting it again later in the answer you give yourself above.
If you want to make sure you have a more random number as there are known issues with the randomness of llFrand you could do (without checking whether the number is even or odd):
integer max;
integer random = llFrand((integer)(max/2)) + llFrand((integer)(max/2));
The second issue with your code above is that you are not checking against CHANGED_INVENTORY and I'm not quite sure why you'd not do that. Following up on this second issue, why do you ask a question to get a random notecard line number and give an answer that provides a random within a range? And what will you do if the notecard changes? Change the code and the notecard? This seems to be redundant to me.
NOTECARD named colors or whatever you set in the script:
blue
red
green
yellow
black
SCRIPT within the same prim:
// this script reads from a notecard which is named whatever you set in init
// in this example from a notecard named "colors"
string ncName;
key ncNumOfLinesReqId;
key ncReqId;
integer numOfLines;
init()
{
// Put the name of your notecard as in the prim's inventory here.
ncName = "colors";
}
default
{
changed(integer change)
{
// reset script to make sure you have the current number of lines
// CHANGED_OWNER has the integer value 0x80 (128)
// CHANGED_INVENTORY has the integer value 0x01 (1)
if (change & (CHANGED_OWNER | CHANGED_INVENTORY))
{
llResetScript();
}
}
state_entry()
{
init();
// get the number of notecard lines
ncNumOfLinesReqId = llGetNumberOfNotecardLines(ncName);
}
touch_start(integer num_detected)
{
// if the number of lines is 0
if (!numOfLines)
{
// PUBLIC_CHANNEL has the integer value 0
llSay(PUBLIC_CHANNEL, "~!~ Unconfigured, check notecard ~!~");
}
else // if number of lines not 0
{
ncReqId = llGetNotecardLine(ncName, (integer)llFrand(numOfLines));
}
}
dataserver(key reqId, string data)
{
if (reqId == ncNumOfLinesReqId)
{
// make sure you typecast!
numOfLines = (integer)data;
}
else if (reqId == ncReqId)
{
// PUBLIC_CHANNEL has the integer value 0
llSay(PUBLIC_CHANNEL, data);
}
}
}
Further information:
The notecard you are reading from does not necessarily have to be in the same prim. If you know the UUID of the notecard, you can read from it as long as it's transferable (and not deleted). Be warned that changing the contents of the notecard and saving, stores the new content under a different UUID. But if you're that skilled, you might as well store the text on a web service and get the text snippet count and text snippets from there.
More on the official Second Life wiki.

Related

Printing number of items in a range from an array in Kotlin

Currently working on a little school assignment, trying to figure out if there is a specific way to print items out of a randomized array. Teacher wants us to generate 200 random numbers in a range of 1 through 100, store them, and then print them with the amount of each range(10s, 20s, 30s, etc). I've gotten the randomization and storage down, but I'm having a little issue trying to figure out how to properly display these.
We should have them separated by how many random numbers are 1-10, 11-20, etc etc, but also with a histograph to the side. I think I can figure out the histograph well enough, but I could use some help on how to display the numbers for each range! I hope this makes sense, any help is appreciated!
What I have so far is very simple, just having a rough time figuring out what goes in the println()
fun main() {
val rnds = (1..200).map { (1..100).random() }
println() // <-- ???
}
it should look something like:
1 - 10: # // <-- number of randomized numbers in that range here
11 - 20: # // <-- number of randomized numbers in that range here
21 - 30: # // <-- number of randomized numbers in that range here
etc etc, all the way until 91 - 100
I should also mention that I'm VERY new to kotlin, and still pretty green to programming in general. The easier the solution, the better, at least until I have a better understanding at what I'm seeing.
You can create your range buckets by using the map function on a range of each starting number of a bucket, and then associateWith to sort the original lists into these buckets:
val byRanges: Map<IntRange, List<Int>> = (1..100 step 10)
.map { it..(it + 9) }
.associateWith { range -> rnds.filter { it in range } }
Then when you want to convert this to text, you can use the joinToString() function on the map entries to format each item as text:
val asText: String = byRanges.entries.joinToString("\n") { (range, list) ->
"${range.start} - ${range.endInclusive}: # ${list.size}"
}
You can increase the "for" loop by range value and filter the list with desired condition to get the item count.
fun main() {
val randomRangeStart = 1
val randomRangeEnd = 100
val list = (1..200).map { (randomRangeStart..randomRangeEnd).random() }
for (i in randomRangeStart..randomRangeEnd step 10) {
println("Range $i - ${i+9}: ${list.filter { it >= i && it <= i+9 }.count()}")
}
}

How to make what function I use in c be controlled by a variable

This is my first year of vex. I am taking on the role of programmer.
I have had this idea for rapid autonomous creation, recording the driver. Instead of the usual array/debugger dump of raw streams of power levels, I had the idea of extracting functions from driver movement.
I wont go into the details, and I can code it myself, but I need some help.
There is one thing I am unable to do simply because of my lack of coding experience.
I want to create a for loop that checks every joystick button one by one.
For example:
struct button
{
bool pressed;
}
for(int i = 0; i>12; i++) //12 is number of buttons on the joystick
{
struct button button<cycle through buttons>;
}
I want there to then be:
struct button button6U;
struct button button6D;
struct button button6R;
etc.
Then, I want this:
for(int i = 0; i>12; i++) // 12 is number of buttons on the joystick
{
if(VexRT[<currentButton>])
{
button<currentButton>.pressed = true;
}
}
I have no idea how to do this, with a wildcard modifing the actual variable name I am writing to.
A couple thoughts:
A for statement would have no idea how to advance the order of joystick buttons. So something I think I might need is:
orderOfButtons
{
VexRT[6U];
VexRT[6D];
VexRT[6R];
// etc.
}
I just cant seem to figure out how to have a variable defining what VexRT[]button I am reading from.
Any help would be appreciated!
Thanks.
Sounds like you want an array:
#define NUMBER_OF_BUTTONS 12
...
struct button VexRT[NUMBER_OF_BUTTONS];
If you want to use symbolic constants to refer to specific buttons in the array, you can use an enumeration:
enum btn_id { BTN_6U, // maps to 0
BTN_6D, // maps to 1
BTN_6R, // maps to 2
...
}
Enumeration constants are represented as integers, and by default they start at 0 and increment by 1. You can initialize them to different values if you want, and multiple enumeration constants can map to the same value. I take advantage of this when I want to identify a "first" and "last" enumeration for looping, like so:
enum btn_id {
BTN_6U,
BTN_FIRST = BTN_6U, // both BTN_FIRST and BTN_6U will map to 0
BTN_6D,
BTN_6R,
...
BTN_whatever,
BTN_LAST
};
Thus, VexRT[BTN_6U] maps to VexRT[0], VexRT[BTN_6D] maps to VexRT[1], etc.
Note that this way, you don't have to loop through all the buttons just to set one:
enum btn_id currentButton = BTN_6D;
...
VexRT[currentButton].pressed = true;
If you do want to loop through the whole set, you can use
for ( enum btn_id i = BTN_FIRST; i < BTN_LAST; i++ )
{
VexRT[i].pressed = false;
}
So, what you want is to sample the user input (at some specified rate), then record it into an array, then play that back at a later time? If you have functions that drive the VEX (I'm not familiar with that), each of which are associated with an input, you can use an array of function pointers to create your output.
#define MAX_ACTION 12
#define MAX_RECORDED 200
// Declare your array of function pointers
int (*action[MAX_ACTION])(void);
// Declare your stored array of recorded actions
int recorded[MAX_RECORDED];
...
// Assign function pointers to associated functions
action[0] = go_forward;
action[1] = turn_right;
...
// Record your actions into some array
while (...)
{
// Record the action
recorded[i++] = get_action();
// Sample delay
}
...
// Playback the actions
for (i=0;i<RECORDED;i++)
{
(*action[recorded[i]])();
// delay here
}
P.S. Your for loop is backward (i<12 not i>12).
I think you are trying to access the events coming from the joystick. You can just loop through the array of values and record them. I think the channels on the joystick are simply accessed like: vexRT[x] where x is 1-12. If you just want to store the latest value from each channel you could do this:
int value[12];
for(i=0; i<12; i++)
{
value[i] = vexRT[i];
}
If you want to store all of the values so that you can map them or play them back or something then you will need a more complex data structure to store them, like a list of the value arrays.
I also have found documentation that says the values are accessed by like vexRT[Chx] where x is 1-12, so you could alternatively create a string and use it to access the joystick channels inside your loop:
string *s = (char *)malloc(5*sizeof(char)); //5 is the max length of the null terminated string
for() . . . {
sprintf(s,"Ch%d", i);
value[i] = vertRT[s];
}

C Table implemented by an array

Basically I'm trying to implement a table with help of an array. The array functionality is already given and should not be altered. What I'm having trouble configuring is my table_remove function. Keep in mind that I'm not striving for the most effective way to do this.
What I tried to do is loop through the entire table to find if there is a key that matches.
If the key is found, save the position.
If not exit.
So after the position is found I set it to free the key & value on that position in hope that it will 'remove' the key & value pair from that position. However, my given test program returns "Removing the last element from a table does not result in an empty table.". If I add in the end "array_setVal(array, NULL, index) then the entire program crashes (Probably because it tries to write on that null position further on in the test).
So now I'm wondering if I'm approaching this issue the wrong way and have to do further operations to actually remove the value from the position without sort of messing up the position itself so next time I use table_insert, the position will be empty and another key & value pair will be inserted in that spot.
int saveRemovedIndex = -1;
/* Check if the key already exists */
for(int indexCounter = 0; indexCounter <= MAXINDEX; indexCounter++){
i = array_inspectValue(t->values, indexCounter);
if (t->cf(i->key,key)==0) {
saveRemovedIndex = indexCounter;
break;
}
}
/* Checks if the key actually exists in the table.
* If it exists, remove it. Else quit.*/
if (saveRemovedIndex != -1) {
i = array_inspectValue(t->values, saveRemovedIndex);
if(t->keyFree!=NULL) {
t->keyFree(i->key);
}
if(t->valueFree!=NULL) {
t->valueFree(i->value);
}
} else {
return;
}

Processing - How to log Strings in txt file?

Im getting more and more frustrated on why this is not doing what i want to. I need to have a text file that logs the last 10 buttons the user pressed, i tried in two ways but…
…this code only saves the last button pressed:
String [][] buttonsPressed = { {"Pressed one"}, {"Pressed two"} };
String[] sum;
void setup() {
size(700, 350);
sum = loadStrings("scores.txt");
}
void draw() {
}
void keyPressed() {
if ((key=='1')) {
saveStrings("scores.txt", buttonsPressed[0]);
}
if ((key=='2')) {
saveStrings("scores.txt", buttonsPressed[1]);
}
if ((key == ENTER)) {
printArray(sum);
}
}
…this code saves the buttons pressed but overwrites itself when i run the sketch again (probably has something to do with createWriter):
PrintWriter sum;
void setup() {
size(700, 350);
sum = createWriter("scores.txt");
}
void draw() {
}
void keyPressed() {
if ((key=='1')) {
sum.println("pressed one");
}
if ((key=='2')) {
sum.println("pressed two");
}
if ((key == ENTER)) {
sum.flush();
sum.close();
String[] lines = loadStrings("scores.txt");
for (int i = 0; i <= 9; i++) {
printArray("[" + i + "] " + lines[i]);
}
}
}
Is there a simple way to do this without using libraries ? Please get me in the right direction :)
Break your problem down into smaller steps.
Step 1: At the beginning of your program, read in the existing history file. Store them in some kind of data structure, like an array or an ArrayList.
Step 2: Make the data structure keep track of the last 10 buttons pressed. You'll need to write code that adds the newest button pressed to the end of the data structure, and if the data structure contains more than 10 items, you have to remove the oldest item. Maybe do this in a separate example sketch where you just print the data structure to the console and don't worry about outputting it to a file just yet.
Step 3: Output the data structure to a file. You don't have to worry about appending to the file because your data structure contains the entire history, so you can just overwrite the file with the entire data structure. You'll probably want to do this every time the data structure changes. Again, maybe do this in a separate example program before worrying about where the data is coming from: maybe make a program that outputs an array of random numbers every time the user clicks?
Focus on one small step at a time, and try creating small example programs for each step. Then when you get stuck, you can ask a specific question and provide an MCVE, and we'll go from there. Good luck.

ActionScript 3 sort an array with numbers and letters not working as expected

I'm trying to sort the users cards in a card game, for example all user's aces to stand close to each other.
I'm using this:
p1cards is an array with elements like "c8", "d9", "h1", letters stand from card symbol (Club, Diamond, Hearts) and number is the card value (1 is Ace, 2 is 2, and so on)
p1cards.sort(sortOrder);
function sortOrder(a,b)
{
var aN = parseInt(a.substr(1));
var bN = parseInt(b.substr(1));
if (aN > bN)
{
return 1;
}
else
{
return -1;
}
}
The problem is that sorted card like the 8d, 8c are switching places to 8c, 8d, kind of randomly, when I draw a new card.
Any help will be apreciated.
See in picture below:
http://i.stack.imgur.com/2Ticj.jpg
You don't define in your sort what to do when the values are the same, so depending what item gets slotted in as a and which is b (which you have no control over) will determine the order. Tell your sort function what to do when the items are the same:
function sortOrder(a,b)
{
var aN = parseInt(a.substr(1));
var bN = parseInt(b.substr(1));
if(aN == bN){
//they are the same, so add a secondary sort based off suit
var aS = a.substr(0,1); //grab the first character which is the suit
var bS = b.substr(0,1);
if(aS > bS) return 1;
if(bS > aS) return -1;
return 0;
}
if (aN > bN)
{
return 1;
}
else
{
return -1;
}
}
If you have an undefined behaviour that you are not happy with, simply define the behaviour that you like.
In your case, if both numbers are the same, evaluate the card symbol additionally.
this makes the order of two cards unambigiously clear and the sort operation (for these two cards) idempotent.

Resources