
Programiranje u C-u - od svega pomalo


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 ;-)

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.
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;}

mbaksa, to nisu faktorijele, nemoj zbunjivat ljude :D
Tu nam treba 1+2+3+...+n, a faktorijela bi bila 1*2*3*...*n

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

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, 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.
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.

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

Š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.

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) );
}

LJUDI HITNO!
Kako je znak za cjelobrojno djeljenje u C++???

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ć

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 );

Š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. :)
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;

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....

Dakle, tu je također trebao ići operator <=.
Previd, ispravljeno, THX.
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.

Dakle, tu je također trebao ići operator <=.
Previd, ispravljeno, THX.
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.

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.

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...

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.

Molim primjer!
Ovako nikad nisam ni neću kužit.
http://lazyfoo.net/SDL_tutorials/lesson08/index.php
http://gpwiki.org/index.php/SDL:Tutorials:Practical_Keyboard_Input

@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 - 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?

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.

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

@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.

Nemogu skicirat ali ovako:
20* # ide u visinu
15* # ide u širinu
neki od likova:
#
## #
## ##
#
# ##
### #
#
#
#
#

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.

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)

Pozdrav!
Evo došao sam do trenutka gdje moram nasumično odrediti broj lika, tj. koji lik ce ici dolje...
Kako ide ono kao u BASICU:
RANDOMIZE TIMER
x=int (RND*10)
Hvala!
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.