Discussion
· 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

Discussion (32)3
Log in or sign up to continue

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.

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

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 ...

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.

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
}

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'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!)