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

Morse code translated to text

Text translated to Morse code

Text translated to Morse code

Morse code transmitted

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;
{
    Copyright (c) 2011 Jack Fearn

    Licensed under the Apache License, Version 2.0 (the "License"); you may not
    use this file except in compliance with the License, as described at
    http://www.apache.org/licenses/ and http://www.pp4s.co.uk/licenses/
}
{$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...');
  Readln;
  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...');
  Readln;
  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.');
  Readln(Choice);
  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');
          Readln;
        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!');
  Readln;
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);
  Readln(Passage);
  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
  Readln;
  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);
  Readln(StartCode);
  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
  Readln;
end;

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

Remarks

Could you write your own Morse code translator?

Programming - a skill for life!

Student programs to inspire you!