Discussion
Eduard Lebedyuk · Jul 8, 2021

DC Challenge: If you can read this...

Hey Community,

Here's a new CodeGolf challenge for you! Check the details in this post.

image

Task

You'll have to translate a string into a Pilot's alphabet (NATO phonetic alphabet).

Input:

If, you can read?

Output:

India Foxtrot, Yankee Oscar Uniform Charlie Alfa November Romeo Echo Alfa Delta ?

Note:

  • The set of used punctuation is ,.!?
  • Punctuation should be kept in your return string, but (original) spaces should not
  • Xray should not have a dash within
  • Every word and punctuation mark should be separated by a space ' '
  • There should be no trailing whitespace
  • Use this code to check the result length
  • You also can use this test case here

Share your solutions in comments!
Shortest answer wins!

Code Golf index

7
2 519
Discussion (32)4
Log in or sign up to continue

my 1st attempt:

N(t) s a="Alfa,Bravo,Charlie,Delta,Echo,Foxtrot,Golf,Hotel,India,Juliett,Kilo,Lima,Mike,November,Oscar,Papa,Quebec,Romeo,Sierra,Tango,Uniform,Victor,Whiskey,Xray,Yankee,Zulu"
 f i=1:1:$l(t) s %=$E($zcvt(t,"U"),i) w $s(%?1A:$p(a,",",$a(%)#32)_" ",%=" ":"",1:%)

Line1=174  Line2=84  Total=258

Out of curiosity, I checked the size of the underlying OBJ code:
> object size = 380  (+47% !)  + timestamp = 18

So the expected gain is not what you would assume at first sight.
For the  price of an almost unreadable code 

While true, that's a rabbit hole that will generally be quite unrewarding as you continue down through the language/abstraction layers to the underlying machine code.

"Code golf" in my experience has never been about the size of the final executable ... it's all about how little you have to write to solve the problem.

Updated

Class CodeGolf.NatoTranslator
{

ClassMethod ToNato(i As %String) As %String
{
 s l="lfa,ravo,harlie,elta,cho,oxtrot,olf,otel,ndia,uliett,ilo,ima,ike,ovember,scar,apa,uebec,omeo,ierra,ango,niform,ictor,hiskey,ray,ankee,ulu"
 f j=1:1:$l(i){s k=$e(i,j),o=$g(o)_" "_$s(",.!?"[k:k,1:$zcvt(k,"U")_$p(l,",",$a(k)#32))} q $zstrip(o,"<=W")
}

ClassMethod Test(val = "If, you can read?") As %Status
{
  set res = ..ToNato(val)
  zw res
  #dim methodObj As %Dictionary.MethodDefinition
  set methodObj = ##class(%Dictionary.MethodDefinition).IDKEYOpen($ClassName(), "ToNato")
  Write !,"Size: ", methodObj.Implementation.Size
}

}

Size: 255

You can make it smaller by removing the #dim, which is not required.

The only time I use #dim is if I am working with a class that I have got to via an object chain:

set class=##class(%Dictionary.CompiledClass).%OpenId("MyClass") for i=1:1:class.Properties.Count() set tProp=class.Properties.GetAt(i)  write !,prop.Name

In that case, I will use '#dim tProp as %Dictionary.CompiledProperies' as I don't remember all of the properties in the CompileProperties class. Once the code works, I remove the #dim.

If you are a masochist and like a little pain, here is a lengthy description of another scenario where I use #dim where I have many very similar classes in content, and I use a lot of $clssmethods and $properties in my code. 

Let us assume you have three message classes. The message classes will have some properties that are common to all message classes, and the message classes differ only in the fields they contain that are derived from the source system that created the message:

The base properties are the Create/Process/Completed TimeStamps, RequestFHIRJSON, ResponseFHIRJSON, RequestHL7Message, ResponseHL7Message, FileDirectory, SourceFileName, ResponseFileName, HTTPMethod, HTTPResponseCode, RequestStatus, MessageStatus, MessageTextNotification and a few others.

The HL7 or FHIR message that is created by a Data Transform (DTL) that transforms data in the source database into the target HL7 or FHIR message

The Message also contains the HL7 or FHIR response message (Operation Outcome in the case of FHIR, ACK/NACK for HL7)

Yous have methods to CreateMessage(), UpdateMessage(), GetNextMessage(), Complete Message(), ResendMessage(), PurgeMessages()

The variable properties in my three examples are:

1) PatientID for Message 1

2) PatientNumber, VisitNumber, EpisodeNumber, ActivityDate for Message 2

3) Hospital Folder Number in Message 3

The Methods I have listed all contain $classmethod calls, and I don't really need to worry about the fields specific to the type of message. If I am creating a message or updating a message, I pass an array of DataTypes into the method where the 'key' in the array is the property name, and the 'Value' is the value for that property.

I do use the %Dictionary.CompiledClass definition for the Message Class definitions so that I can determine whether the Property referenced in the Array of Datatypes is a %Library Data Type, a Foreign Key or Designative reference to a value in another class or a Collection/Array/List so that I know whether I am just setting the property value in my message object to the value in the Array of Property Values or if the property value is the ID of an object in another class in which case I will use a SetObjectIdAt() on the value and in the case of the List/Array Collections I either use SetAt() or InsertAt(). As I am using the CompiledClass Dictionary reference, I check to see if the property in the Array of Datatypes exists in the properties of the message class. However, in my Business Process, I want to get the Message fields because they will tell me what Class/Table I will access using the data supplied to retrieve the source record fed into the DTL to generate the FHIR/HL7 message. 

The Business Process has been passed an Ensemble Request message with the MessageId returned by the GetNextMessage() method, which my Business Service calls. The Business Service has a property "Message Queue Class Name" configured when I add the service to the production.

The Business Process Opens the Message Object and in that case I use a #DIM purely that when I use 

set obj=$classmethod({message_Queue_Class_name},"%OpenId",{Message_Id})

set tPatientId=obj.PatientId, and because I have used #dim the editor will provide a list of property names as I type in obj. and that makes it easier to select the field that I want to access. I have used simple examples for the variable fields in my different message class examples. Still, as my Message Queue Classes have about 15 common Properties, it is useful to have that IntelliSense functionality so that I don't have to keep remembering whether my common property name was SourceFHIRMessage or SouirceMessageFHIR. 

Once my code works, I comment out the #dim line rather than remove it so that if someone else has to maintain my code, they can uncomment the #dim statement. It may then help them with the Intellisense on the Property Names on the class being Manipulated.

While not actually competing in this exercise, I would suggest that both of you could shorten your comma-delimited list by 26 characters with the realization that the first character of each entry is already supplied by the input string laugh

N(i) s l="lfa7ravo7harlie7elta7cho7oxtrot7olf7otel7ndia7uliett7ilo7ima7ike7ovember7scar7apa7uebec7omeo7ierra7ango7niform7ictor7hiskey7ray7ankee7ulu"

 f j=1:1:$l(i) s c=$e(i,j),o=$g(o)_$s(",.!?"[c:c,c?1a:$e(" ",j>1)_c_$p(l,7,$a(c)#32),1:"")

q o

; 243 chars

; save 2 quote characters by using a number (7) as the delimiter

; save characters by not $ZCVT to upper, $A(k)#32 works fine for lower and upper

;save on $ZSTRIP of whitespace by only adding space character for every letter after 1st one

; ensure to follow the rules on allowed punctuation and exclude all other characters

can save 4 more characters with

$p("lfa7ravo7harlie7elta7cho7oxtrot7olf7otel7ndia7uliett7ilo7ima7ike7ovember7scar7apa7uebec7omeo7ierra7ango7niform7ictor7hiskey7ray7ankee7ulu",7,$a(c)#32)

instead of 's l=' and '$p(l,'

One additional modification to @Stuart Strickland's most amazing attempt:

N(i)
 j=1:1:$l(i) c=$e(i,j),o=$g(o)_$s(",.!?"[c:c,c?1a:$e(" ",j>1)_$ZCVT(c,"U")_$p("lfa77harlie7elta7cho7oxtrot777ndia7777ike7ovember7scar777omeo777niform7777ankee",7,$a(c)#32),1:"")
 o

180 192 characters, assuming Unix line endings and a ridiculously limited use case that still solves the problem devil

EDIT: Added 12 characters to add fix for capitalized output ...

Or how about this (again, with thanks to @Stuart Strickland)?

N(i,s)
 j=1:1:$l(i) c=$e(i,j),o=$g(o)_$s(",.!?"[c:c,c?1a:$e(" ",j>1)_$ZCVT(c,"U")_$p(s,7,$a(c)#32),1:"")
 o
 

114 characters cheeky

Who needs the Nato alphabet in the code when you can pass it as a parameter? laugh

(I'll stop now, I know I'm getting silly)

q:$zcrc(i,7)=3969309436 $e($zwunpack("䤠摮慩䘠硯牴瑯‬慙歮敥传捳牡唠楮潦浲䌠慨汲敩䄠晬⁡潎敶扭牥删浯潥䔠档汁慦䐠汥慴㼠"),2,*) q ""

  1. Might not be correct in about one out of every 4 billion cases.

f j=1:1:$l(i) s c=$e(i,j) w $s(",.!?"[c:c,c?1a&($a(c)<128):$e(" ",j>1)_$zcvt(c,"U")_$p($zwunpack("晬㝡瑥㝡慨汲敩攷瑬㝡档㝯硯牴瑯漷晬漷整㝬摮慩男楬瑥㝴汩㝯浩㝡歩㝥癯浥敢㝲捳牡愷慰男扥捥漷敭㝯敩牲㝡湡潧渷晩牯㝭捩潴㝲楨歳祥爷祡愷歮敥男畬"),7,$a(c)#32),1:"")

189, with a few fixes.

I'm Impressed. That assumes that a word does not change meaning based on the characters to the left or right. So I assume you have taken that into account in your solution as I believe that Chinese is one of those languages that can mean different things depending on the surrounding words and even tone. But then, China is not part of NATO, so the question is academic.

How about French? Does anyone have a French example of conveying masculine/feminine attributes in the resultant interpreted message? i.e. how do you ensure you get your Le's and La's right?

Ok, now it's me being silly. I suspect there is no shorter version of this code, so well done to the winner.

It's a nice $zwunpack unicode trick, Nigel:

It's basically the same bytes but grouped into a larger unicode symbols.

Se o código é para ser pequeno e o alfabeto pode ser passado como parâmetro, então, que tal se o código também for passado como parâmetro:

ClassMethod  ToNato ( As  % String , As  % String , As  % String , As  % String ) As  % Integer
{
o
}

Teste ClassMethod  ( val  = "If, you can read?" ) As  % Status
{
  a = "Alfa, Bravo, Charlie, Delta, Echo, Foxtrot, Golf, Hotel, India, Juliett, Kilo, Lima, Mike, November, Oscar, Papa, Quebec, Romeo, Sierra, Tango, Uniform, Victor, Whisky, Raio X, Yankee, Zulu"
  s= ","
  i = val
  x = "fj = 1: 1: $ l (i) sc = $ e (i, j), o = $ g (o) _ $ s (" ",.!? "" [c: c, c = "" "": "" "", 1: $ e ("" "", j> 1) _ $ p (a, s, $ a (c) # 32)) " 
  set  res  = .. ToNato ( a , s , i , x )
  zw  res
  #dim  methodObj  As  % Dictionary.MethodDefinition
  set  methodObj  = ## class ( % Dictionary.MethodDefinition ). IDKEYOpen ( $ ClassName (), "
  "Tamanho:" , métodoObj . Implementação . Tamanho
}

leaving aside that there are  evident typing errors that break the code
your reply underlines that the criteria: "Shortest answer wins!"
misses the precise definition of what is measured.
There is not much chance to be shorter than "x x q o"  (= 7 char)

Desculpe, acho que quando colei do Studio ele acabou embaralhando o codigo, mas o correto é o abaixo.

ClassMethod ToNato(a As %String, s As %String, i As %String, x As %String) As %Integer
{
    x x q o
}

ClassMethod Test(val = "If, you can read?") As %Status
{
  S a="Alfa,Bravo,Charlie,Delta,Echo,Foxtrot,Golf,Hotel,India,Juliett,Kilo,Lima,Mike,November,Oscar,Papa,Quebec,Romeo,Sierra,Tango,Uniform,Victor,Whiskey,Xray,Yankee,Zulu"
  s s=","
  S i=val
  s x="f j=1:1:$l(i) s c=$e(i,j),o=$g(o)_$s("",.!?""[c:c,c="" "":"""",1:$e("" "",j>1)_$p(a,s,$a(c)#32))" 
  set res = ..ToNato(a,s,i,x)
  zw res
  #dim methodObj As %Dictionary.MethodDefinition
  set methodObj = ##class(%Dictionary.MethodDefinition).IDKEYOpen($ClassName(), "ToNato")
  Write !,"Size: ", methodObj.Implementation.Size
}

O "Xecute" foi a carta na manga.

I bet, this one, with 6 chars only, is shorter

ClassMethod ToNato(t  = "If, you can read?" ) [ CodeMode = expression ]
{
..s(t)
}

ClassMethod s(t)
{
// whatever solution you have, put it there.
}

Oh, believe me, I can top even myself

include macrodefs
ClassMethod ToNato(t  = "If, you can read?" ) [ CodeMode = expression ]
{
$$$S
}

ClassMethod s(t)
{
// whatever solution you have, put it there.
}

macrodefs.inc
#define S ..s(t)

Are four chars short enough?  

Today, I'm just cheeky and devilish

Well, in that case:

ClassMethod ToNato(t) [ CodeMode = call ]
{
^S
}

And write everything in the S routine.

Nice solution, but just one question, how gets your S routine the parameter <t>?

Is there some trick, I don't know? I would have written this way

ClassMethod ToNato(t) [ CodeMode = call ]
{
^S(t)
}

but then makes 5 chars

All arguments are passed automatically:

And the routine:

Results in:

Good Morning Vietnam... ach, I meant Good Morning Julius!

After 1977 (the year I first met Mumps) now is the time to learn M the right way and entirely!

OK, the truth is, I never usd neither the call nor the expression codemode., hence there was no need to check, how parameter passing works...angry

put it into %ZLANGC00 as ZY

and just have 

ClassMethod ToNato(t)   {
  ZY
} 

I'm not going to win, but I thought I'd try a slightly different approach. With thanks to others for the clever $P part.

ClassMethod N(As %String, As %String = "") As %String
{
$S(i="":"",1:$S(".,?!"[$E(i):p_$E(i),i?1A.E:p_$ZCVT($E(i),"U")_$P("lfa7ravo7harlie7elta7cho7oxtrot7olf7otel7ndia7uliett7ilo7ima7ike7ovember7scar7apa7uebec7omeo7ierra7ango7niform7ictor7hiskey7ray7ankee7ulu",7,$A($E(i))#32),1:"")_..N($E(i,2,*)," "))

Size: 252

I claim the least number of lines - 1 - and least commands - 1 - and probably the least variables - 2.

Could do without the second input param if you allow a leading space in the output (not mentioned in requirements, but fails for the example output, etc.). I also noticed that the sizing does not include the ClassMethod... line, so you could reduce it by moving strings to default values for input variables, but I think that's much like the other comments that involved moving the implementation outside the method completely, just cheating the counting mechanism rather than solving the problem. :-)

Hi. If you mean the "For" loop, then it's replaced by recursion - the method calls itself. Basically, it translates only the first character of the string and then appends the rest of the string as converted by the same method. Which then does the same, and so on until it has run out of characters, and it then unwinds the stack putting it all together. Only good for small strings of course, as it could run out of stack space, a common problem with recursion. (That and getting your head around what it's doing!)

By the way, in the original post the example Output should have a space between "Foxtrot" and ",".