Programiranje

Programiranje u C-u - od svega pomalo

MrBlc sri 9.2.2011 11:25

Znači, treba ti suma elemenata od 1 do n, pri čemu je i-ti elemenat jednak: 1 / suma elemenata od 1 do i + 1

 

Znači da ti trebaju dvije for petlje jedna u drugoj:

 

float suma = 0;

for (int i = 1; i <= n; i++)

{

  int nazivnik = 0;

  for (int j = 1; j <= i + 1; j++)

  {

    nazivnik = nazivnik + j;

  }

  suma = suma + ((float)i)/nazivnik;

}

 

 

I na kraju ti suma sadrži rezultat.

Luuka sri 9.2.2011 11:37
IRebic kaže...

Ljudi, treba mi pomoć oko zadatka, korisnik upisiva broj n , a program treba izračunati broj za koji vrijedi:

  1        ...                n

---- + -----    +  -------------

1+2   1+2+...   1+...+(n+1)

 

ako je (n=2) bit će:

  1         2

----- + --------

1+2    1+2+3

 

ako je (n=3) bit će:

  1         2                3

---- + --------  + -----------

1+2   1+2+3     1+2+3+4

 

Nadam se da kužite, hvala na pomoći unaprijed...

 

Trebat će ti dvije for petlje.

Jedna koja računa onaj zbroj dolje (ili iskoristi gformulu za zbroj prvih n brojeva)

Druga koja računa zbroj razlomaka.

 

Nije teško, možda ti kasnije napišem kod, ali probaj prvo sam

 

edit : kasnim, već ti je riješeno.

 

btw 1+2+3+...+n = n(n+1)/2 pa ti jedna petlja ne treba ;-)

mbaksa sri 9.2.2011 11:49
MrBlc kaže...

Znači, treba ti suma elemenata od 1 do n, pri čemu je i-ti elemenat jednak: 1 / suma elemenata od 1 do i + 1

 

Znači da ti trebaju dvije for petlje jedna u drugoj:

Trebao si ga ostaviti da sam dođe do toga. {#}

 

BTW zeznuo si drugu for petlju - ona ti ide od 1 do i, a ne od 1 do i+1. Dakle, tu je također trebao ići operator <=. Također, zašto izbjegavaš operator uvećavanja += ? Retoričko pitanje, ofkors.

 

MrBlc kaže...
 

float suma = 0;

for (int i = 1; i <= n; i++)

{

  int nazivnik = 0;

  for (int j = 1; j <= i + 1; j++) nazivnik += j;

 

  suma += ((float)i)/nazivnik;

}

 

Ili, još bolje (zašto si ne bi napisao funkciju za izračunavanje zbroja svih brojeva do x?):

 

int zbrojiDo(int n) {
    int zbroj = 0;
    for (int i = 1; i <= n; i++) zbroj += j;
    return zbroj;
}

int main() {
    float suma = 0;
    for (int i = 1; i <= n; i++) suma += ((float)i)/zbrojiDo(i+1);
}

 

Ili, još bolje - ovo o čemu je Luuka pisao, samo s jednom petljom (EDIT: Luuka nije o tome pisao - pisao je o nečemu drugome... ali može se riješiti i na ovaj način - znači, najmanje četiri načina):


float suma = 0;

int nazivnik = 1;

for (int i = 1; i <= n; i++) {    nazivnik += i+1;    suma += ((float)i)/nazivnik;}

Luuka sri 9.2.2011 12:03
beno101 kaže...

Okej...

Sad ste zbunili i mene kojeg je stvarno teško zbunit...

 

Zaključak:

jedna petlja za izračunat nazivnik

druga petlja za izračunat zbroj razlomaka

 

uz napomenu da se prva petlja može izostavit jer znamo formulu za zbroj prvih n brojeva :  1+2+3+..+n = n(n+1)/2

mbaksa sri 9.2.2011 12:05
Luuka kaže...

mbaksa, to nisu faktorijele, nemoj zbunjivat ljude :D

Tu nam treba 1+2+3+...+n, a faktorijela bi bila 1*2*3*...*n

LOL! Da, totalno zaboravih da su faktorijele vezane uz množenje... Dakle, nisu faktorijele, nego zbroj... Editirat ću svoju poruku i ispraviti to.

 

Luuka kaže...
beno101 kaže...

Okej...

Sad ste zbunili i mene kojeg je stvarno teško zbunit...

 

Zaključak:

jedna petlja za izračunat nazivnik

druga petlja za izračunat zbroj razlomaka

 

uz napomenu da se prva petlja može izostavit jer znamo formulu za zbroj prvih n brojeva :  1+2+3+..+n = n(n+1)/2

Ili, kao što sam dao primjer, druga petlja se može izostaviti ako pamtimo nazivnik iz prethodne iteracije. To je bolje, jer imaš samo dva zbrajanja u jednoj iteraciji, umjesto da imaš jedno zbrajanje, jedno množenje i jedno dijeljenje. {#} Iliti, drugim riječima, ne moraš "iznova" računati cijeli nazivnik.

 

Luuka sri 9.2.2011 12:11
mbaksa kaže...

Ili, kao što sam dao primjer, druga petlja se može izostaviti ako pamtimo nazivnik iz prethodne iteracije. To je bolje, jer imaš samo dva zbrajanja u jednoj iteraciji, umjesto da imaš jedno zbrajanje, jedno množenje i jedno dijeljenje. {#} Iliti, drugim riječima, ne moraš "iznova" računati cijeli nazivnik.

Jasno da je bolje, ali polako. Treba doć do toga, korak po korak. Čovjek je tek krenuo programirat, nećemo ga odmah s efikasnošću ubit :D

beno101 sri 9.2.2011 12:39
Luuka kaže...
Jasno da je bolje, ali polako. Treba doć do toga, korak po korak. Čovjek je tek krenuo programirat, nećemo ga odmah s efikasnošću ubit :D

 ŠTA?

To nije nigdje pisalo kad sam se prijavljivo za programiranje...

Ali šta ćeš:

 

Ja beno101 pri zdravoj pameti i razumu.

Sva svoja blaga (pola zvjezdice) ostavljam moderatoru mbaksi.

Neka mu služi tih pola zvjezdice kao što je i meni.

 

hrx sri 9.2.2011 12:56

Rekurzija anyone?

 

Granični uvjet: n=1 -> suma=1/3

 

                                  2*n

Član u rekurziji: -----------------

                           (n+1)*(n+2)

 

 

float suma(int n) {
    if (n==1) return (1.0/3.0);
    else return ( 2.0*n/((n+1)*(n+2)) + suma(n-1) );
}

Floki sri 9.2.2011 12:57

Kad nisi siguran kako napraviti algoritam, uvijek pođi od onog što unosiš i onog što treba biti izlaz

 

Ovo npr. radi za nazivnik:

 

 

 int n = 5, a = 3, suma = 3;
            for (int i = 2; i <= n; i++)
            {
                a +=   (i+1);
                suma += a;
            }
            Console.WriteLine(suma);

 

plus @Luukina formula za brojnik, i to je to

A @MRBlc je stavio jedan način već

hrx sri 9.2.2011 13:00
beno101 kaže...

LJUDI HITNO!

 

Kako je znak za cjelobrojno djeljenje u C++???

 

Isti kao i za dijeljenje realnih brojeva: / .

 

Ako imaš realni broj kao jedan od operanada, treba ga pretvoriti u int;

 

float a;
int b;
int div;

div = ( ((int) a) / b );

mbaksa sri 9.2.2011 13:01
beno101 kaže...
Luuka kaže...
Jasno da je bolje, ali polako. Treba doć do toga, korak po korak. Čovjek je tek krenuo programirat, nećemo ga odmah s efikasnošću ubit :D

 ŠTA?

To nije nigdje pisalo kad sam se prijavljivo za programiranje...

Ali šta ćeš:

 

Ja beno101 pri zdravoj pameti i razumu.

Sva svoja blaga (pola zvjezdice) ostavljam moderatoru mbaksi.

Neka mu služi tih pola zvjezdice kao što je i meni.

Moderator prihvaća tvoju žrtvu - uzet ćemo ti zvjezdice, a ujedno i avatar. {#}Šalim se - programiranje ti je jedna vrlo zanimljiva disciplina u kojoj možeš tek zadovoljiti zahtjev da određeni ulaz podataka daje određeni izlaz, no s vremenom ćeš i sam uviđati gdje možeš nešto poboljšati, optimizirati. Tu se programiranje pretvara skoro u umjetnost. :)

 

beno101 kaže...

LJUDI HITNO!

 

Kako je znak za cjelobrojno djeljenje u C++???

Kaže se "operator", jer ne mora biti samo jedan znak (iako jest). Pogodi koji! /

Međutim, prvi operand ti treba biti int (ili čak oba?) i onda je rezultat dijeljenja tip int, odnosno cijeli broj.

 

int broj1, broj2;

int rezultat = broj1/broj2;

beno101 sri 9.2.2011 13:04
mbaksa kaže...

int broj1, broj2;

int rezultat = broj1/broj2;

 Joooj!

Koji sam ja njub!

Zaboravio sam i da je int samo cijeli broj pa je to i ujedno cijelobrojno dijeljenje...
Kad sam nervozan neznan ništa....

 

MrBlc sri 9.2.2011 14:08
mbaksa kaže...

Dakle, tu je također trebao ići operator <=.

Previd, ispravljeno, THX.

 

mbaksa kaže...

Ili, još bolje - ovo o čemu je Luuka pisao, samo s jednom petljom (EDIT: Luuka nije o tome pisao - pisao je o nečemu drugome... ali može se riješiti i na ovaj način - znači, najmanje četiri načina):


float suma = 0;

int nazivnik = 0;

for (int i = 1; i <= n; i++) {      nazivnik += i+1;      suma += ((float)i)/nazivnik;}

Ovo je duplo brže, ali imaš grešku. Nazivnik u prvom koraku iznosi 1 + 2. Inicijalna vrijednost nazivnika bi trebala biti 1.

mbaksa sri 9.2.2011 14:10
MrBlc kaže...
mbaksa kaže...

Dakle, tu je također trebao ići operator <=.

Previd, ispravljeno, THX.

 

 

mbaksa kaže...

Ili, još bolje - ovo o čemu je Luuka pisao, samo s jednom petljom (EDIT: Luuka nije o tome pisao - pisao je o nečemu drugome... ali može se riješiti i na ovaj način - znači, najmanje četiri načina):


float suma = 0;

int nazivnik = 0;

for (int i = 1; i <= n; i++) {    nazivnik += i+1;    suma += ((float)i)/nazivnik;}

Ovo je duplo brže, ali imaš grešku. Nazivnik u prvom koraku iznosi 1 + 2. Inicijalna vrijednost nazivnika bi trebala biti 1.

 

Točno. I mislio sam da mi tu nešto ne štima, ali mi se nije dalo razmišljati. {#} Ispravit ću u gornjoj poruci.

rustweaver sub 12.2.2011 19:22

Jednostavno, postoje non-blocking input funkcije za tipkovnicu, misa...

 

U petlji provjeravas koja je tipka pritisnuta, te tako pomices likove. Ako nije pritisnuta nikakva tipka ne reagiras nego pustas da se izvodi dalje dok se ne dogodi nekakav input.

Standardne C biblioteke nemaju funckije za non-blocking input. Trebat ce ti nesto poput SDL-a ili Curses biblioteka...

beno101 sub 12.2.2011 19:24
rustweaver kaže...

Jednostavno, postoje non-blocking input funkcije za tipkovnicu, misa...

 

U petlji provjeravas koja je tipka pritisnuta, te tako pomices likove. Ako nije pritisnuta nikakva tipka ne reagiras nego pustas da se izvodi dalje dok se ne dogodi nekakav input.

Standardne C biblioteke nemaju funckije za non-blocking input. Trebat ce ti nesto poput SDL-a ili Curses biblioteka...

Molim primjer!

Ovako nikad nisam ni neću kužit.

 

mbaksa sub 12.2.2011 19:38

@beno101 - s inputom se stigneš igrati kasnije. Ti si prvo napravi logiku - napravi si klasu ili funkcije koje će sve obavljati. Znači, napravi si funkcije pomakni(smjer) i rotiraj(smjer), koje će pomicati i rotirati lik. Za prvu silu te funkcije možeš pozivati ovisno o tome je li korisnik za scanf ili cin upisao znak a, s, d ili w. Kad će ti to raditi, onda si implementiraj to da ti pritisak tipke pomiče lik te nekakav tajmer, koji će automatski za nekoliko stotina milisekundi sam pozvati pomakni(dolje).

 

Moraš razdvojiti logiku programa od načina kontrole likova. {#}

beno101 sub 12.2.2011 19:41
mbaksa kaže...

@beno101 - s inputom se stigneš igrati kasnije. Ti si prvo napravi logiku - napravi si klasu ili funkcije koje će sve obavljati. Znači, napravi si funkcije pomakni(smjer) i rotiraj(smjer), koje će pomicati i rotirati lik. Za prvu silu te funkcije možeš pozivati ovisno o tome je li korisnik za scanf ili cin upisao znak a, s, d ili w. Kad će ti to raditi, onda si implementiraj to da ti pritisak tipke pomiče lik te nekakav tajmer, koji će automatski za nekoliko stotina milisekundi sam pozvati pomakni(dolje).

 

Moraš razdvojiti logiku programa od načina kontrole likova. {#}

Tako sam i mislio ali ne kuzim kako micat lik???

Recimo imam char a=215; (neki bezvezni znak)

Ako je on :

 

 

#######

#   a        #

#   a        #

#   aaa     #
#             #
#             #

#            #

#######

 

Kako da ga pomaknem dolje?

I kak da taj lik a koji se sastoji od tri reda stavim u jednu cjelinu?

 

rustweaver sub 12.2.2011 19:48

Slozis funkciju koja ispisuje taj znak na monitor, a kao argument za funkciju mozes koristiti trenutnu rotaciju, te poziciju lika.

 

npr za tetris znak "L" ti treba 4 stupnja rotacije.

 

imao bi funkciju:

int draw_L(int rotacija, int x, int y)
{
   ...
}

 

Takva bi funkcija tada trebala iscrtati L na koordinatama x,y uzevsi u obzir trenutnu rotaciju. Naravno trebalo bi uzeti u obzir i sudaranje s drugim objektima. Funkcija bi vracala npr broj 1 ako je znak "L" dotakao dno i vise ne moze ici dolje. Tada bi glavna petlja postavila novi znak koji bi se opet nanovo spustao sa vrha ekrana.

Tom69 sub 12.2.2011 19:48
beno101 kaže...

Evo!

Odlučio sam napraviti svoju osobnu verziju tetrisa u Cu (ne C++u).

I zanima me kako da sad pomičem te likove?

Hvala!

 

P.S. ako ima još netko što za dodati neka ne ustručava u tome.

Ja bih ti za početak preporučio Allegro 4.4 (ima više dokumentacije i primjera od novoizašlog 5.0). S njime se možeš koncentrirati na samu logiku igre bez da se mučiš s implementacijom low-level funkcija za tajming, crtanje po ekranu, parsiranje ulaznih znakova i slično.

 

Osnovni pseudokod je:

 

dok (igra)

   procesiraj ulaz

   obavi logiku

   iscrtaj grafiku

kraj dok

 

mbaksa sub 12.2.2011 19:51

@beno101: Nisam baš siguran kako si si ti to zamislio. Ti svaki lik moraš razložiti na kockice! Možeš ti za taj lik imati broj 215, ali ti moraš znati da ti je taj lik polje 3x3 kvadratića i moraš znati koji su "puni", a koji "prazni". Isto tako, čitava "ploča" ti mora biti polje - možeš ti imati likove označene brojevima (dakle, da njih čuvaš i da pamtiš gdje se nalaze), ali kod iscrtavanja ploče ili kod ispitivanja je li zapunjen koji red, ti ćeš te likove morati uključiti u polje. Zapravo, čim lik padne, on kao takav nestaje i "prelazi" u polje ploče.

MrBlc sub 12.2.2011 21:15

Bolje ti je raditi s 2D grafikom - imaš statičku pozadinu i elemente. Svaki tick ti se Y koordinata padajućeg elementa povečava za određeni broj (o tick intervali ovisi fluidnost pokreta, a broj tickova u sekundi * incerement Y koordinate je brzina padanja), lijepiš element na statičku pozadinu i novodobivenu grafiku šalješ na iscrtavanje. Kad rješiš taj problem, dalje ide kontroliranje kretanja pomoću inputa, ispitivanje dodira donje stranice s elementima koji su pali u svrhu zaustavljanja, pa onda kontroliranje kompletiranosti retka i brisanje elemenata (uz pad gornjih), te na kraju provjera da li je element cijeli stao na ekran u trenutku dodira elementa ispod sebe (ako nije - game over).

 

 

Tekstualno možeš napraviti istu stvar, samo tickove možeš aktivirati samo kada padeš za visinu jednog retka jer znak ne može biti dijelom u jednom retku, dijelom u drugom. Možeš tickove imati i češće (recimo da bi na osnovu njih odredio točan trenutak pada u svrhu podvlačenja), samo onda ispis pozivaš kada je Y%visina_retka = 0. Prilikom ispisa pomičeš u overwrite mode-u na mjesto na kojem element više ne postoji i tamo upisuješ razmak, a na nova mjesta upisuješ željeni znak. Orginalni tetris ima 7 oblika od kojih 1 ima samo 1 rotaciju, 3 imaju 2 rotacije i preostala 3 imaju 4 moguće rotacije. Da ne moraš brinuti koji je trenutni oblika, možeš za prvi staviti da ima 4 rotacije koje su identične, a za sljedeća 3 da se dvije rotacije naizmjenice pojavljuju 2 puta. Na taj način svi imaju 4 moguće rotacije.

Također, svi elementi se sastoje od 4 kockice. Baci pogled na sliku. Sad napraviš nekakvu strukturu podataka (može biti višedimenzionalno polje ili baš struktura) u kojoj ćeš za svaki element, za svaku rotaciju tog elementa spremit relativni pomak u odnosu na prvo polje (prvo polje je sjecište prvog stupca i prvog retka, te može biti prazno - ako je prazno, neće postojati element kojem je relativni pomak 0, 0). Za kocku bi te vrijednosti bile (0, 0), (0, 1), (1, 0) i (1, 1) u svim rotacijama, dok bi za blik 5, rotaciju 4 to bilo (0, 2), (1, 0), (1, 1) i (1, 2) (ukupno bi imao 140 parova koordinati).

 

Za pomak imao sljedeće operacije:

- stari položaj + prvi pomak: space

- stari položaj + drugi pomak: space

- stari položaj + treći pomak: space

- stari položaj + četvrti pomak: space

 

- novi položaj + prvi pomak: #

- novi položaj + drugi pomak: #

- novi položaj + treći pomak: #

- novi položaj + četvrti pomak: #

 

 

 

Za rotaciju bi imao:

- stari položaj + prvi pomak (stare rotacije): space

- stari položaj + drugi pomak (stare rotacije): space

- stari položaj + treći pomak (stare rotacije): space

- stari položaj + četvrti pomak (stare rotacije): space

- novi položaj + prvi pomak (nove rotacije): #

- novi položaj + drugi pomak (nove rotacije): #

- novi položaj + treći pomak (nove rotacije): #

- novi položaj + četvrti pomak (nove rotacije): #

 

S tim da moraš voditi računa o pomaku koji se događa prilikom rotacije. To možeš napraviti tako da imaš u vertikalnom položaju dodatni horizontalni pomak, a u horizontalnom položaju vertikalni pomak pribrojen pomaku oblika. Druga opcija je spremanje tih pomaka u posebne varijable. Mislim da je prva opcija bolja, s tim da bi bilo dobro spremiti za svaki oblik i rotaciju širinu i visinu elementa za lakšu provjeru blizine poda ili desnog zida.

 

Alternativni pristup je spremanje svih oblika kao 4x4 raster, pa ako je 1 to polje iscrtavaš, a ako je 0 ne iscrtavaš (16 polja rastera x 4 rotacije x 7 oblika = 448 elemenata). To olakšava rotaciju i omogućuje korištenje dodatnih oblika sastavljenih od više od 4 elementa, ali otežava situaciju kada rotiraš element u iz vertikalnog u horizontalni položaj u blizini zida (mora se odmaknuti) i samu provjeru blizine zida ili poda.

 

Nadam se da sam ti pomogao vizualizirati problem.

BolestanUm sub 12.2.2011 21:36

 

 

Dakle,

 

preporučujem ti, da svoju igru razlomiš na grafički i logički dio (ona poznata "Podijeli pa vladaj"). Logički dio ti može biti 2D polje char-ova ili int-ova, gdje spremas pozicije likova, jer na taj način možeš znati kada ce neki drugi lik koji se spušta stati itd.

Npr bilo bi ti super kad bi koristio int 2D polje: Naprimjer int a[600][200]. Znaci podloga za tetris se sastoji od 200 'piksela' širine i 600 'piksela' visine. (zasto 'piksel' u navodnicima - jer to nije pravi piksel na koji smo navikli, to ti je zapravo samo mjesto za tvoj znak)

 

Zašto bi ti bilo super za 2D int polje: jer onda možes neke oblike u tetrisu upisat posebnim brojevima i to kombinirat s bojama: Npr. kocka (2x2) neka bude broj u tom polju 2, zanci sve 4 pozije u polju sadrže broj 2, i kada ides graficki prikazati to polje prolaskom for petlje kroz retke i stupce: Pratis vrijednost unutar polja: Ako je -1 (default - prazno), nista!, ako je neki drugi broj postavi boju (to mozes na vise nacina u C, ja se sjecam samo setcolor(int number) ili textcolor (int number) ili pak cprintf(...) i ispišeš ili # kako si ti zamislio ili možeš ASCII 219 █ <- taj znak.

 

Način "osvježavanja" slike (refresh) mozes na vise nacina, kako ti zelis, mozes prilikom svakog pokreta ili obrisat cijeli ekran i for petljom proci 2D polje sa vrijednostima i iscrtavati sve, ili prebrisati samo onaj oblik koji putuje od vrha do dole i ponovo ga crtati (tada moras koristiti funckiju gotoxy - koja prima koorditante x i y i ispisuje znak ili nesto, nesicam se, progooglaj malo)

 

I jos jedan naputak: Unos brojeva bez "stanke programa" (kao prilikom scanf-a). Za tu namjenu koristi funckiju kbhit(). Ona ti provjerava je li pritisnuta tipka, ako je vraca 1 ako nije vraca 0. način na koji se to koristi:

 

if(kbhit()) //Provjeri je li pritisnuta tipka, ako je udi u if, ako ne nastavi program

{

  pritisnutaTipka = getch(); //Preuzmi tipku koja je prtisnuta: Napomena 'pritisnutaTipka' je tipa char

  ...

  if(pritisnutaTipka == 'a')

  {

  ... // Pozovi funkciju koja pomiče aktivni element ulijevo

  } 

  ... //itd.

}

 

 

(Koje bibiloteke ukljuciti da bi to sve radilo: Iskreno, neznam - u C-u ne programiram vise ovakve stvari, Googlaj!! :D)