• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Program rysujacy szachownice

VPS Starter Arubacloud
0 głosów
5,641 wizyt
pytanie zadane 3 listopada 2018 w C i C++ przez Padoski Użytkownik (990 p.)
edycja 3 listopada 2018 przez Eryk Andrzejewski

Chcę napisać program, który wyświetla szachownicę w konsoli, składającą się z przemiennych # i spacji.

Problemem jest to, że działa tylko dla n parzystych. Napisałby ktoś, żebym mógł sobie przeanalizować?

Kod jaki napisałem to:

#include <iostream>

using namespace std;

void drukujLinie(int);
void drukujLinie2(int);
void drukujSzachownice(int);
int main()
{
    int szerokosc;
    cout<<"Podaj szerokosc szachownicy: ";
    cin>>szerokosc;
    drukujSzachownice(szerokosc);

}
void drukujSzachownice(int x)
{
    for(int i=0;i<x/2;i++)
    {
        drukujLinie(x);
        drukujLinie2(x);
    }
}
void drukujLinie(int y)
{
    for(int i=1;i<=y/2;i++)
   {
            cout<<"# ";
   }
   cout<<endl;
}
void drukujLinie2(int z)
{
     for(int i=1;i<=z/2;i++)
   {
            cout<<" #";
   }
   cout<<endl;
}

 

komentarz 3 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Prosiłbym o stosowanie znaków interpunkcyjnych oraz polskich znaków diakrytycznych - dużo przyjemniej będzie się wtedy czytało takie treści, przynajmniej według mnie. smiley

W dodatku, warto zaznaczać język programowania dla kodów w bloczkach - wtedy włączymy kolorowanie składni i to też będzie przyjemniejsze dla oka.

1 odpowiedź

+2 głosów
odpowiedź 3 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)
wybrane 25 listopada 2018 przez Padoski
 
Najlepsza

Ja na szybko napisałem taki kod, z użyciem operatora XOR:

#include <iostream>

int main() {
    std::cout << "Podaj rozmiar: ";
    unsigned size;
    std::cin >> size;
    
    for (unsigned y = 0; y < size; ++y) {
        for (unsigned x = 0; x < size; ++x) {
            if ((y % 2) ^ (x % 2)) {
                std::cout << " ";
            } else {
                std::cout << "#";
            }
        }

        std::cout << '\n';
    }
}

Wyjaśnienie działania kodu

Zmienne x i y to współrzędne wskazujące dane pole naszej szachownicy. Załóżmy, że pole czarne to #', a pole białe to spacja.

Po krótkiej analizie problemu, można dojść do wniosku, że pola będą czarne wtedy, gdy obydwie współrzędne będą parzyste, lub obydwie współrzędne będą nieparzyste. Natomiast pola będą białe wtedy, kiedy jedna ze współrzędnych będzie parzysta, a druga nieparzysta (nie ma znaczenia czy parzysty będzie x, czy y - ważne, żeby były różne).

Parzystość liczby można zbadać stosując operator modulo (%), czyli sprawdzając resztę z dzielenia danej liczby przez liczbę 2.

x % 2

Dla liczb parzystych zostanie zwrócone 0, dla liczb nieparzystych zostanie zwrócone 1.

Warunek w if sprawdza, czy "parzystości" obydwu współrzędnych się czymś różnią - mówiąc prościej, warunek ten zachodzi, gdy jedna współrzędna jest parzysta, a druga nieparzysta.

Gdybyś potrzebował coś dokładniej wyjaśnić, to proszę mówić. smiley

komentarz 3 listopada 2018 przez Padoski Użytkownik (990 p.)
Tak, bylbym bardzo wdzieczny za wyjasnienie. Co daje to zagniezdzenie i jak to rozumiec to XOR  w petli. Czekam na odp Pozdrawiam
komentarz 3 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Szachownica, którą narysuje ten program po wprowadzeniu n=5 będzie wyglądała tak:

Umówmy się, że pierwsza współrzędna to x i dotyczy ona umiejscowienia punktu w poziomie, natomiast druga współrzędna to y i dotyczy ona umiejscowienia punktu w poziomie - tak się to oznacza w matematyce, nie spotkałem się raczej z innymi oznaczeniami.

Współrzędne początku (lewy górny róg) szachownicy to (0, 0). A więc obydwie współrzędne są parzyste. Stąd też, na tym polu znajdzie się znak #.

Weźmy na przykład środek tej szachownicy. Jest to punkt o współrzędnych (2, 2). Znowu obie współrzędne są parzyste, stąd też na tym polu znajdzie się znak #.

Teraz weźmy pole o współrzędnych (1, 3). Tym razem obydwie współrzędne są nieparzyste - znowu na polu znajdzie się znak #.

A teraz weźmiemy odwrotny przykład. Pole o współrzędnych (1, 2) ma jedną współrzędną nieparzystą, a drugą parzystą - a więc wypisujemy spację.

Pole o współrzędnych (4, 1) ma jedną współrzędną parzystą, a drugą nieparzystą - znowu wypisujemy spację.

A jak się ma do tego wszystkiego XOR? Przy operacjach na bitach, XOR działa w taki sposób, że zwraca 0, jeżeli obydwa bity są takie same, albo 1 jeżeli te bity się różnią.

Tabelka prawdy dla XOR:
 

Tabela prawdy dla XOR
p q p ^ q
0 0 0
0 1 1
1 0 1
1 1 0

Warunek w instrukcji warunkowej działa więc tak, że sprawdza, czy jedna ze współrzędnych jest parzysta, a druga jest nieparzysta.

komentarz 3 listopada 2018 przez Padoski Użytkownik (990 p.)

Oki, dziękuję bardzo za wytłumaczenie. Bo miałem problem ze zrozumieniem działania tego zagnieżdżenia pętli. Jeszcze chciałbym się upewnić, czy dobrze rozumiem. Mianowicie:

Pętla y się zaczyna i y przyjmuje 1, a następnie wchodzi do pętli dla x i tam wykonują się pozostałe x aż do size. Czyli dla 5 (1,1), (2,1) (3,1) (4,1) (5,1) i znowu petla y i tak dalej tak ?

A jak mozna w takim razie to inrepretowac bo na osi y =1 bylo by na samym dole,a w konsoli jakby to y=1 to bedzie pierwszy wiersz? Chodzi mi o to zdj szachownicy dla przykladu. Czy y=1 i x aż do 5 beda w pierwszym wierszu tej szachownicy od gory czy moze tym ostatnim? I jeszcze pytanie, co moglbym zmienic w moim kodzie zeby dzialalo dla wszystkich n a nie tylko parzystych? Oraz kolejne pytanie czy da sie to w jednej petli zrobic? Bo takie jest kolejne zadanko by sprobowac w jednej petli to zrobic :) Pozdrawiam

Czy tu y=1 i x <size to bedzie ten wiersz czy moze ten pierwszy od góry?

komentarz 3 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Dobrze to rozumiesz, z różnicą taką, że w moim kodzie założyłem, iż początkowe  współrzędne mają wartość 0, nie 1.

Początek szachownicy to lewy górny róg, rozrasta się ona w prawo i w dół. Więc y = 0 to pierwszy wiersz, y = 4 to ostatni wiersz, x = 0 to pierwsza kolumna od lewej, x = 4 to ostatnia kolumna od lewej.

Szczerze mówiąc, nie wiem co można zmienić w Twoim kodzie. Warunkiem pętli for jest u Ciebie x/2, a to wyrażenie będzie identyczne zarówno dla x parzystego i o jeden większej liczby nieparzystej (taka właściwość dzielenia całkowitoliczbowego), np. 4 / 2 zwróci 2, ale 5 / 2 też zwróci 2 - w związku z tym pętla wykona się taką samą liczbę razy w obu przypadkach. W związku z tym myślę, że po prostu rozwiązanie tego zadania dla ogólnego przypadku (dla liczb parzystych i nieparzystych) wymaga trochę innego podejścia.

Czy da się zrobić w jednej pętli? Zaraz pokombinuję. smiley

komentarz 3 listopada 2018 przez Padoski Użytkownik (990 p.)
Dziekuje bardzo za wytlumaczenie, czekam w takim razie na tę jedną pętlę. Pozdrawiam :)
komentarz 3 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Tyle wykombinowałem:

#include <iostream>

int main() {
    std::cout << "Podaj rozmiar: ";
    unsigned size;
    std::cin >> size;
    
    bool black = true;

    for (unsigned i = 0; i < size * size; ++i) {
        if (black) {
            std::cout << '#';
        } else {
            std::cout << ' ';
        }
        
        black = !black;

        if (i % size == size - 1) {
            std::cout << '\n';

            if (size % 2 == 0) {
                black = !black;
            }
        }
    }
}

Pewnie dałoby się prościej, ale to już może spróbuj samodzielnie. smiley

komentarz 24 listopada 2018 przez Padoski Użytkownik (990 p.)
@Eryk Andrzejewski, sorki ze tak odkupuje, ale mam pytanie co do tego ostatniego(czyli do kodu z uzyciem jednej pętli)

W jaki sposob on dziala? Moglbys go wytlumaczyc? Nie rozumiem m.in. czym jest black = !black.

Bylbym bardzo wdzieczny za wytlumaczenie. Pozdrawiam :)
komentarz 24 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Chciałbym pamiętać. laugh

A teraz na poważnie. Szachownica jest kwadratem o boku size, a więc liczba wszystkich pól to size * size. Każde pole może być czarne (wtedy rysuję znak #) lub białe (wtedy wypisuję spację). Zmienna black definiuje kolor aktualnie omawianego pola, a konkretnie to mówi nam, czy aktualne pole jest czarne. Jest czarne, kiedy wartość tej zmiennej to true. Natomiast kiedy wartością zmiennej jest false, to pole jest białe.

Instrukcja:

black = !black;

Przypisuje do zmiennej black negację jej obecnej wartości - czyli mówiąc prościej, zmienia stan zmiennej na przeciwny. Jeżeli zmienna ma wartość false, to po wykonaniu się tej instrukcji będzie miała wartość true - i odwrotnie, jeżeli ma wartość true, to będzie miała wartość false.

Z każdym kolejnym polem zamieniam ten kolor - fakt ten wynika z obserwacji, że sąsiednie pola szachownicy są inaczej pokolorowane. Natomiast problem pojawia się przy przechodzeniu do nowej linii. Zaraz omówię to dokładniej. Dodam tylko jeszcze, że jeśli program wykryje, że aktualny kafelek jest ostatnim w danym rzędzie (robi to przy użyciu operacji modulo na indeksie kafelka), to przechodzi do nowej linii wypisując '\n'.

Teraz omówię jeszcze owy problem przy przechodzeniu do nowej linii. Można zaobserwować, że jeżeli rozmiar szachownicy jest liczbą nieparzystą, to (patrząc od lewej do prawej, od góry do dołu) ostatni kafelek w danym rzędzie i pierwszy kafelek w nowym rzędzie mają inne kolory - czyli tak jak w przypadku wszystkich innych sąsiednich kafelków - nie musimy niczego modyfikować.

Natomiast gdy rozmiar szachownicy jest parzysty, to owe dwa kafelki powinny mieć ten sam kolor. Jako, że zmieniłem już wartość zmiennej black na przeciwną, to muszę tę czynność powtórzyć, by powrócić do pierwotnego stanu i pierwszy kafelek w nowym rzędzie miał taki sam kolor, jak ostatni kafelek w obecnym rzędzie.

komentarz 25 listopada 2018 przez Padoski Użytkownik (990 p.)
Oki zrozumiałem, prawie wszystko oprócz jednej rzeczy. Mianowicie: dajmy np. ze wybieram sobie szachownice o wymiarze 5x5.

I teraz nurtuje mnie takie coś,że w tej pętli zachodzi preinkrementacja.

Czyli zaczyna nam od i=1, bo zajdzie te preinkrementacja, wiec to przejście do nowej lini musi zajść dla i =4 bo wtedy 4%5=4 czyli tyle samo co size(5)-1. W takim razie jezeli jest ta preinkrementacja, to jakby ten iterator w tym pierwszym wierszu bedzie kolejno 1,2,3,4 i tutaj 5 juz nie przyjmie, więc wykonały się tylko 4 kafelki? Wiem ze zle rozumuje chyba, dlatego jakbys jeszcze mi to mogl wytlumaczyć?
komentarz 25 listopada 2018 przez Eryk Andrzejewski Mędrzec (164,260 p.)

To, czy użyjesz w owej pętli for preinkrementacji, czy postinkrementacji, to nie ma większego znaczenia. Taką pętlę for:

for (int i = 0; i < 10; ++i)
{
    //Kod pętli
}

Można zapisać w taki sposób, przy użyciu pętli while:

int i = 0;

while (i < 10)
{
    //Kod pętli
    ++i;
}

Jak widzisz, ++i nie zostało zastosowane w żadnym wyrażeniu, jest po prostu "wolnostojącą" instrukcją i jej jedynym zastosowaniem jest zwiększenie wartości zmiennej i - a ta wartość będzie inna już przy kolejnej instrukcji.

Co innego, gdybym miał tam coś takiego:

for (int i = 0; i < 10; a += (++i))

To faktycznie, to czy użyjemy preinkrementacji, czy postinkrementacji ma znaczenie, bo dodajemy do zmiennej a, w zależności od rodzaju inkrementacji, wartość zmiennej i przed jej zwiększeniem, albo po wykonaniu tej operacji.

Słyszałem kiedyś, że stosowanie postinkrementacji jest bardziej wydajne, lecz nie wiem na ile to jest prawdziwe.

Podobne pytania

0 głosów
1 odpowiedź 205 wizyt
pytanie zadane 14 maja 2023 w C i C++ przez polandonion Dyskutant (7,560 p.)
+2 głosów
1 odpowiedź 869 wizyt
0 głosów
2 odpowiedzi 1,410 wizyt

93,018 zapytań

141,985 odpowiedzi

321,274 komentarzy

62,362 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...