zegarek w notatniku w c++

0

Witam.

Mam za zadanie napisać program, który będzie rysował w notatniku zegarek ze wskazówkami, które wskażą podaną godzinę. Może mi ktoś podpowiedzieć, jak to zrobić ? Mógłbym zrobić to łopatologicznie, czyli miliard COUT'ów i IF'ów dla każdej minuty i godziny, ale... Znacie jakiś prostszy sposób ?
Ma to być zegarek, rysowany prostymi znakami / | \ oraz liczby 1-12. Okrągły taki :) Nie musi mieć jakieś ramki czy czegoś, wystarczą liczby ułożone na okręgu.

Dodatkowo wymaga się ode mnie, żeby program działał pod linuxem i można było podać godzinę podczas wywoływania programu z konsoli (np. zegar.o 15 30).

Pierwszorzędną sprawą jest jednak sam zegar, ale mile widziane będą podpowiedzi odnośnie kolejnych problemów. Nie wstawiam żadnego kodu napisanego przeze mnie, bo nie chcę zaczynać pisać tego łopatologicznie, a innego sposobu nie znam.

Z góry dziękuję za podpowiedzi i pozdrawiam.

1

narysuj ten zegarek takimi znaczkami, bo trochę ciężko mi to sobie wyobrazić.
//edIt
Musisz narysować na początku taki zegar, tyle, że musisz zwrócić uwagę na to aby był symetryczny na tyle aby dało to się zalgorytmizować. Jak nam pokażesz to jak może wyglądać taki zegar pomożemy Ci to zalgorytmizować.
Czas możesz wyciągnąć z systemu poprzez na przykład taką klasę:

#ifndef CPPTIME_H
#define CPPTIME_H
#include <ctime>
#include <cstring>
class Time {
  std::time_t t;
  std::tm local;
  char asciiRep[26];
  unsigned char lflag, aflag;
  void updateLocal() {
    if(!lflag) {
      local = *std::localtime(&t);
      lflag++;
    }
  }
  void updateAscii() {
    if(!aflag) {
      updateLocal();
      std::strcpy(asciiRep,std::asctime(&local));
      aflag++;
    }
  }
public:
  Time() { mark(); }
  void mark() {
    lflag = aflag = 0;
    std::time(&t);
  }
  const char* ascii() {
    updateAscii();
    return asciiRep;
  }
  // Roznica w sekundach:
  int delta(Time* dt) const {
    return int(std::difftime(t, dt->t));
  }
  int daylightSavings() {
    updateLocal();
    return local.tm_isdst;
  }
  int dayOfYear() { // Liczba dni od 1 stycznia
    updateLocal();
    return local.tm_yday;
  }
  int dayOfWeek() { // Liczba dni od niedzieli
    updateLocal();
    return local.tm_wday;
  }
  int since1900() { // Liczba lat od 1900
    updateLocal();
    return local.tm_year;
  }
  int month() { // Liczba miesiecy od stycznia
    updateLocal();
    return local.tm_mon;
  }
  int dayOfMonth() {
    updateLocal();
    return local.tm_mday;
  }
  int hour() { // Liczba godzin od polnocy (zegar 24-godzinny)
    updateLocal();
    return local.tm_hour;
  }
  int minute() {
    updateLocal();
    return local.tm_min;
  }
  int second() {
    updateLocal();
    return local.tm_sec;
  }
};
#endif 

main:

 
        Time t;
	cout<<t.ascii();

//Kolejne Edit
Tylko musisz tak narysować ten zegar aby dało się jakoś pokazać która aktualnie jest godzina. Bo mi ciężko Sobie wyobrazić, jak pokazywać wskazówkę znakami ascii.

1

Policz sobie kąt jaki ma tworzyć wskazówka z pionem (y), a następnie, za pomocą funkcji trygonometrycznych będziesz miał stosunek x do y, np. jeśli będziesz miał 45 stopni to dla y = 1, x też jest 1. Jeszcze trzeba wziąć pod uwagę to że znaki są dłuższe niż szersze.

                O
                O
                O    x  
                O  x
                Ox

Tutaj masz przyklad. Podano, że jest pierwsza, liczysz kąt wskazówki godzinowej, wychodzi 30 stopni. liczysz tangens 30. y wychodzi 1, a x to co zwrocil tangens. Musisz rozbić kąty na cztery ćwiartki, bo wiadomo, raz x i y będzie ujemny, raz x dodatni, y ujemny itd. I teraz y przesuwasz o jeden, x o tą wartość z tangensa, tylko pomnożoną razy stosunek długości do szerokości pola znakowego, nie wiem ile to może być.

Pozdro

0
#include <cstdlib>
#include <iostream>
#include <fstream>


using namespace std;

int main(int argc, char *argv[])
{
    ofstream plik;
    plik.open("zegarek.txt");
    plik<<"		12		"<<endl;
    plik<<"             "<<endl;
    plik<<"	 11	        1	 "<<endl;
    plik<<"             "<<endl;
    plik<<"    10			     2	  "<<endl;
    plik<<"             "<<endl;
    plik<<"9				 3"<<endl;
    plik<<"             "<<endl;
    plik<<"    8			     4	  "<<endl;
    plik<<"             "<<endl;
    plik<<"	 7	        5	 "<<endl;
    plik<<"             "<<endl;
    plik<<"		6		"<<endl;
    
      
    system("PAUSE");
    return EXIT_SUCCESS;
}
 

Program rysujący zegar w pliku zegarek.txt.
Tylko że problem jest taki, że zegarek zawsze będzie się rozjeżdżał... W zależności od godziny będzie krzywy w inną stronę.
Kolejne pytanie - jak ustawić środek koła, żeby program wiedział skąd rysować wskazówkę ? Wystarczy w środkową linijkę dać zmienne x,y ? Chyba nie...

@rafal-prog
hmm nie bardzo rozumiem. Co wtedy, jeśli wskazówki będą w różnych ćwiartkach ? I jak program ma liczyć kąt między wskazówkami ? Bo fajnie to wychodzi na podanym przez Ciebie przykładzie, ale jak się mu poda godzinę np. 10:23 to jakoś musi to wyliczyć...

Kurde, skomplikowane to ;)

1
#include <fstream>
#include <cstring>
using namespace std;

const unsigned SZEROKOSC_ZEGARA = 39;
const unsigned WYSOKOSC_ZEGARA = 13;

typedef char Zegar[WYSOKOSC_ZEGARA][SZEROKOSC_ZEGARA];

const Zegar szablon = {
	"                12                    ",
	"                                      ",
	"         11                1          ",
	"                                      ",
	"    10                             2  ",
	"                                      ",
	"9                                 3   ",
	"                                      ",
	"    8                             4   ",
	"                                      ",
	"         7                5           ",
	"                                      ",
	"                6                     "
};

int main() {
	Zegar zegar;
	memcpy(&zegar, &szablon, sizeof(Zegar)); // wypełniasz zegar cyferkami

	/* tu dodajesz wskazówki */
	/* ...   zegar[y][x] = '|'   ... */

	/* zapisujesz wszystko do pliku */
	ofstream plik("zegarek.txt");
	for (unsigned i = 0; i < WYSOKOSC_ZEGARA; i++) plik << zegar[i] << endl;
}
1

Co do malowania wskazówek zapoznaj się z algorytmem rysowania linii

0

dziękuję bardzo za pomoc. Podpowiedz mi tylko jak działa ta wysokość i szerokość zegara, bo co bym tam nie wpisał to i tak nie ma to żadnego wpływu... Chyba, że są to max długości wskazówek.

Postaram się to jakoś ogarnąć, chociaż łatwo nie będzie. Pozostaje jeden problem - program ma działać pod linuxem i godzina ma być podawana podczas włączania programu (np. zegar.o 15 00)

0

Tylko teraz jeszcze parę pytań.Jakim cudem pokazać na tym szablonie godziny : 14, 16, 20, 22? Bo ja chyba nie potrafię..

0
kopernik napisał(a)

Tylko teraz jeszcze parę pytań.Jakim cudem pokazać na tym szablonie godziny : 14, 16, 20, 22? Bo ja chyba nie potrafię..

Podział AM/PM? To dzieci w zerówce mają w programie nauczania...

0
mistico napisał(a)

dziękuję bardzo za pomoc. Podpowiedz mi tylko jak działa ta wysokość i szerokość zegara

To jest rozmiar tablicy przechowującej Twój zegar. Nie zauważasz różnicy bo przecież zegar nie jest skalowany do rozmiaru.

0

Chyba lepiej zapisać to Sobie do stringa i po prostu w nim zamieniać odpowiednie znaczki:

#include <iostream>
#include <string>
#include "Cpptime.h"
using namespace std;

string szablon[] = {
        "                12                    ",
        "                                      ",
        "         11                1          ",
        "                                      ",
        "    10                            2   ",
        "                                      ",
        "9                                    3",
        "                                      ",
        "    8                             4   ",
        "                                      ",
        "         7                5           ",
        "                                      ",
        "                6                     "
};
void Rysuj(char znak,string szablon[],int x=6,int y=17){
    for(int i=0;i<2;i++){
        x++;
        y++;
        szablon[x][y]=znak;
    }
}
void RysujD(char znak,string szablon[],int x=6,int y=17){
     for(int i=0;i<3;i++){
        x--;
        y--;
        szablon[x][y]=znak;
    }
}
int main(){

    const int x=6,y=17;
    szablon[x][y] = 'O';
    Rysuj('*',szablon);
    RysujD('#',szablon);
    for(int i=0;i<13;i++){
        cout<<szablon[i]<<endl;
    }
    return 0;
}

To jest wersja bardzo bardzo początkowa.. i funkcja Rysuj() musi mieć jeszcze wiele wiele linijek, ale od tego można zacząć coś budować,,
Teraz pozostaje kwestia liczenia punktów x,y w zależności od godziny

0

A właściwie najprostszy sposób wydaje się banalny.
Musisz odszukać punty które będą wskazywały na godzinę np. 12. Wystarczy pierwszy punkt czyli (x-1), y, wrzucić je do jakiejś struktury i później od tych punktów zaczynać rysowanie..
Może jest to bardzo łopatologiczne, ale skuteczne.
P.S i co jak co, ale te funkcje które napisałem można umieścić w jednej.. nio i jeszcze tam jest trochę do pisania..

0

@mistico Jak masz godzinę 10.23 to kąt godzinowej będzie (10+23/60)*30 stopni, minutowej wiadomo 23/60 * 360 stopni. sprawdzasz na poczatku w jakiej cwiartce jest kat, a potem jak otrzymasz wynik to albo x albo y jest ujemny np. w 3 cwiartce masz x i y ujemne. Oczywiście na ekranie wspolrzedne beda inaczej rozmieszczone, trzeba odpowiednio dostoswać moją metodę.

Skorzystaj z biblioteki curses , będziesz mógł łatwo wprowadzać znaki na określoną pozycję.

0

Ok, ja w tej chwili widzę tylko jeden problem. Na tarczy którą mamy nie da się pokazać wskazówką na godziny 2,4,8,10. I z tym nie wiem za bardzo co zrobić..
Resztę właściwie już masz.

0

http://cpp0x.pl/kursy/Kurs-New-Curses-C++/19

Ogarniesz w pół godziny, a kod będzie dużo prostszy.

Edit:
Ok, zapomnialem, że to ma być drukowane w notatniku, a nie na ekranie.

@kopernik jak to nie ma tych współrzędnych? Wystarczy utworzyć dwuwymiarową tablicę znaków i tam wypisywać współrzędne.

0
kopernik napisał(a)

Ok, ja w tej chwili widzę tylko jeden problem. Na tarczy którą mamy nie da się pokazać wskazówką na godziny 2,4,8,10. I z tym nie wiem za bardzo co zrobić..
Resztę właściwie już masz.

Dlaczego nie da się pokazać godziny drugiej? Da się, tylko trzeba wyliczyć wszystkie punkty pośrednie. Ja z matmy nie jestem najlepszy dlatego nie rzucę wzorami.
Normalnie przy rysowaniu na ekranie wyliczało się trygonometrią x i y na podstawie kąta wskazówki. Potem wystarczyło już narysować linię od środka do tego punktu. Tu ze względu na "rozdzielczość" może to być trochę problematyczne.
Nasuwa mi się jeszcze pytanie. Jak dokładny ma to być zegar? Co do minuty, kwadransu, pół godziny czy może godziny?

1

Nie widzę sensu stosowania string. Łańcuch nie musi zmieniać swojej długości podczas działania programu, zwykła tablica dwuwymiarowa char'ów wystarczy.
Tak samo nie widzę żadnego sensu stosowania ncurses. Przecież zegarek ma trafić do pliku.

Oznaczmy:
w - szerokość tarczy
h - wysokość tarczy
cx, cy - współrzędne środka tarczy
d - względna długość wskazówki tj. d=1 to wskazówka sięgająca końca tarczy, d=0.5 to wskazówka sięgająca połowy drogi do końca tarczy itp.
n - ilość jednostek czasu na całej tarczy tj. n=12 dla wskazówki godzinowej i n=60 dla wskazówki minutowej
t - ilość jednostek czasu (aktualna godzina / minuta)

Wyznaczamy współrzędne x (kolumna) i y (wiersz) końca wskazówki (uwaga, układ prawoskrętny)
+---X
|
Y

Najpierw może zacznijmy od wyznaczenia współrzędnych w układzie kartezjańskim z punktem (0,0) w centrum tarczy
Zamieńmy czas 't' na kąt wskazówki w radianach (kąt w układzie kartezjańskim czyli liczony lewoskrętnie od osi x)
1.gif
Przyda się sinus i kosinus:
2.gif
3.gif
Teraz z trygonometrii liczymy współrzędne:
4.gif
5.gif

Na koniec zamieniamy współrzędne kartezjańskie na ekranowe:
6.gif
7.gif
i gotowe.

Teraz jedyne co ci pozostaje to narysować linię z punktu (cx,cy) do punktu (x,y).

0

Witam ponownie, przepraszam za brak odzewu, byłem w trasie. Wielkie dzięki za pomoc.

Doszedłem do wniosku, że tarcza zegara jest w sumie nie potrzebna i tylko utrudnia program. Wystarczy, że wskazówki będą układały się w dobrą godzinę. Do tego wystarczy program rysujący dwie linie pod odpowiednim do siebie kątem. Linia G(godzinowa) musi być krótsza od lini M(minutowej). Do tego program musi wiedzieć, czy minutowa jest nad godzinową czy nie, ale to wystarczy podzielić minuty na 5 i sprawdzić, czy wynik jest większy od G.

No i na koniec najważniejsza sprawa, czyli narysowanie tego z jakimś tam punktem odniesienia (srodek tarczy).

Postaram się coś stworzyć z tego co napisał adf88, zobaczymy co wyjdzie...

0

Witam ponownie. Program mam, autorstwa danio, za który bardzo dziękuję. Sam nie dałem rady :) No i program jest w C, a nie w C++ ale to nie szkodzi.

 #include <stdio.h>
#include <stdlib.h>

char clockShield[] =
"                     12                   \n"
"                                          \n"
"            11                 1          \n"
"                                          \n"
"                                          \n"
"      10                             2    \n"
"                                          \n"
"                                          \n"
"                                          \n"
"   9                                     3\n"
"                                          \n"
"                                          \n"
"                                          \n"
"       8                              4   \n"
"                                          \n"
"                                          \n"
"             7                 5          \n"
"                                          \n"
"                      6                   \n";


char symbols[] = { '-', '.', '-', '.', '-', '|', '-', '.', '-', '.', '-', '|' };
int fields[][17] = 
{ 
   { 410, 409, 368, 367, 326, 325, 284, 283, 242, 241, 200, 199, 158, 157 }, // 14 --
   { 409, 370, 331, 292 }, // 4 .
   { 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425 }, // 17 -
   { 409, 456, 503, 550 }, // 4 .
   { 410, 411, 454, 455, 498, 499, 542, 543, 586, 587, 630, 631, 674, 675 }, // 14 --
   { 409, 452, 495, 538, 581, 624, 667, 710 }, // 8 |
   { 408, 409, 450, 451, 492, 493, 534, 535, 576, 577, 618, 619, 660, 661 }, // 14 --
   { 409, 448, 487, 526 }, // 4 .
   { 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, 393 }, // 17 -
   { 409, 362, 315, 268 }, // 4 .
   { 409, 408, 365, 364, 321, 320, 277, 276, 233, 232, 189, 188, 145, 144 }, // 14 --
   { 409, 366, 323, 280, 237, 194, 151, 108 } //8 |
};

int main(int argc, char *argv[])
{
   /*
   for (int i = sizeof(clockShield)-1; i >= 0; i--)
      if (clockShield[i] == '-')
         printf("%d, ", i);
   * 
   * for (int i = 0; clockShield[i] != '\0'; i++)
   *    if (clockShield[i] == '.')
   *       printf("%d, ", i);
   */
   
   if (argc != 4)
   {
      printf("Wymagana ilość argumentów to: 3\n");
      return 1;
   }

   int h = atoi(*(argv + 1));
   int m = atoi(*(argv + 2));
   char *filename = *(argv + 3);
   
   if (h > 12)
      h -= 12;
   h -= 1;
   
   int rest = 5 - (m % 5);
   if (rest < 3)
      m += rest;
   
   m /= 5;
   if (m == 0)
      m = 12;
   m -= 1;

   // duza wskazowka
   for (int i = 0; i < 17 && fields[m][i] != 0; i++)
      clockShield[fields[m][i]] = symbols[m];
   
   // mala wskazowka
   int count = 0;
   for (int i = 0; i < 17 && fields[h][i] != 0; i++, count++);
   
   count = count / 2 + 1;
   
   for (int i = 0; i < count && fields[h][i] != 0; i++)
      clockShield[fields[h][i]] = symbols[h];
   
   
   FILE* pFile = fopen(filename, "a");
   if (pFile == NULL)
   {
      perror("\n");
      return 1;
   }
   else
   {
      fputs(clockShield, pFile);
      fputs("\n", pFile);
      fclose(pFile);
      printf("\nZapis do pliku przebiegł pomyślnie\n");
   }

   return 0;
}

Piszę z kolejnym problemem. W program muszę wbudować kolejki komunikatów msgget. Niestety nie wiem, jak msgget działa, ani co miałby w tym programie robić. Próbowałem coś zrobić, ale nie widziałem w necie, żeby było to jakoś wyjaśnione. Ma ktoś jakiś pomysł ? Dużo z tym roboty będzie ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1