One More Time - Efficiency Winner
Published on 04/07/2021
Here's my submitted code with the total length of 693 characters:
<script runat="server">w="Celebration Celebrate celebrate Music's dancing feeling tonight right, Don't Need, We're can't dance don't gonna right we're yeah, Come Hey! Just Mmm, free just know late more need stop time wait yeah I'm One You all and got on, the too you Oh We do it me no so".split(' ');s="⣰⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⢘⢬⢷⢔♫⣰♫⢥⢹⢨⢰⢧⢕♫⢐⢖♫⢑♫⢘⢮⢸⢩♫⢥⢿♫⢻⢝⢬♫⢲⢛⢬♫⢚⢞⢒♫⣰⣰⣰⢐♫⢲⢨⢠⢞⢼⢽⢗⢖♫⢣⢤⢕♫⢓⢵⢾⢕⢷⢫♫⢙⢯♫⢢⢶⢳⢟♫⢚⢞⢒♫⣰⢑⢴⢜⣀⢦♫⢓⢵⢾⢕⣀⢦♫⢑⢴⢜⣀⢦⣷⣷⣷⣷⣷♫⣷⣷⣷⣷♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒⣷⣷♫⣷⣷⣷⣷".replace(/⣷/g,'♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒♫⢑⢴⢜⣀⢦').replace(/⣰/g,'⢱⢪⢭♫');for(c=0;c<s.length;c++){i=s.charCodeAt(c)-10384;if(i>=0){t=w[i]+' '}if(s[c]=='♫'){t='<br>'}Platform.Response.Write(t)}</script>
If you want to implement it, just paste it on a CloudPage:
<body>
tag of the pageThe code is not perfect and I realized a few things that I could have done differently to make the script shorter by a few characters (which I'll mention down below).
First let's present the code as it would be written if we didn't have the character count constraint on us:
<script runat="server">
var words = "Celebration Celebrate celebrate Music's dancing feeling tonight right, Don't Need, We're can't dance don't gonna right we're yeah, Come Hey! Just Mmm, free just know late more need stop time wait yeah I'm One You all and got on, the too you Oh We do it me no so".split(' ');
var structure = "⣰⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⢘⢬⢷⢔♫⣰♫⢥⢹⢨⢰⢧⢕♫⢐⢖♫⢑♫⢘⢮⢸⢩♫⢥⢿♫⢻⢝⢬♫⢲⢛⢬♫⢚⢞⢒♫⣰⣰⣰⢐♫⢲⢨⢠⢞⢼⢽⢗⢖♫⢣⢤⢕♫⢓⢵⢾⢕⢷⢫♫⢙⢯♫⢢⢶⢳⢟♫⢚⢞⢒♫⣰⢑⢴⢜⣀⢦♫⢓⢵⢾⢕⣀⢦♫⢑⢴⢜⣀⢦⣷⣷⣷⣷⣷♫⣷⣷⣷⣷♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒⣷⣷♫⣷⣷⣷⣷".replace(/⣷/g,'♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒♫⢑⢴⢜⣀⢦').replace(/⣰/g,'⢱⢪⢭♫');
for(c = 0; c < structure.length; c++){
var index = structure.charCodeAt(c) - 10384;
if(index >= 0){
var text = words[index] + ' '
}
if(structure[c] == '♫'){
var text='<br>'
}
Platform.Response.Write(text)
}
</script>
You can see here that the scripts consists of 3 parts:
w
in the minified version) telling us what words should be in the lyricss
) which tells us when words should appear in the songfor
loop that is combining the two variables to output the lyrics on the CloudPageThis variable contains all words found in the lyrics of the Daft Punk hit sorted in such manner that words with the longest character count.
In the submitted code we see this variable starting as a string, but it's immediately turned into an array using the String.split() method - essentially each space in the string serves as a breaking point marking where one array element ends and another one starts. This is done in the name of saving the character count as this way the word array has the length of 276 characters
w="Celebration Celebrate celebrate Music's dancing feeling tonight right, Don't Need, We're can't dance don't gonna right we're yeah, Come Hey! Just Mmm, free just know late more need stop time wait yeah I'm One You all and got on, the too you Oh We do it me no so".split(' ')
while the most compact way of writing the same set of words as an array would take 363 characters which is longer by 87 characters:
w=["Celebration","Celebrate","celebrate","Music's","dancing","feeling","tonight","right,","Don't","Need,","We're","can't","dance","don't","gonna","right","we're","yeah,","Come","Hey!","Just","Mmm,","free","just","know","late","more","need","stop","time","wait","yeah","I'm","One","You","all","and","got","on,","the","too","you","Oh","We","do","it","me","no","so"]
Arrays are objects in JavaScript that work like lists - they can contain multiple elements and each one of them can be accessed by calling their index (their location). To demonstrate this, let's take a fragment of the "words" array (which while being grammatically incorrect, represents my dancing skills quite accurately):
var words = ["We’re", "can't", "dance"];
// Index: 0 1 2
Indexes are zero-indexed which is to say that:
0
,1
, the third one by 2
, etc.We get values stored in arrays by using the name of the array and placing the location of the desired element in square brackets like so:
// Get values of individual array elements:
var firstElement = words[0]; // Result: "We're"
var secondElement = words[1]; // Result: "Can't"
var thirdElement = words[2]; // Result: "Dance"
We know the words now, but don't know when to sing them, so we need to break down the song structure.
The song has:
434 words with the titular lyrics appearing 30 times
117 lines in total (which means we need 116 line breaks
a chorus that's repeated 15 times:
One more time
Music's got me feeling so free
We're gonna celebrate
Celebrate and dance so free
which I managed to get represented in the script with a total of 266 characters.
s="⣰⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⣰♫⣰⢚⢞⢒♫⢺⢡⢳⢟♫⢘⢬⢷⢔♫⣰⢚⢞⢒♫⢺⢯♫⢘⢬⢷⢔♫⣰♫⢥⢹⢨⢰⢧⢕♫⢐⢖♫⢑♫⢘⢮⢸⢩♫⢥⢿♫⢻⢝⢬♫⢲⢛⢬♫⢚⢞⢒♫⣰⣰⣰⢐♫⢲⢨⢠⢞⢼⢽⢗⢖♫⢣⢤⢕♫⢓⢵⢾⢕⢷⢫♫⢙⢯♫⢢⢶⢳⢟♫⢚⢞⢒♫⣰⢑⢴⢜⣀⢦♫⢓⢵⢾⢕⣀⢦♫⢑⢴⢜⣀⢦⣷⣷⣷⣷⣷♫⣷⣷⣷⣷♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒⣷⣷♫⣷⣷⣷⣷".replace(/⣷/g,'♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒♫⢑⢴⢜⣀⢦').replace(/⣰/g,'⢱⢪⢭♫');
You can see the structure is being stored in a string again and that's again done again to save the code length.
The String.split()
method is not used here, because we can treat strings as arrays of characters. This allows us to access each of them with the syntax for accessing array elements, for example if we would want to get the second letter of the word "One" we would call the index [1]
and this would give us the letter n
. Just as with arrays, we can utilize loops to execute the same code on each element of our object or, as in our case, each character.
The Dots
There's a lot of to unpack here, so let's start small with just one character: ⢱
This is known as the Braille pattern dots-1568 and I'll admit I have chosen to use Braille because it simply looked cool in the script. This is the only place where I intentionally ignored the impact on the word count and probably increased the script size by a few characters, but with such a classic song, you need to have your style game on point.
If we use the string method String.charCodeAt()
on this character we can learn that this Unicode-encoded character has a decimal value of 10417
. You know now that the words are stored in an array and that we can access individual elements of them with a number, so you probably know where this is headed - ⢱
is used to get the word "One". If we subtract 10384
from the decimal encoding value, we land at a value of 33
- this is the index of the word "One" in our word array.
Character | CharCode | Index | words[index] |
---|---|---|---|
⢱ | 10417 | 33 | One |
⢪ | 10410 | 26 | more |
⢭ | 10413 | 29 | time |
The Notes and Replacements
The song structure string contains ♫
characters which simply indicate line breaks in the code. The replace methods are used to compress the song structure by expressing parts that are often repeated by a single character in the original string:
Character | Compressed string | Resulting output | Number of occurrences |
---|---|---|---|
⣰ | ⢱⢪⢭♫ | One more time <br> | 30 |
⣷ | ♫⣰⢓⢵⢾⢕⣀⢦♫⢚⢞⢒♫⢑⢴⢜⣀⢦ | <br> One more time <br> Music's got me feeling so free <br> We're gonna celebrate <br> Celebrate and dance so free | 15 |
The allows us to reduce the size needed to represent the structure from 555 to 266 and while I was writing this article I realized I totally missed an opportunity to compress the first chorus:
One more time
We're gonna celebrate
Oh yeah, all right
Don't stop the dancin
It's short, but it could be even shorter:
if
statements could be optimized to become just one if... else
statement index
variable didn't really need to be declaredwhich would reduce the code length by 8 characters, but let's ignore that and explain how it works in the submitted shape:
for(c = 0; c < structure.length; c++){ //1
var index = structure.charCodeAt(c) - 10384; //
if(index >= 0){
var text = words[index] + ' '
}
if(structure[c] == '♫'){
var text='<br>'
}
Platform.Response.Write(text)
}
Here's how the submitted process works:
0
(is not the line break character), temporarily assigns corresponding word and a space to the text
variable (this way we can omit putting spaces into the structure string and have them added automatically)♫
), the the <br>
tag is assigned to the text
variabletext
value to the body of the CloudPagePlatform vs Core library
Marketing Cloud developers have two libraries that they can choose, but in this case selecting the winner was quite simple when the function responsible for writing the output of the code to the page is used only once - it's was better to just use the default Platform.Response.Write()
function which itself is rather long, but still shorter by 8 characters than the total length of the Write()
function and the required process of loading the Core
library:
Platform.Response.Write(t) // 26 characters
Platform.Load("core","1");Write(t) // 34 characters
It was a fun challenge and I feel I got lucky with it winning despite many missed opportunities for further optimization. Let's just hope that in the future we'll get a chance to compete in a challenge like this ⢱⢪⢭
.
I'm using decimal charcodes of Unicode characters to pull respective words from an array of words.