Morse Code

by Jack Fearn: L6 Age ~16

Introduction

Morse code translation is a suitably challenging programming exercise for students, and solutions in several languages are available on websites. Jack's program MorseCode (now available as a web version) translates from a string of characters to its Morse code equivalent. It both displays the Morse as dots and dashes (with a space added to represent the end of each character and a slash to represent the end of each word) and outputs it as sound. You can also input the dots and dashes with Morse punctuation and the program will translate it to the string of characters that it represents. Jack provides useful information about Morse code and also links to a the web site for further details, creating a nicely finished product.

A string array stores each string of dots and dashes at the index equal to the ASCII value of the character it represents. Decryption is trickier than encryption. Jack uses string manipulation neatly to separate a Morse stream into individual character strings for decryption, which he then achieves by linearly searching the array. Helpfully, the program outputs error messages in red when the input cannot be translated.

The following screenshots show a decryption, an encryption and a transmission.

Morse code translated to text

Text translated to Morse code

Morse code transmitted

Compile the program using Lazarus because it the uses the Clrscr procedure in the crt unit (which not built into Delphi) or see how to download and use crt in Delphi in our Graphics tutorial.

The Program

```program MorseCode;
{

use this file except in compliance with the License, as described at
}
{\$mode objfpc}{\$H+}

uses
Classes, SysUtils, Crt, ShellAPI, Windows;

{\$IFDEF WINDOWS}{\$R MorseCode.rc}{\$ENDIF}

const
Pitch = 902;
Dot = 75;
Dash = 200;

var
Morse_Ascii : Array[1..90] of String =
({1}'','','','','','','','','','','','','','','','','','','','','','',
'','','','', '','','','','',{32}'/ ',{*No proper code for '!'*}'',
{34}'.-..-. ','','','','','.----. ', '-.--.- ', '-.--.- ','','','--..-- ',
{45}'-....- ','.-.-.- ','-..-. ','----- ','.---- ','..--- ','...-- ','....- ',
{53}'..... ','-.... ','--... ','---.. ','----. ','---... ','','','-...- ','',
{63}'..--.. ','.--.-. ',{'A'}'.- ','-... ','-.-. ','-.. ','. ','..-. ','--. ',
{72}'.... ','.. ','.--- ','-.- ','.-.. ','-- ','-. ','--- ','.--. ','--.- ',
{82}'.-. ','... ','- ','..- ','...- ','.-- ','-..- ','-.-- ',{'Z'}'--.. ');
Signal : String;
Choice, i : Integer;
Error :  Boolean;

Procedure Instructions;
var
handle : HWND;
begin
Clrscr;
Writeln('Morse Code is transmitted through different combinations of two signals: ');
Writeln;
Writeln('''.'' - short signal (often called "dots" or "dits")');
Writeln('''-'' - long signal (often called "dashes" or "dahs")');
Writeln;
Write('Press Enter to continue...');
Clrscr;
Writeln('This program uses the . and - symbols (full stop and hyphen)');
Writeln('The morse code is written as so: ');
Writeln;
Writeln('".... . .-.. .-.. --- / .-- --- .-. .-.. -.. "');
Writeln;
Write('Press Enter to continue...');
Clrscr;
Writeln('Each space represents the end of a character,');
Writeln('breaking the sequence up so it can be understood.');
Writeln;
Writeln('Each forward slash, represents the end of a word.');
Writeln('This must also be followed by a space.');
Writeln;
Writeln('Punctuation and numbers have their own set of signals.');
Writeln('Code must be input this way for the computer to understand.');
Writeln;
Writeln('For further online information, Press 1, or to go back to the menu, Press 2.');
Case Choice of
1 : begin
Writeln('Your browser will now direct you to www.learnmorsecode.com');
Delay(2000);
Shellexecute(handle, 'open', pchar('http://www.learnmorsecode.com/'), nil,nil, sw_show);
Delay(5000);
Writeln('Press Enter to continue');
end;
2 : begin
end;
end; //Case
end;

Procedure Transmit(SignalX : String);
begin
Clrscr;
Writeln('Transmitting...');
Writeln;
Delay(500);
For i := 1 to (Length(SignalX)) do
begin
Case SignalX[i] of
'-' : begin
Windows.Beep(Pitch,Dash);
Write ('-');
end;
'.' : begin
Windows.Beep(Pitch,Dot);
Write('.');
end;
' ' : begin
Delay(300);
Write('/ ');
end;
end; //Case
Delay(80)
end; //For i
Writeln;
Writeln;
Writeln('Sent!');
end;

Procedure Encrypt;
var
Passage : String;
CharCount : Integer;
begin
Clrscr;
Signal := '';
Writeln('Enter passage to be encrypted. Press Enter when complete.');
gotoxy(1,15);
Writeln('A : .-        B : -...      C : -.-.      D : -..       E : .   ');
Writeln('F : ..-.      G : --.       H : ....      I : ..        J : .---');
Writeln('K : -.-       L : .-..      M : --        N : -.        O : --- ');
Writeln('P : .--.      Q : --.-      R : .-.       S : ...       T : -   ');
Writeln('U : ..-       V : ...-      W : .--       X : -..-      Y : -.--');
Writeln('Z : --..      0 : -----     1 : .----     2 : ..---     3 : ...--');
Writeln('4 : ....-     5 : .....     6 : -....     7 : --...     8 : ---..');
Writeln('9 : ----.     " : .-..-.    '' : .----.   ( or ) : -.--.- ');
Writeln(', : --..--    - : -....-    . : .-.-.-    / : -..-. ');
Writeln(': : ---...    ; : -.-.-.    = : -...-     ? : ..--..    @ : .--.-.');
gotoxy(1,2);
CharCount := Length(Passage);
Passage := UpperCase(Passage);
For i := 1 to CharCount do
begin
If Ord(Passage[i]) < 90 then
begin
Signal := Signal + (Morse_Ascii[Ord(Passage[i])]);  // For playback with windows beep // turn Code on screen Red/Green when played?
Write(Morse_Ascii[Ord(Passage[i])]);
end; //If Ord
end; //For i
Transmit(signal);
end;

Procedure Decrypt;
var
StartCode, Code, Letter, Translation : String;
a, x, y,  SpacePos : Integer;
begin
Clrscr;
Translation := '';
Writeln('Enter code to be decrypted. Press Enter when complete.');
gotoxy(1,15);
Writeln('A : .-        B : -...      C : -.-.      D : -..       E : .   ');
Writeln('F : ..-.      G : --.       H : ....      I : ..        J : .---');
Writeln('K : -.-       L : .-..      M : --        N : -.        O : --- ');
Writeln('P : .--.      Q : --.-      R : .-.       S : ...       T : -   ');
Writeln('U : ..-       V : ...-      W : .--       X : -..-      Y : -.--');
Writeln('Z : --..      0 : -----     1 : .----     2 : ..---     3 : ...--');
Writeln('4 : ....-     5 : .....     6 : -....     7 : --...     8 : ---..');
Writeln('9 : ----.     " : .-..-.    '' : .----.   ( or ) : -.--.- ');
Writeln(', : --..--    - : -....-    . : .-.-.-    / : -..-. ');
Writeln(': : ---...    ; : -.-.-.    = : -...-     ? : ..--..    @ : .--.-.');
gotoxy(1,3);
Code := StartCode;
a := Length(Code);
If not (Code[a] = ' ') then       // Most likely error when writing in
begin
Code := Code + ' ';
a += 1;
end; //If not
Repeat
Error := True;
SpacePos := Pos(' ',Code);
Letter := Leftstr(Code, SpacePos);
Code := Rightstr(Code,(a-SpacePos));
a := Length(Code);
For i := 32 to 90 do
begin
If Letter = Morse_Ascii[i] then
begin
Translation := Translation + (Char(i));
Error := False;
end; //If Letter
end; //For i
Until (Error = True) or (Code = '');
If Error = True then
begin
Writeln;
Writeln('Error! Unable to decipher code:');
Writeln;
x := Pos(Letter,StartCode);
y := WhereY;
Writeln(StartCode);
Writeln;
gotoxy(x,y);
textcolor(red);
Writeln(Letter);
textcolor(white);
end
else
begin
Writeln(Translation);
end; //If Error
end;

begin
Repeat
Writeln('Morse Code Encrypter & Decrypter');
Writeln('1 - Encrypt');
Writeln('2 - Decrypt');
Writeln('3 - Code instructions/Help');
Writeln('4 - Quit');
Case Choice of
1 : begin
Encrypt;
end;
2 : begin
Decrypt;
end;
3 : begin
Instructions;
end;
4 : begin
halt;
end;
end; //Case
clrscr;