C (131 caractères)
Oui, 13 1 !
main(c){for(;c=c?c:(c=toupper(getch())-32)?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putch(c/2?46-c%2:0);}
J'ai réussi à obtenir quelques caractères supplémentaires en combinant la logique de l'option while
et for
en une seule for
et en déplaçant la déclaration de la boucle c
dans la variable main
comme paramètre d'entrée. Cette dernière technique, je l'ai empruntée à la réponse de strager à un autre défi .
Pour ceux qui essaient de vérifier le programme avec GCC ou avec des éditeurs uniquement en ASCII, vous aurez peut-être besoin de la version suivante, légèrement plus longue :
main(c){for(;c=c?c:(c=toupper(getchar())-32)?c<0?1:
"\x95#\x8CKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-12]-34:-3;c/=2)putchar(c/2?46-c%2:32);}
Cette version comporte 17 caractères de plus (pour un poids total de 148 caractères), en raison des modifications suivantes :
- +4 :
getchar()
et putchar()
au lieu de la version non portable getch()
et putch()
- +6 : codes d'échappement pour deux des caractères au lieu de caractères non-ASCII
- +1 : 32 au lieu de 0 pour le caractère espace
- +6 : ajouté "
c<0?1:
"pour supprimer les déchets provenant de caractères inférieurs à ASCII 32 (à savoir, de '\n'
). Vous obtiendrez toujours des déchets de n'importe quelle !"#$%&'()*+[\]^_
` {|}~
ou tout ce qui est supérieur à ASCII 126.
Cela devrait rendre le code complètement portable. Compilez avec :
gcc -std=c89 -funsigned-char morse.c
Le site -std=c89
est facultatif. Le site -funsigned-char
est nécessaire, cependant, ou vous obtiendrez des déchets pour la virgule et le point.
135 caractères
c;main(){while(c=toupper(getch()))for(c=c-32?
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"
[c-44]-34:-3;c;c/=2)putch(c/2?46-c%2:0);}
À mon avis, cette dernière version est également beaucoup plus attrayante sur le plan visuel. Et non, elle n'est pas portable, et elle n'est plus protégée contre les entrées hors limites. Il a également une interface utilisateur assez mauvaise, prenant l'entrée caractère par caractère et la convertissant en code Morse et ayant pas de condition de sortie (vous devez frapper Ctrl + Break ). Mais un code portable et robuste avec une interface utilisateur agréable n'était pas une exigence.
Voici une explication aussi brève que possible de ce code :
main(c){
while(c = toupper(getch())) /* well, *sort of* an exit condition */
for(c =
c - 32 ? // effectively: "if not space character"
"•ƒŒKa`^ZRBCEIQiw#S#nx(37+$6-2&@/4)'18=,*%.:0;?5"[c - 44] - 34
/* This array contains a binary representation of the Morse Code
* for all characters between comma (ASCII 44) and capital Z.
* The values are offset by 34 to make them all representable
* without escape codes (as long as chars > 127 are allowed).
* See explanation after code for encoding format.
*/
: -3; /* if input char is space, c = -3
* this is chosen because -3 % 2 = -1 (and 46 - -1 = 47)
* and -3 / 2 / 2 = 0 (with integer truncation)
*/
c; /* continue loop while c != 0 */
c /= 2) /* shift down to the next bit */
putch(c / 2 ? /* this will be 0 if we're down to our guard bit */
46 - c % 2 /* We'll end up with 45 (-), 46 (.), or 47 (/).
* It's very convenient that the three characters
* we need for this exercise are all consecutive.
*/
: 0 /* we're at the guard bit, output blank space */
);
}
Chaque caractère de la longue chaîne du code contient le code Morse codé d'un caractère de texte. Chaque bit du caractère codé représente soit un tiret, soit un point. Un 1 représente un tiret, et un 0 un point. Le bit le moins significatif représente le premier tiret ou point du code Morse. Un dernier bit de "garde" détermine la longueur du code. En d'autres termes, le bit le plus élevé de chaque caractère codé représente la fin du code et n'est pas imprimé. Sans ce bit de garde, les caractères avec des points de queue ne pouvaient pas être imprimés correctement.
Par exemple, la lettre 'L' est " .-..
"en code Morse. Pour le représenter en binaire, il faut un 0, un 1 et deux autres 0, en commençant par le bit le moins significatif : 0010. Ajoutez un autre 1 pour le bit de garde, et vous obtenez notre code Morse codé : 10010, ou 18 en décimal. Ajoutez le décalage +34 pour obtenir 52, qui est la valeur ASCII du caractère '4'. Le tableau de caractères codés contient donc un '4' comme 33ème caractère (index 32).
Cette technique est similaire à celle qui est utilisée pour coder les caractères en ACoolie's , de strager (2) , Miles , de pingw33n , Alec's et Andrea's mais elle est légèrement plus simple, car elle ne nécessite qu'une seule opération par bit (décalage/division), au lieu de deux (décalage/division et décrémentation).
EDIT :
En lisant le reste des implémentations, je vois que Alec et Anon a trouvé ce schéma d'encodage - utilisant le bit de garde - avant moi. La solution d'Anon est particulièrement intéressante, car elle utilise l'algorithme Python bin
et en supprimant la fonction "0b"
et le bit de garde avec [3:]
plutôt que de tourner en boucle et de changer de place, comme Alec et moi l'avons fait.
En prime, cette version gère également le trait d'union ( -....-
), la barre oblique ( -..-.
), deux-points ( ---...
), point-virgule ( -.-.-.
), égale ( -...-
), et au signe ( .--.-.
). Tant que les caractères 8 bits sont autorisés, leur prise en charge ne nécessite aucun octet de code supplémentaire. Il n'est pas possible de prendre en charge plus de caractères avec cette version sans ajouter de la longueur au code (à moins qu'il n'existe des codes morse pour les signes plus grand/moins grand que).
Parce que je trouve que les anciennes implémentations sont toujours intéressantes, et que le texte comporte quelques avertissements applicables à cette version, j'ai laissé le contenu précédent de ce billet ci-dessous.
Ok, on peut supposer que l'interface utilisateur peut craindre, non ? Donc, en empruntant à strager j'ai remplacé gets()
qui fournit une entrée de ligne tamponnée, avec écho, avec getch()
qui permet de saisir des caractères sans tampon et sans écho. Cela signifie que chaque caractère que vous tapez est immédiatement traduit en code morse sur l'écran. C'est peut-être cool. Il ne fonctionne plus avec stdin ou un argument de ligne de commande, mais il est sacrément petit.
J'ai gardé l'ancien code ci-dessous, cependant, pour référence. Voici le nouveau.
Nouveau code, avec vérification des limites, 171 caractères :
W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?c>77|c<31?0:W("œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"
[c-31]-42):putch(47),putch(0);}
Enter interrompt la boucle et quitte le programme.
Nouveau code, sans vérification des limites, 159 caractères :
W(i){i?W(--i/2),putch(46-i%2):0;}c;main(){while(c=toupper(getch())-13)
c=c-19?W("œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"[c-31]-42):
putch(47),putch(0);}
Voici l'ancien code 196/177, avec quelques explications :
W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,c,s[99];gets(s);
for(p=s;*p;)c=*p++,c=toupper(c),c=c-32?c>90|c<44?0:W(
"œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"[c-44]-42):
putch(47),putch(0);}
Ceci est basé sur La réponse d'Andrea en Python en utilisant la même technique pour générer le code morse que dans cette réponse. Mais au lieu de stocker les caractères codables l'un après l'autre et de trouver leurs index, j'ai stocké les index l'un après l'autre et je les ai cherchés par caractère (de manière similaire à ma réponse précédente ). Cela permet d'éviter les longues lacunes vers la fin qui ont posé des problèmes aux premiers implémenteurs.
Comme avant J'ai utilisé un caractère supérieur à 127. La conversion en ASCII uniquement ajoute 3 caractères. Le premier caractère de la longue chaîne doit être remplacé par \x9C
. Le décalage est nécessaire cette fois, sinon un grand nombre de caractères sont en dessous de 32, et doit être représentés par des codes d'échappement.
Comme précédemment, le traitement d'un argument de ligne de commande au lieu de stdin ajoute 2 caractères, et l'utilisation d'un véritable caractère d'espace entre les codes ajoute 1 caractère.
D'un autre côté, certaines des autres routines ici ne traitent pas les entrées en dehors de la plage acceptée de [ ,.0-9\?A-Za-z]. Si ce traitement était supprimé de cette routine, 19 caractères pourraient être supprimés, ce qui ramènerait le total à 177 caractères. Mais si cela est fait, et que des données non valides sont introduites dans ce programme, celui-ci risque de se planter et de brûler.
Le code dans ce cas pourrait être :
W(i){i?W(--i/2),putch(46-i%2):0;}main(){char*p,s[99];gets(s);
for(p=s;*p;p++)*p=*p-32?W(
"œ*~*hXPLJIYaeg*****u*.AC5+;79-@6=0/8?F31,2:4BDE"
[toupper(*p)-44]-42):putch(47),putch(0);}