Randomized Names [Ver 1.1]

0 Members and 1 Guest are viewing this topic.

*
The Hero of Rhyme
Rep:
Level 82
( ͡° ͜ʖ ͡°)
2014 Best RPG Maker User - StoryProject of the Year 20142014 Queen of RMRK2011 Best Newbie2014 Best RPG Maker User - Creativity2014 Kindest Member2013 Queen of RMRKBronze SS AuthorBronze Writing ReviewerSecret Santa 2013 ParticipantFor taking arms in the name of your breakfast.GOOD!For frequently finding and reporting spam and spam bots2012 Best Yuyubabe Smiley2012 Best RPG Maker User (Creativity);o

Yuyu Randomized Names
Version: 1.1
Author: yuyu!


Introduction

This plugin will generate random names for characters in your game - which could include NPCs and Actors. It's pretty cool if you want your villagers to have unique names but don't want to sit around and think of something for everyone. Note that names are meant to sound unrealistic and fantasy-esque. These names are calculated from looking at two parts of a name, the start and the end (depending on gender). Most name parts are broken down from real names, but that doesn't mean they won't get pretty odd sometimes.


Features

- Generate a random name for an NPC or actor
- Specify names by gender
- Assign unique IDs to NPCs and use message codes to draw the name
- Can be used to randomize an actor's name before name input for some added flavor
- Change parameters to allow names to be unique (will not generate the same name twice)
- Specify how many names will be unique (includes actors first, then npcs)


Changelog

- Ver 1.1 -

- Added a parameter for a maximum # of unique names (a fail-safe for games that might generate a lot of names and trigger too many loops)
- Cleaned up code


Screenshots

Spoiler for "Screenshots":

^ Actors with randomized names


^ Setup for npc + message code



Download

Click here to download the script (from pastebin)!


Terms of Use

Free for commercial use. Please provide credit and do not claim the plugin as your own. Thanks!


Special Thanks

- LoganF
- Zeriab
« Last Edit: June 29, 2017, 08:08:55 PM by yuyu! »
Spoiler for My Games and Art:
ℒℴѵℯ❤


My Artwork Thread

The Lhuvia Tales [Current]

Ambassador [Complete]

The Postman [Complete]

The Wyvern [Complete]

Phoenix Wright: Haunted Turnabout [Complete]

Major Arcana [Cancelled]


*
? ? ? ? ? ? ? ? ? The nice kind of alien~
Rep:
Level 91
Martian - Occasionally kind
A Yuyu script :D

When you check if the plugin command is Yuyu_RandName I recommend instead checking the lowercase of the plugin command is yuyu_randname
I would rename your argument variables:
Code: [Select]
            var argType = args[0].toLowerCase(); // type
            var argId = parseInt(args[1]); // id
            var argGender = args[2].toLowerCase(); // gender

Keep in mind that your uniqueness loop is likely to run more and more rounds as more names are exhausted. If you end up running through all the names next time you'll have an infinite loop at your hands. Given the large number of possibilities it's probably not that big of a deal, but just something to keep in mind.


Good job! It's nice seeing you become better and better ^_^
*hugs*

*
Rep:
Level 82
It's nice to see you putting up some code, Yu.

I agree with Zeriab on the string literal case advice. When you consider the end user, they may not care or know to pay attention to case sensitivity when writing the plugin command. That can easily become a source of frustration. You seem to have taken notice of that with the args parsing so it might have been an oversight.

Additionally, keep in mind that MV will parse any preceding white space in the command box as a null string, which will then become your command argument. You might want to check if that is the case and take a peek at args[0]. It's probably not like to happen but if it does, it's another source of frustration and potential confusion for the end user.

I also want to comment on the braces. Even for single line statements, include braces. It's a bad habit to get into, and is the source of many bugs - and they do exist in real world code out there (Apple had a case of that a few years ago with their SSL certification validation process; a duplicate 'goto fail;' line ended up in the main body of the function and it exposed a vulnerability in the security). There's often an argument regarding screen real estate efficiency but I find it lacks in comparison to protecting yourself from future bugs and general maintainability of code.

Lastly, a bigger one building on from Zeriab's concern about your loop. This is mostly for learning but feel free to use it practically.

Making use of performance.now() (a built-in function that takes a time stamp that is independent of the system clock), I looked at how long it takes your loop to operate over varying numbers of names used in total in a potential game.

Here's the function that I modified:

Code: [Select]
// Combine name parts together
Yuyu_RandomName.combineParts = function(type, id, gender) {
var start = "", end = "", name = "";

// Initialize variable array (if necessary)
//if (!Array.isArray($gameVariables.value(vId)))
this.initializeArray();

var times = [];
for (var j = 0; j < 100; ++j) {
this.initializeArray();
var t1 = performance.now();
for (var i = 0; i < 4000; ++i) {

// Get start, end, name, then add to data variable
do {
start = start = this.nameStart();
end = (gender == "m") ? this.nameEndMale() : this.nameEndFemale();
name = start + end;
} while (unique == true && this.nameRepeat(name));
// Set actor name or store npc name in variable
$gameVariables.value(vId)[i] = name;
}
var diff = performance.now() - t1;
times.push(diff);
}

var timeTaken = 0;
for (var i = 0; i < 100; ++i) {
timeTaken += times[i];
}
var avgTime = timeTaken / 100;
};

Basically, store 1000 generated names in the array and record the time it takes to complete. I also kept a count of how many times the do/while executed in a single pass to show how often a collision might occur.

Average Time Taken: 4.93ms

So, 1000 names is quite ok. Let's increase that to 2000.

Average Time taken: 20.05ms

Twice the names, and 5x the time taken. Still only 1 retry on average, so that's ok.

Let's double it up again to 4000.

Average Time Taken: 73.61ms

You can already see that it is taking exponentially longer when doubling up the count.

Let's look at 10k names, so increasing the count by 2.5x.

Average Time Taken: 471.47ms

At about 29k names, it starts to get into an infinite loop of retries to find a unique name. So that's around the limit. I figured that out by testing with 100k names but it wouldn't finish. After leaving it for about 20 minutes and then coming back to check where it was (by pausing the code via debug), i was at 29982.

The reason that it takes so long is because you use an Array for storing currently used names. Arrays are great when it comes to indexing or inserting things, but they're terrible for searching through. This is because it has to be done sequentially, from start to finish. In the case of looking to see if a name already exist, it starts from index 0 and runs through to index n, which is either the same name or the end of the array. This makes our "infinite loop" also take longer and longer to try to resolve itself; it's taking seconds (we can assume by deduction from exponential explosion theory) to retry each time a conflict happens.

Instead, I turned the Array into a Map, and used the generated name as a key. I'm only doing this for demonstration and it requires a change to the nameRepeat function. As an implementation to the problem, it isn't ideal at all because you want to be able to refer to names by their ID and this would be ineffecient for that purpose - we'd have to search all values to find a match and that's worse than indexing an array.

The same 10k names took an average of 4.91ms. That's as fast as 1k names with an Array.

Because of how Maps break down when it comes to searching, they're quick for this kind of purpose. In terms of their time complexity (a measurement of time units that an operation takes), Maps have constant time searching whereas Arrays are linear time depending on their size and where the target actually is.

You wouldn't want to use a Map solely for this problem - you really do want the ID number to be the key and not the name itself. You could, however, consider keeping a seperate Map that exists purely for keep a track of currently used names and then store an array of names in the $gameVariables as you are doing. But this comes at a cost of increased memory usage; you're effectively doubling it to save time.

Given that a game won't typically have huge numbers of NPCs, it probably isn't an issue. So take this as a thought exercise that simply points out the ups and downs to what data structure you choose to use. There are multiple solutions to this problem that I can think of from the top of my head which might make for some good learning opportunities.
(Why do I always feel like it's the end of the world and I'm the last man standing?)

*
The Hero of Rhyme
Rep:
Level 82
( ͡° ͜ʖ ͡°)
2014 Best RPG Maker User - StoryProject of the Year 20142014 Queen of RMRK2011 Best Newbie2014 Best RPG Maker User - Creativity2014 Kindest Member2013 Queen of RMRKBronze SS AuthorBronze Writing ReviewerSecret Santa 2013 ParticipantFor taking arms in the name of your breakfast.GOOD!For frequently finding and reporting spam and spam bots2012 Best Yuyubabe Smiley2012 Best RPG Maker User (Creativity);o
Oh, wow!! Thank you guys for taking the time to provide such awesome feedback! ^_^ My knowledge is growing, but still very limited. I'm about to start an intensive training course for an entry level developer position and I'm really happy to have any chances possible to get ahead and learn more about code!

@ Zeriab
Great point on the .toLowerCase() check! I actually totally forgot to run that. ;-; I'll rename those args, too!

@LoganF
OK, I'll try to implement a way to check on that preceding whitespace. :) Also I'm glad you brought up the use of braces - I thought I was being "neater", but then it became more of a bad habit. If anything, the braces would be neater AND safer!

I'm glad you pointed out the flaws of Arrays for searching through so much data! Until just yesterday, I had no idea what a Map even was. I read a few tutorials on it, but I'm still not entirely sure how it works. I'm going to research it and play around with a few tutorials. :)


As for the loop...I'm considering two possible solutions:
1. Having a maximum array size (user defined via parameters), OR
2. Having a maximum uniqueness check value (also user defined)

Either way, I may default the max to 1k names - most people shouldn't get anywhere close to that! The second option sounds potentially less limiting for the player. However, I don't think most people would care (and they could change it anyways). I'm wondering if I would save on memory if the array itself were limited? Though I'm not even sure if that matters because the array pushes the data and grows as needed.
« Last Edit: June 29, 2017, 06:04:26 PM by yuyu! »
Spoiler for My Games and Art:
ℒℴѵℯ❤


My Artwork Thread

The Lhuvia Tales [Current]

Ambassador [Complete]

The Postman [Complete]

The Wyvern [Complete]

Phoenix Wright: Haunted Turnabout [Complete]

Major Arcana [Cancelled]


*
The Hero of Rhyme
Rep:
Level 82
( ͡° ͜ʖ ͡°)
2014 Best RPG Maker User - StoryProject of the Year 20142014 Queen of RMRK2011 Best Newbie2014 Best RPG Maker User - Creativity2014 Kindest Member2013 Queen of RMRKBronze SS AuthorBronze Writing ReviewerSecret Santa 2013 ParticipantFor taking arms in the name of your breakfast.GOOD!For frequently finding and reporting spam and spam bots2012 Best Yuyubabe Smiley2012 Best RPG Maker User (Creativity);o
OK, I updated the script to ver 1.1, based on your feedback! I went ahead and created a parameter to set the max number of unique names.

Thanks again for the help, guys! ^_^
« Last Edit: June 29, 2017, 08:07:05 PM by yuyu! »
Spoiler for My Games and Art:
ℒℴѵℯ❤


My Artwork Thread

The Lhuvia Tales [Current]

Ambassador [Complete]

The Postman [Complete]

The Wyvern [Complete]

Phoenix Wright: Haunted Turnabout [Complete]

Major Arcana [Cancelled]