Problem z kodowaniem i odkodowywaniem języka Morse'a w C/C++


(Nereczko) #1

Mam problem z napisaniem programu, który będzie tłumaczył zdania na kropki i kreski (alfabet Morse'a). O ile zdefiniowanie zwykłych liter nie przysparza najmniejszego problemu, to tabela z literami przedstawionymi w języku Morse'a ,w którym większość liter przedstawiana jest jako więcej niż jeden znak, daje się we znaki. Czy ma ktoś pomysł na to jak mam sobie poradzić z tymi */- w najprostszy sposób ( moja znajomość języka C lub C++ nie jest zbyt świetna)?

Przy okazji jeszcze jedno pytanie:

Jak sprawić, żeby oprócz tłumaczenia, można było zobaczyć "sygnał świetlny" (mały kwadrat np. żółty lub biały) i usłyszeć dźwięk odpowiadający kropkom i kreskom po przetłumaczeniu na Morse'a ?

Z góry dziękuję za odpowiedzi :slight_smile:


(kostek135) #2

Jak dla mnie najlepiej zrobić mapę gdzie kluczem będzie char (odpowiednia litera) a wartością string (ciąg który należy wypisać). Ewentualnie zauważ, że w ASCII litery wielkie i małe są obok siebie. Można więc użyć zwykłej tablicy translując litery na ich kody.

Przykładowo 0-25 małe 26-51 duże

  1. Jeśli mała litera z tablicy translacji weź indeks litera - 97

  2. Jeśli duża litera z tablicy translacji weź indeks litera - 65 + 26 -> litera - 39

Możesz też nie robić przesunięć (szybciej), a zadeklarować chunk 128 komórek napisów i wpisać w odpowiednie miejsca to co chcesz, milion sposobów - nawet ifami / switchem się zaklepać na śmierć.


(Nereczko) #3

podejrzewam, że to co napisałeś pomogłoby komuś, kto dłużej w tym siedzi, jednakże potrzebuję odpowiedzi, którą zrozumie nawet kompletny laik (czyli ja), ale i tak dzięki :slight_smile:


(stalesz) #4

W DP jest taki program Morsik,dość stary z dżwiękiem tylko z głośnika systemowego.Może Ci ułatwi pracę.

http://www.dobreprogramy.pl/Morsik,Prog ... 11625.html


(kostek135) #5

Ok jeszcze raz litera to tak naprawdę cyfra. Jak zajrzysz do tablicy ascii, to zobaczysz, że 'a' = 97, 'A' = 65, 'B' = 66 itp.

Zrób tablice napisów o np. 128 komórkach.

I teraz napisanie,

tab['a'] = "pies";

powoduje, że przy

printf("%s", tab['a']);

wypisze tobie pies. Zamiast pisać pies pod każdą literę wpisz translację. Druga wersja to instrukcja warunkowa http://cpp0x.pl/kursy/Kurs-C++/Poziom-1/Instrukcja-warunkowa-if-else/16 przykładowy kurs.

if(var == 'a') wypisz coś

else if(var == 'b') wypisz coś innego

etc...

Drugiego sposobu nie polecam, ale dla laika co ma czas może być prosty do ogarnięcia.

Map nie tłumaczę, bo i tak nie użyjesz.

PS Skoro jesteś laikiem radzę zmienić język, w C/C++ się tylko umęczysz zarządzaniem pamięcią i wskaźnikami.


(Agatonster) #6

wagina2 ,

Zapoznaj się z tematem i popraw tytuł tematu na konkretny, mówiący o problemie. W celu dokonania zaleconej korekty proszę użyć przycisku Edytuj przy poście otwierającym ten temat.

Zignorowanie zalecenia będzie skutkowało przeniesieniem tematu do Kosza.


(Nereczko) #7

a da radę zrobić coś z tym:

#include 

#include 

#include 


using namespace std;


char NORMAL[46]=

{

'a',

'ą',

'b',

'c',

'ć',

'd',

'e',

'ę',

'f',

'g',

'h',

'i',

'j',

'k',

'l',

'ł',

'm',

'n',

'ń',

'o',

'ó',

'p',

'q',

'r',

's',

'ś',

't',

'u',

'v',

'w',

'x',

'y',

'z',

'ź',

'ż',

' ',

'1',

'2',

'3',

'4',

'5',

'6',

'7',

'8',

'9',

'0'

};

string MORS[46]=

{

MORS[0]="*-",

MORS[2]="*-*-",

MORS[3]="-***",

MORS[4]="-*-*",

MORS[5]="-*-**",

MORS[6]="-**",

MORS[7]="*",

MORS[8]=" **-**",

MORS[9]="**-*",

MORS[10]="--*",

MORS[11]=" ****",

MORS[12]="**",

MORS[13]="*---",

MORS[14]="-*-",

MORS[15]="*-**",

MORS[16]="*-**-",

MORS[17]="--",

MORS[18]="-*",

MORS[19]="--*--",

MORS[20]="---",

MORS[21]="---*",

MORS[22]="*--*",

MORS[23]="--*-",

MORS[24]="*-*",

MORS[25]="***",

MORS[26]=" ***-***",

MORS[27]="-",

MORS[28]="**-",

MORS[29]="***-",

MORS[30]="*--",

MORS[31]="-**-",

MORS[32]="-*--",

MORS[33]="--**",

MORS[34]="--**-",

MORS[35]="--**-*",

MORS[36]="/",

MORS[37]="*----",

MORS[38]="**---",

MORS[39]="***--",

MORS[40]=" **** -",

MORS[41]=" *****",

MORS[42]="- ****",

MORS[43]="--***",

MORS[44]="---**",

MORS[45]="----*",

MORS[46]="-----"

};

int main()

{

	int i,j=0,n;

	printf("Witam\n");

	printf("Podaj tekst do tłumaczenia\n");

	string TABPOMOC;

	getline( cin, TABPOMOC );

	n=strlen(TABPOMOC);

	for(i=0;i<=n;i++)

		{

			while(TABPOMOC[i]!=NORMAL[j])

			{

				j++;

			}

			printf("%s/",MORS[j]); <-- znak / ma na celu pokazanie,że to już koniec litery

		}

mieszanka C i C++...myślałem żeby zrobić tak, żeby te same litery w różnych językach miały takie same indeksy...przy okazji proszę o ocenę funkcji zamiany na morse'a ,bo podejrzewam,a w ręcz jestem pewien, że mam ten fragment źle i można to zrobić łatwiej i krócej...


(kostek135) #8
#include 

#define MORSE_NONE NULL


const char* morse_ascii[] = {

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    "", MORSE_NONE, "", "", /* , _ . / */

    "-----", "", "", "", /* 0 1 2 3 */

    "", "", "", "", /* 4 5 6 7 */

    "", "", MORSE_NONE, MORSE_NONE, /* 8 9 _ _ */

    MORSE_NONE, "", MORSE_NONE, "", /* _ = _ ? */

    MORSE_NONE, "*-", "", "", /* _ A B C */

    "", "", "", "", /* D E F G */

    "", "", "", "", /* H I J K */

    "", "", "", "", /* L M N O */

    "", "", "", "", /* P Q R S */

    "", "", "", "", /* T U V W */

    "", "", "", MORSE_NONE, /* X Y Z _ */

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

    MORSE_NONE, "", "", "", /* _ a b c */

    "", "", "", "", /* d e f g */

    "", "", "", "", /* h i j k */

    "", "", "", "", /* l m n o */

    "", "", "", "", /* p q r s */

    "", "", "", "", /* t u v w */

    "", "", "", MORSE_NONE, /* x y z _ */

    MORSE_NONE, MORSE_NONE, MORSE_NONE, MORSE_NONE,

};


int main() {

	char in;


	while((in = getchar()) > 31) {

		printf("%s ", morse_ascii[in]);

	}


	return 0;

}

Wpisz zgodnie z komentarzem swoje translacje, bo tego już za ciebie nie zrobię. Wpisałem ci przykładowo '0' i 'A', dla sprawdzenia sobie jak to działa._ w komentarzu znaczy, że odpowiednia pozycję należy pominąć <=> nie dotykaj MORSE_NONE, to po prostu zaznaczenie, że tam nie ma kodu w morsie, który jest odpowiednikiem w ascii. Być może coś pominąłem, ale tak jak mówie - przejrzyj tablicę ASCII + uzupełnij.


(Nereczko) #9

ten Twój kod niczym nie przypomina mojego :stuck_out_tongue: czyli mam rozumieć, że mój jest zupełnie zły?


(kostek135) #10

Tak. Kiepskie jest podejście naiwne (przeszukanie liniowe całej tablicy tłumaczeń do znalezienia jednego tłumaczenia). Możesz to zrobić O(1) jeśli potraktujesz litery jako liczby.

Poza tym nie wiem co rozumiesz przez zły dla mnie zły == nieoptymalny dla innego jak nie działa.

Poza tym teraz znalazłem błąd logiczny nie czyścisz j co literę zwiastuje crash dla pewnych testów.

PS poza tym pod czym go kompilowałeś, jeśli kompilowałeś, bo nawet poprawiając takie babole jak sprawdzenie strlen rozmiaru stringa -> jest string::size, to i tak przy pierwszym uruchomieniu, zanim dojdzie do wczytywania dostaję SF.


(Nereczko) #11

a jak zrobić żeby obsługiwał też polskie znaki ?


(kostek135) #12

http://forum.4programmers.net/Newbie/19 ... _znaki_c++


(Nereczko) #13

jak już tak mi pomagasz, to może znasz sposób na to, żeby przy okazji, oprócz wypisywania tego Morse'a, dawało jeszcze sygnał dźwiękowy...to co udało mi się zrobić to bipanie odnoszące się tylko do pierwszego znaku np. w *- tylko do * :slight_smile:


(kostek135) #14

Nie mam pojęcia, bo standard c++ tego nie przewiduje, być może istnieją zewnętrzne biblioteki to realizujące. Ale i tak będą zależne od systemu / kompilatora. Co mogę poradzić to umieść informację o używanym systemie i kompilatorze, być może ktoś inny odpowie.


(Nereczko) #15

A nie da rady jakoś w tej pętli wcisnąć coś co będzie rozpoznawać znaki morsa i od razu je bipać? coś w stylu:

while((in = getchar()) > 31)

   	{

      printf("%s/", morse_ascii[in]);

      while(//warunek odpowiedni//)

	  {

		if(morse_ascii[in]="*")

      	{

      		Beep(700, 300);

      		Sleep(10);

      	}

      	if(morse_ascii[in]="-")

      	{

      		Beep(700, 1000);

			Sleep(10);

      	}

      }

-- Dodane 28.01.2013 (Pn) 21:22 --

a odnośnie "sygnału świetlnego" coś poradzisz? :slight_smile:


(kostek135) #16

Na początku dodaj

#include

zmień ciało pętli w następujący sposób

printf("%s ", morse_ascii[in]);


int length = strlen(morse_ascii[in]);


for(int i = 0; i < length; i++)

    if(morse_ascii[in][i] == '*')

        rob cos

    else

        rob cos innego

Rozwiązanie tymczasowe - na szybko - docelowo lepiej utworzyć drugą tablicę z długościami -> wyliczasz raz funkcja strlen liczy długości każdorazowo - co jest niepotrzebne biorąc pod uwagę, że są to const char*. Niestety w C napisy nie miały przechowywanej długości, stąd polecam zrobić podobną tablicę do wcześniejszej - tylko przechowywać ilość znaków. Przy dłuższych tekstach może być warto.

"Grafika" też nie jest standardowo dostępna, być może da się jakoś dostać do API klawiatury? I migać diodą od num locka na przykład - pogooglaj dobry programista sam rozwiązuje swoje problemy.


(Rolek0) #17

Na Windowsie mozna migać diodami klawiatury symulując wciśnięcia klawiszy

void kliknij(WORD k) //symuluje wciśnięcie i puszczenie klawisza

{

	INPUT in[2] = {};

	in[0].type = INPUT_KEYBOARD;

	in[0].ki.wVk = k;

	in[1].type = INPUT_KEYBOARD;

	in[1].ki.wVk = k;

	in[1].ki.dwFlags = KEYEVENTF_KEYUP; //puszczenie klawisza

	SendInput(2, in, sizeof(INPUT));

}


// Num Lock - VK_NUMLOCK

// Caps Lock - VK_CAPITAL

// Scroll Lock - VK_SCROLL

// Kana Mode - VK_KANA (na japońskich klawiaturach)

Stan klawisza można pobrać funkcją GetKeyState, która zwaraca warość 16-bitową, najstarszy bit wskazuje czy klawisz jest wciśnięty, a najmłodszy czy przełączony (nie wszystkie klawisze mają diody ale wszystkie są przełączalne).

bool wcisniety(int k) { return (GetKeyState(k) & 0x8000) != 0; }

bool przelaczony(int k) { return (GetKeyState(k) & 0x0001) != 0; }

wagina2 (dlaczego akurat taki nick?? :wink: ), jeśli chciałabyś się douczyć C++ to polecam http://xion.org.pl/productions/texts/coding/megatutorial/ oraz http://www.intercon.pl/~sektor/cbx/. Warto też poczytać http://gynvael.coldwind.pl/?id=238. Miłej zabawy :wink: