Ajattelin laittaa oman threadin, kun näköjään tulee tuon kurssin kanssa avun tarvetta. Ja huom. Teen sillä periaatteella kysymykseni, että jos kysymys tähän ilmestyy, olen pohtinut tehtävää jo pidempään, ja jotain saanut kokoon, mutta ohjelma vaan ei toimi halutulla tavalla. Kaikki selvennykset ja ohjeet otan ilolla vastaan ja jos vaan kykenen, autan kyllä vastineeksi!
Kysymykseen:
Millä tavalla hoituu tämä? Tee ohjelma, joka pyytää yhden positiivisen kokonaisluvun. Tulosta luvun perusteella pyramidi, jonka korkeus on annettu luku. Käytä tulostukseen for-luuppia.
Esimerkkitulostus
Anna korkeus: 0 Anna korkeus: 4 * *** ***** *******
Sain aikaiseksi allaolevan, mutta saan vain korkeuden verran tulemaan tähtiä, yksi kerrallaan, eli esim. 5 tähteä pystyyn.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { int korkeus = 0; Console.Write("Anna korkeus: "); korkeus = int.Parse(Console.ReadLine()); for (int i = 1; i <= korkeus; i++) { for (int j =0; j == i; i+=2) Console.WriteLine("*"); } } } }
Mod. huom: Otsikoi aiheet kunnolla ja tee joka kysymykselle erillinen aihe.
<?php $height=5; $tmp=$height-1; for($y=1;$y<$height+1;$y++) { for($i=0;$i<$tmp;$i++) { echo " "; } $tmp--; for($x=0;$x<($y*2)-1;$x++){ echo "*"; } echo "<br>"; } ?>
php versio. Ainu mikä uupuu on että kärki olisi keskellä. Sinulla for loopeissa pieni logiikkavirhe.
edit: Aah what the heck. Yllä oleva yksi tapa saada kolmio. Varmaan parempiakin tapoja mutta tuo ny tuli ekana mieleen.
Mod. korjasi kooditagit!
Ok, värkkäilen tuosta.
@ Mod. Ajattelin säästää palstatilaa, mutta käyhän se tuokin.
Lisäys:
tneva82 kirjoitti:
php versio. Ainu mikä uupuu on että kärki olisi keskellä. Sinulla for loopeissa pieni logiikkavirhe.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { int korkeus = 0; Console.Write("Anna korkeus: "); korkeus = int.Parse(Console.ReadLine()); int vali = korkeus - 1; for (int i = 1; i < korkeus; i++) { for (int j = 0; j < vali; j++) { for (int r = 0; r < (i * 2) - 1; r++) Console.WriteLine("*"); } } } } }
Ei toiminut tuolla mallilla. Mikähän tuossa nyt mättää?
Oletko tekemässä kolmiulotteista pyramidia, kun sulla on kolme sisäkkäistä for-looppia?
Otetaas nyt yksinkertanen esimerkki. Tulosta:
**
Et saa käyttää Console.WriteLine("**");
Vaihe 1: Pyramidissa pitää olla oikea määrä kerroksia. Kerrosten määrä riippuu uloimmasta for-silmukasta. Jos et saa sitä tehtyä hallitusti, on turha sählätä yhtään pidemmälle. Tee siis ensin vain yksi for-silmukka, joka tulostaa oikean määrän rivejä. Voit tulostaa vaikka silmukan indeksimuuttujan arvon eri kierroksilla.
Anna korkeus: 4 RIVI, i = 0 RIVI, i = 1 RIVI, i = 2 RIVI, i = 3
Vaihe 2: Rivillä pitää olla oikea määrä välejä ja oikea määrä tähtiä. Niitä on turha yrittää tulostaa, jos ei tiedä edes, montako niitä pitäisi olla. Seuraavaksi siis laske apumuuttujiin, montako väliä ja tähteä kyseiselle riville tulee, ja tulosta nämä muuttujat.
Anna korkeus: 4 RIVI, i = 0, välit = 3, tähdet = 1 RIVI, i = 1, välit = 2, tähdet = 3 RIVI, i = 2, välit = 1, tähdet = 5 RIVI, i = 3, välit = 0, tähdet = 7
Vaihe 3: Nyt tarvitsee enää kirjoittaa silmukka, joka tulostaa oikean määrän välejä, ja toinen silmukka, joka tulostaa oikean määrän tähtiä. Lopuksi pitää tietenkin siirtyä seuraavalle riville esim. kutsulla Console.WriteLine(), ja äskeisen RIVI-tulosteen voi poistaa.
Tinketti kirjoitti:
Ajattelin säästää palstatilaa, – –
Säästäisit enemmän tilaa ja tekisit keskustelusta mukavampaa, jos jättäisit koodeistasi täysin turhat osat pois. Esimerkiksi tämän ongelman kannalta olennaiset osat ovat vain for-silmukat, koska selvästikään vika ei voi olla using-riveissä, luokan nimessä tai syötteen lukemisessa. Koodissasi on myös paljon tarpeettomia tyhjiä rivejä, jotka vaikeuttavat koodin lukemista. Tyhjiä rivejä kannattaa käyttää kuin tekstin kappalejakoa: loogisesti ja kohtuudella.
Tinketti kirjoitti:
for (int i = 1; i < korkeus; i++)Ei toiminut tuolla mallilla. Mikähän tuossa nyt mättää?
Noh ainakin minulla korkeus oli korkeus+1 ehtona(esmes jos korkeus 5 niin tuolla ehdolla täyttäisi indexit 1, 2, 3, 4 eli vain 4 viiden sijasta). Lisäksi skippaat kolmannen for loopin idean joka oli tulostaa parit tyhjät rivin alkuun jotta tulisi kolmio joka on:
* *** ***** ******* *********
sensijaan että olisi:
* *** ***** ******* *********
Toki jos tämä on tavoite niin sitten kaksi for looppia riittää.
Eli ensin korkeuslooppi, sitten tulostat tyhjää, sitten for looppi leveyttä varten.
Mod. korjasi kooditagit tasalevyiselle tekstille!
Jos tavoitteena oikeasti on pyramidi portaan sijaan, niin helpoiten tuo onnistunee muotoilemalla tuloste.
esim. PL/I:llä toimisi yksinkertaisesti:
testi: proc options(main); dcl h fixed bin; dcl input char (10) var; on conversion begin; display('Syötteen pitää olla kokonaisluku'); goto get_h; end; get_h: display('Anna pyramidin korkeus?') reply(input); if verify(input, ' 1234567890') then signal conversion; h = input; if h > 0 then begin; dcl i fixed bin; dcl line char (2*h-1) var init ('*'); do i = 1 to h; put edit (line) (skip, column(h-i+1), a); line = line || '**'; end; end; end testi;
Ohjelman tuloshan on tietenkin:
Anna pyramidin korkeus? 8 * *** ***** ******* ********* *********** ************* ***************
Laitetaan perjantain kunniaksi myös Ruby-koodina, kun muutkin laittavat kaikkea muuta kuin C#:ia :)
height = ARGV[0].to_i for i in 1..height do (height - i).times { print " " } (2*i - 1).times { print "*" } puts end
Periaatteellinen ero edellisiin on että korkeus- argumentti syötetään komentoriviltä, kuten on normaalisti tapana - eikä kysellä hölmöjä kuten "Anna sitä tai tätä:".
Siis näin:
$ ruby kolmio.rb 7 * *** ***** ******* ********* *********** *************
Nyt sain tulemaan jo pyramidin ilman välejä, mutta nyt rupesin pohtimaan, että jos laitan luvun 0, tulee silti:
*
**
Tein if koodin, joka palaa ohjelman alkuun, mutta silti ennen paluuta nuo ilmestyy. Miksi?
for (int i = 1; i <= korkeus + 1; i++) { Console.WriteLine("*"); for (int j = 0; j <= (i*2)-1 ; j++) Console.Write("*"); } if (korkeus <= 0) { goto Main; }
Mikset noudattanut ohjeitani? Ilmeisesti sinua ei kannata auttaa ollenkaan, kun et kelpuuta apua. Nyt näyttää siltä, että et käytä järkeä yhtään vaan heittelet ihan sattumanvaraisesti palasia yhteen ja odotat, että joku antaisi valmiin koodin. Se on vain täysin väärä tapa opetella ohjelmointia. Ethän opettele matematiikkaakaan niin, että kokeilet kaikenlaisia kaavoja ja toivot, että jostain tulee oikea vastaus.
Sitä minä juuri seurasinkin ja muitakin, joita tähän tuli. En vaan ehtinyt perehtyä eilen siihen välitykseen, sillä ekalla yrittämällä koodini siirsi välilyönnillä viimeisiä tähtiä yhden rivin oikealle.
Sanoin nimenomaisesti, että älä tee yhtään tähteä, ennen kuin saat oikean määrän rivejä. Kai nyt itsekin tajuat, että et voi saada kahta silmukkaa oikein, jos et saa edes yhtä silmukkaa oikein. Kun rivejä on oikea määrä, ensimmäinen for-rivi on valmis eikä sitä pidä enää muuttaa. Yritä nyt ensin päästä edes tähän asti.
No eikö tuossa voisi ihan rivi kerrallaan mennä eteenpäin ja miettiä mitä ohjelma tekee.
Toisekseen auttaisi varmaan jos sisentäisit nuo järkevästi
Koodisi järjellisesti sisennettynä:
for (int i = 1; i <= korkeus + 1; i++) { Console.WriteLine("*"); for (int j = 0; j <= (i*2)-1 ; j++) Console.Write("*"); } if (korkeus <= 0) { goto Main; }
Eli jos korkeus on 0, niin suoritat tuon ensimmäisen for-loopin yhden kerran. Loopissa tulostat * ja rivinvaihdon, jonka jälkeen tulostat kaksi loopissa kaksi kertaa *
Sen jälkeen kun eka for looppi on suoritettu, tarkistat onko korkeus 0 tai pienempi ja jos niin on, menet Main-riville gotolla (jonka käyttöä suositellaan välttämään)
Eli voit miettiä ongelmaa siltä kannalta, että jos tarkistat sataako vettä vasta lenkillä käymisen jälkeen, saatat kastua. Tarkistukset on järkevää tehdä ennen toimintaa, eikä vasta sen jälkeen - jos siis tarkoitus on päättää tekeekö toiminnan vai ei.
Sinänsä koko tarkistus on ihan turha, sillä jos teet sen uloimman loopin yhtä monta kertaa kuin mitä haluat rivejä, niin homma toimii suoraan.
Ja suosittelisin myös, että et kirjoita for -looppeja ilman { } merkkejä, vaikka se onkin syntaktisesti oikein. Sisennyksistäsi päätellen se aiheuttaa vain sekaannuksia.
Metabolix kirjoitti:
Sinänsä koodisi voi korjata myös suoraan järkeä käyttämällä: rivejä tulee kaksi liikaa, joten ota silmukasta kaksi kierrosta pois.
Itse asiassa nuo kaksi riviä tulee sillä yhdellä ainoalla kierroksella.
Olisi varmasti selkeämpää tulostaa vain yksi rivi per kierros. Eli yksi WriteLine joka tulee loopissa ihan viimeisenä.
Jotenkin tuosta koodista tulee sellainen mieleen, että ajatteleeko Tinketti että sitä suoritetaan alhaalta ylöspäin?
Grez kirjoitti:
Itse asiassa siinä tulee kaksi riviä yhdellä kierroksella.
Se olikin pahemmin pielessä, kuin ensin ajattelinkaan. :) Pyörrän puheeni, ei kannata edes yrittää korjata, vaan kannattaa tehdä järkevämmin uudestaan, kuten alunperin ehdotin.
No eihän tuossa nyt oikeastaan hirveästi tarvitse korjata. Pikkuisen uudelleenjärjestelyä eli WriteLine loopin viimeiseksi riviksi, ekasta loopista +1 pois ja sisemmästä loopista -1 tilalle -3.. * Ja tarkistus lopusta huitsin nevadaan.
* Tosin tässä pitäisin tyylikkäämpänä muuta ratkaisua.
Tarttuukohan joku syöttiin, jos golfaan vähän C-kielellä ja saan näin lyhyen ratkaisun aikaan?
#include <stdio.h> int main(int c,char**v){int h,i,j,k;for(h=1;h<c;h++)if(sscanf(v[h],"%d",&i)) for(j=1;j<=i;puts(""),j++)for(k=j-i;k<2*j-1;putchar("* "[k++<0]));return 0;}
Ohjelman koko on 173 merkkiä, joista yksi on turha rivinvaihto. Kyllä varmasti saa pienemmän aikaan. Mitenkäs muilla kielillä, mikä on lyhin ongelman ratkaiseva ohjelma, jonka osaat tehdä?
Esimerkkiajo:
$ ./pyramid eiluku -1 0 2 8 * *** * *** ***** ******* ********* *********** ************* ***************
Ohjelman tulee siis hylätä tulostamatta mitään komentoriviparametrit, joista ei saa jäsennettyä lukua. Lisäksi sen tulee kääntyä varoituksitta, jos ohjelmointikielessä käytetään varoituksia :)
No eikös toi jo esitetty 128 merkkinen ruby-koodi ollut lyhyempi ja se oli sentään luettava.
Mielestäni aivan turhaa tällaisen threadiin tunkea jotain kilpailua lyhyimmästä koodista. Tai sitten jos on ihan pakko niin lyhyin hyvin jäsennelty koodi. Kenellekään ei ole mitään hyötyä tuollaisesta obfuskointikilpailuun osallistuvalta näyttävästä koodista.
Pekka Karjalainen kirjoitti:
Mitenkäs muilla kielillä, mikä on lyhin ongelman ratkaiseva ohjelma, jonka osaat tehdä?
Esim. yksinkertainen APL-versio menee pienempään ja säilyy silti luettavana:
height ← 8 a ← {⍵⍴'*'} b ← {⍵⍴' '} c ← {(b (height-⍵)), (a ((2×⍵)-1))} �c¨ ⍳height
Grez kirjoitti:
No eikös toi jo esitetty 128 merkkinen ruby-koodi ollut lyhyempi ja se oli sentään luettava.
Kyseinen ohjelma ei tehnyt samoja asioita kuin minun ohjelmani. Tämän olisit huomannut lukemalla viestini kokonaan.
Grez kirjoitti:
Mielestäni aivan turhaa tällaisen threadiin tunkea jotain kilpailua lyhyimmästä koodista. Tai sitten jos on ihan pakko niin lyhyin hyvin jäsennelty koodi. Kenellekään ei ole mitään hyötyä tuollaisesta obfuskointikilpailuun osallistuvalta näyttävästä koodista.
Kiitos mielipiteestäsi. Yleensä obfuskointikilpailuun osallistuvilta ohjelmilta odotetaan enemmän obfuskointitekniikoita, kuin pelkkä muuttujien nimien lyhentäminen ja kaiken mahdollisen whitespacen poisto.
Sitä en yleensä osaa Putkaan kirjoitellessa ajatella onko viesteistäni ja kommenteistani mitään hyötyä kenellekään. Olen pääsääntöisesti käynyt hyödylliset ohjelmointikeskustelut muualla, ja Putkasta olen saanut keskustelun sijasta useimmiten vain tiukkaan sävyyn esitettyjä mielipiteitä, joiden totuusarvo on usein ollut hyvin kyseenalainen.
En nyt mainitse konkreettisia esimerkkejä, mutta useampi kuin yksi minun tuntemani ohjelmointitekniikka tai jonkin asian toteutustapa, joita oikeasti käytetään tietojeni mukaan jossakin päin maailmaa, on tuomittu aikoinaan Putkan mittapuun mukaan joko mahdottomaksi, typeräksi tai hitaaksi (ehkä jopa peruslogiikan vastaiseksi kaikista kolmeksi yhtäaikaa :) ). Perusteluiden ja joskus selvästi ymmärryksenkin ollessa sangen vähäisiä en ole oikein jaksanut ajatella, että tämä on nyt sellaista vakavaa ja hyödyllistä keskustelua ja olen oppinut sivuuttamaan moiset väitteet.
En toki väitä, että putkalaiset eivät osaisi mitään. Osaamisen taso vaihtelee niin osallistujien välillä kuin kunkin kohdalla eri osa-alueilla, enkä tietenkään voi arvioida sellaisia asioita, joista en itse tiedä tarpeeksi. On kuitenkin selvästi asioita, joista eräiden putkalaisten vapaasti esittämät mielipiteet eivät ehkä ole aivan tarkkoja ja heidän toivoisi vähän harkitsevan minkä asioiden kannalta he esiintyvät asiantuntijoina. Näiden hassujan mielipiteiden julistusten yleisyyden takia ajattelen, että Putka on minulle lähinnä Suomen johtava ohjelmointihuumorisivusto. Humoristista olisi myös se, jos joku tästä loukkaantuisi. Koska mitäpä minun mielipiteelläni on väliä Putkan kannalta?
Vaikka tapanani ei ole kirjaimellisesti sylkeä näppäimistölleni, voinen käyttää seuravaa ilmausta. Olen ennen kirjoitellut ja aion jatkossakin kirjoitella mitä sylki suuhun tuo tänne, silloin kun on aikaa ja huvittaa. Vakavat kysymyksethän voin aina esittää vaikka Stack Overflow'ssa, johon jostakin kumman syystä luotan enemmän kuin Putkan yleiseen osaamisen tasoon.
Pääsette minusta ja hyödyttömistä jutuistani eroon vain bannaamalla. Ja lupaan olla kohteliaasti hiljaa jatkossa, jos joku vaikka väittää, ihan esimerkkinä, että C++-kielessä "ei voi käyttää" automaattista roskien keruuta. (Olisihan se epäkohteliasta vaatia kyseistä henkilöä vaikka kertomaan asiasta Bjarne-sedälle itselleen. Hän kun näkee asian näin. Lyhyt selvennys kauhusta jäykistyneille: Sana optional tarkoittaa sitä, että teitä ei koskaan pakoteta käyttämään pelottavaa ja vaikeaa roskienkeruumuistinhallintaa, vaan vanhat tutut tekniikat toimivat vastaisuudessakin. Ellei pomo pakota. Kieli ei sitä tee.)
Jalski: Ideana oli mm. ottaa se korkeus komentoriviparametrina. Mutta kiva, että yritit. Grez nyt toivoi, ettei näitä ohjelmia enää tarjota, joten noudatetaanpa hänen toivettaan ja keskustellaan vain vakavista asioista otsa rypyssä.
Onhan noita ollut mukava seurata tosiosaajien näytteitä ko. tehtävässä, ja olen yrittänytkin oppia noista, mutta kunhan eka oppisin edes perusteet, olisin tyytyväinen.
Asiaan: Ymmärsinkö nyt yksinkertaistettuna nuo ohjeet oikein? Eli 1. for määrittää korkeuden - ei tulosteta tähtiä, 2. for välityksen määritykseen - tulostetaan välit, 3. for määrittää rivien tähtimäärän - tulostuu tähdistä pyramidi?
Tinketti kirjoitti:
Asiaan: Ymmärsinkö nyt yksinkertaistettuna nuo ohjeet oikein? Eli 1. for määrittää korkeuden - ei tulosteta tähtiä, 2. for välityksen määritykseen - tulostetaan välit, 3. for määrittää rivien tähtimäärän - tulostuu tähdistä pyramidi?
Aika olennaista on myös, miten nuo forit on sisäkkäin. For silmukan ideana on toistaa sen sisällä eli {} merkkien välissä oleva asia moneen kertaan.
Nyt siis haluat tulostaa monta riviä -> uloin for-silmukka
Kullekin riville haluat tulostaa tiety määrän (0-n) välilyöntiä joiden perään haluat tulostaa tietyn määrän (1-n) tähtiä.
Eli uloimman for-silmukan sisälle tulisi kaksi for-silmukkaa peräkkäin.
Voit ajatella miten tekisit homman jos sinulla olisi kirjoituskone jossa on välilyönti, *-merkki ja rivivaihto ja sitten annat vaan tietokoneelle ohjeet saman homman tekemiseen.
Vielä offtopicit loppuun:
Pekka Karjalainen kirjoitti:
Tämän olisit huomannut lukemalla viestini kokonaan.
Taitaa olla yleinen ongelma:
Pekka Karjalainen kirjoitti:
Grez nyt toivoi, ettei näitä ohjelmia enää tarjota, joten noudatetaanpa hänen toivettaan ja keskustellaan vain vakavista asioista otsa rypyssä.
Viestini lukemalla olisit voinut havaita että kritisoin niiden postaamista threadiin jossa aloittelija kysyy neuvoja ongelmaansa. Ja sekin oli vain mielipide.
Pekka Karjalainen kirjoitti:
Jalski: Ideana oli mm. ottaa se korkeus komentoriviparametrina. Mutta kiva, että yritit. Grez nyt toivoi, ettei näitä ohjelmia enää tarjota, joten noudatetaanpa hänen toivettaan ja keskustellaan vain vakavista asioista otsa rypyssä.
Eipä tuossa nyt varsinaisesti kauhean kovaa yritystä ollut. APL-ohjelmissa nyt vaan harvemmin luetaan syötettä komentoriviparametreinä...
Pahoitteluni ketjun aloittajalle, jos keskustelun harhautuminen sivuraiteille on sekoittanut.
Oikeastaanhan ketjuun laittamani PL/I-version tarkoitus oli vain näyttää vaihtoehtoinen ratkaisutapa, jossa siis yhdessä silmukassa tulostetaan merkkijonoja merkki kerrallaan tulostamisen sijasta.
Noniin, onnistuihan se viimeinkin. Sain sen tehtyä näin:
for (int i = 1; i <= korkeus; i++) { for (int j = 1; j <= korkeus - i; j++) Console.Write(" "); for (int k = 1; k <= (i * 2) - 1; k++) Console.Write("*"); Console.WriteLine(""); }
Koska on hauska tehdä vähän eri tavalla, niin laitetaanpa "matemaattinen" :) ratkaisu:
$height = min(max(intval($_GET['x']), 1), 100); function f($x, $height) { return ($x <= $height ? $x : (2*$height - $x)); } for ($y = $height; $y > 0; $y--) { for ($x = 1; $x <= ($height * 2 - 1); $x++) { echo ($y <= f($x, $height) ? '*' : ' '); } echo "\n"; }
Hyvä Tinketti, että sait koodisi toimimaan.
Tärkeintä ohjelmoinnissa on että ymmärtää mitä on tekemässä. Yritys ja erehdys ikävä kyllä toimii ohjelmoinnissakin, mutta se aiheuttaa kaksi inhottavaa asiaa:
* Et tiedä miten tekemäsi asia toimii (valtava bugin reikä)
* Et opi tekemisestäsi
Toivottavasti ymmärsit toteuttamasi koodin, eli miksi se toteutti vaatimuksesi?
Oheinen lyhyt esimerkkini näyttää toisen tavan tehdä asian: piirretään koko "kuva", josta kaavan (hieman ruma kaava) mukaan päätellään (kaava "piirtää" halutun kolmion ja se täytetään 'pienempikuin'-vertailulla - jos haluat pelkän viivapyramidin tai pyramidin negatiivin vaihda vertailumerkkiä piirtämisessä) kumpi merkki piirretään.
Kun on keksinyt idean, niin loppu on sitten käsityötä ja nyansseja (joskin myös se aika raskas puoli, jossa itse olen huono :) )
Lisäys:
Pekka Karjalainen,
Tartutaan nyt syöttiin, ettet saa niin vihamielista vastaanottoa ja turhaan harmistu :), eli edellinen 'pakattuna':
$h=(int)$_GET['x']; for($y=$h;$y>0;$y--){ for($x=1;$x<=($h*2-1);$x++)echo($y<=($x<$h?$x:(2*$h-$x))?'*':' '); echo "\n";}
Kas, onpas kuvottavan näköinen :)
PS. toki nämä php-versiot vaativat, että vastaus käsitellään tekstinä, jos ajat tätä palvelimella niin sen saa tehtyä esim.
header('Content-type: text/plain; charset=utf-8');
Vielä pascalilla:
write('Anna korkeus: '); readln(korkeus); if korkeus>0 then begin setlength(s, korkeus); fillchar(s[1], korkeus-1, ' '); s[korkeus]:='*'; writeln(s); for i:=2 to korkeus do begin s[korkeus-i+1]:='*'; s:=s+'*'; writeln(s); end; end;
Nytpä onkin sitten tehtävä sama Do While-loopilla. Osaan kyllä tehdä kahdelle käskylle sen, mutta joku tässä useamman do:n kanssa mättää. Kertokaapa minulle mikä se siis on?
do { Console.Write(" "); j++; } while (j <= korkeus - 1); do { Console.Write("*"); k++; } while (k <= (i * 2) - 1); do { i++; } while (i <= korkeus);
Siis minkä osaat tehdä kahdelle käskylle? Ja mitä kummaa pitäis kertoa? Toi koodi on niin hirveää rävellystä, että sitä jaksa edes kommentoida.
Ei sinänsä opetuksenkaan taso ole mistään kotoisin, jos tuollaista tehtävää käytetään do while -silmukan opettamiseen.
Eli siis osaan käyttää Do While-looppia kahden erilaisen komennon tekoon, kuten esimerkiksi aiemmin piti tehdä tähtineliö for-loopilla, mutta tämä kolmas komento nyt hieman hämää.
Opetuksen tasosta voin sanoa sen verran, että yllämainittu on jo huomattu. ;) Mutta voisit nyt sentään ohjata oikeille raiteille tuota "so called" räpellystä, kun kerta tiedät mitä pitäisi tehdä...
No siis ihan samalla tavalla pitäisi laittaa tietyt loopit tietyn loopin sisään kuin foreillakin.
Nythän tuossa on kolme peräkkäistä looppia, eli asioita suoritetaan x+y+z kertaa, ei x*(y+z) kertaa...
Onko nyt miten isosta kiinni, kun nyt antaa vaan alimman rivin tähtineen?
do { Console.WriteLine(""); i++; } while (i <= korkeus); do { Console.Write(" "); j++; do { Console.Write("*"); k++; } while (k <= (i * 2) - 1); } while (j <= korkeus - i);
Mikset voi miettiä järkevästi noita koodejasi? Ei siitä arpomalla toimivaa tule. Muuta nyt vaikka tuokin koodisi suomeksi (välittämättä siitä, montako kertaa silmukat ajetaan):
toista tätä: tulosta tyhjä rivi lopeta toisto toista tätä: tulosta välilyönti toista tätä: tulosta tähti lopeta toisto lopeta toisto
Toisin sanoen koodi tulostaa ensin joukon tyhjiä rivejä, ja sitten koodi tulostaa muutamaan kertaan välilyönnin ja tähtiä. Onko tässä järkeä? (Ohitin nyt sen virheen, että et nollaa silmukoiden muuttujia missään vaiheessa.)
Olet siis taas sotkenut silmukat ihan kummallisesti, ja lisäksi koodin sisennys on todella epäselvä. Suosittelen, että palaat vielä for-silmukoihin ja mietit niitä, kunnes ihan varmasti ymmärrät koodin: missä on silmukka, miksi se toimii tietyn määrän kertoja ja mitä koodia se silmukka toistaa.
Kun ensin ymmärrät for-silmukoita käyttävän koodisi, kopioi se do-while-version pohjaksi. Muuta sitten yhtä for-silmukkaa kerrallaan. Ensiksi muokkaa koodista vaikka sitä for-silmukkaa, jossa on laskurina i.
// Muuta tämä for-silmukka do-while-silmukaksi. // Silmukka alkaa tästä, eli tähän kuuluu do-sana. for (int i = 1; i <= korkeus; i++) { // Tässä on silmukan sisältö. Älä muuta tätä! } // Silmukka loppuu tänne, eli tähän kuuluu while-sana.
Lopputuloksena pitäisi olla yksi do-while-silmukka, jonka sisällä on sama 5 rivin koodi kuin ennenkin. Älä koske sisältöön, ennen kuin tämä ensimmäinen muutos on onnistunut. Vastaavasti kun saat tämän uloimman silmukan toimimaan, älä enää muuta tätä, vaan muuta pelkästään sisällä olevia silmukoita.
Lisäys: Sitä paitsi sinulle neuvottiin jo edellisessä keskustelussa, miten for-silmukka muutetaan do-while-silmukaksi!
No niin, nyt on 2 looppia mielestäni kohdallaan, mutta viimeisen Whilen kohdistaminen mättää. Eli "välitys" -Whilen kohtaa en löydä oikeaksi. :(
int i = 0; do { i++; int j = 1; do { Console.Write(" "); j++; } while (j <= korkeus - 1); int k = 1; do { Console.Write("*"); k++; } while (k <= (i * 2) - 1); Console.WriteLine(); } while (i <= korkeus);
Oot kuitenkin onnistunut laittamaan *:ä tulostavaan looppiin toistojen määrän perustumaan rivinumeroon (i), mutta välilyöntejä tulostavan loopin toistojen rajoitus perustuu korkeuteen (korkeus), eli joka riville tulostetan se sama määrä välilyöntejä.
Kannattaa myös huomata että do ajetaan aina vähintään yhden kerran, joten täytyisi lisätä if:t ulkoiseen ja välilyöntejä tulostavaan looppiin.
Tiedän, että tämä on tyhmä kysymys, mutta mitä välilyöntejä tulostavaan looppin ifin tapahtumaksi laitetaan? Eli:
if (j < 0) { // mitä tähän? }
No vaikkapa
if (i > 0) do
(Tämä siis 19:03:30 postauksesi koodin riville 6)
Tai ehkä selkeyden vuoksi kaarisulkujen kanssa rivien 6-10 tilalle:
if (i > 0) { do { Console.Write(" "); j++; } while (j <= korkeus - 1); }
(En korjannut while ehdossa olevaa virhettä)
Tein nyt tällaisen do whilen, jonka teoriassa pitäisi toimia, mutta eipä vaan käyttäydy niinkuin pitää. Pyramidin pohja ei nimittäin lähde ihan rivin alusta, vaan yhden välilyönnin jälkeen... Miksi?
int j = 1; if (i > 0) do { Console.Write(" "); j++; } while (j <= korkeus - i);
Näköjään laitoin tuon ehdon ihan väärin. Siis se if voisi olla
if (korkeus > i)
mov ebx, 8 ; korkeus xor esi, esi ; laskuri 0, 1, 2 ... .loop: mov edi, buf ; puskuri mov al, ' ' lea ecx, [ebx-1] rep stosb ; välilyönnit mov al, '*' lea ecx, [esi*2+1] rep stosb ; tähdet mov al, 0 stosb ; \0 push buf call [puts] add esp,4 inc esi ; seuraava kierros dec ebx jnz .loop
tneva82 kirjoitti:
Jaahas. Yritätkö tehdä maailmanennätystä hyödyttömimmästä viestistä?
Hmh. Okei
for x in range(h): print " " * (h-x-1) + "*" * (2*x + 1)
(define (print-pyramid height) (define (make-rows height count) (define (make-row spaces stars) (cond ((> spaces 0) (cons " " (make-row (- spaces 1) stars))) ((> stars 0) (cons "*" (make-row spaces (- stars 1)))) (else nil))) (if (>= count height) nil (cons (make-row (- height (+ count 1)) (+ (* count 2) 1)) (make-rows height (+ count 1))))) (define (print-rows rows) (define (print-row row) (display (car row)) (if (pair? (cdr row)) (print-row (cdr row)) (newline))) (if (pair? rows) (begin (print-row (car rows)) (print-rows (cdr rows))))) (print-rows (make-rows height 0)))
Jaahas. Yritätkö tehdä maailmanennätystä hyödyttömimmästä viestistä?
Tuohon if-lauseeseen voi laittaa yksinkertaisesti saman ehdon kuin silmukan loppuun. Seuraavat kaksi koodia ovat nimittäin täsmälleen toisiaan vastaavat:
if (ehto) do { // ... } while (ehto);
while (ehto) { // ... }
Aihe on jo aika vanha, joten et voi enää vastata siihen.