Pieniä kysymyksiä ohjelmoinnista

Liittynyt
20.10.2016
Viestejä
791
Törmäsin yksinkertaisen oloiseen mutta jotenkin hankalaan ongelmaan. On 8x8 ruudukko ja siihen joko "käyttäjä" tai random arpoo 8 ykköstä ja loput solut on nollia. Pitäisi nopeasti pienellä koodinpätkällä tutkia, ovatko ykköset ns. yhtä suurta mannerta, eli palat kiinni toisissaan seinistä tai katto/lattiasta. Kulmittain ei saa olla eikä irrallisia saaria. En saanut tätä tehtyä millään?

Täydennystä, liitteenä on muutama ok ja ei-ok manner. Ja kulmitttain saa olla, mutta ei pelkästään kulmittain.
 

Liitteet

Viimeksi muokattu:

Zigh

Tittelitön
Liittynyt
17.10.2016
Viestejä
4 652
Törmäsin yksinkertaisen oloiseen mutta jotenkin hankalaan ongelmaan. On 8x8 ruudukko ja siihen joko "käyttäjä" tai random arpoo 8 ykköstä ja loput solut on nollia. Pitäisi nopeasti pienellä koodinpätkällä tutkia, ovatko ykköset ns. yhtä suurta mannerta, eli palat kiinni toisissaan seinistä tai katto/lattiasta. Kulmittain ei saa olla eikä irrallisia saaria. En saanut tätä tehtyä millään?

Täydennystä, liitteenä on muutama ok ja ei-ok manner. Ja kulmitttain saa olla, mutta ei pelkästään kulmittain.
Itse tekisin varmaan niin, että kerätään kahta settiä "vieraillut" ja "naapurit", joissa vain uniikkeja ruutuja eikä samaa ruutua molemmissa.
A Etsitään siis ensimmäinen ykkönen -> vieraillut + 1 kpl
B Tarkistetaan tämän naapurit (neljään suuntaan)-> naapurit + n kpl
C Siirrytään yhteen naapureista -> vieraillut + 1 kpl, naapurit - 1 kpl
D Toistetaan B ja C niin kauan, että naapurit on tyhjä (kohdassa B lisätään vain naapurit, joita ei löydy kummastakaan setistä)
E Jos kuvio on yhtenäinen, vieraillut on tässä vaiheessa kooltaan 8. Jos ei, kuvio ei ole yhtenäinen.

Varmaan löytyy joku elegantimpikin ratkaisu, mutta tämä nyt tuli ensimmäisenä mieleen.
 
Liittynyt
20.10.2016
Viestejä
791
Itse tekisin varmaan niin, että kerätään kahta settiä "vieraillut" ja "naapurit", joissa vain uniikkeja ruutuja eikä samaa ruutua molemmissa.
A Etsitään siis ensimmäinen ykkönen -> vieraillut + 1 kpl
B Tarkistetaan tämän naapurit (neljään suuntaan)-> naapurit + n kpl
Tämä taitaa mennä siinä kohtaa väärin, jos on esim. 8 ykköstä vaakasuoraan ja sattuu aloittamaan toiseksi päädymmäisestä ja lähtee laskemaan päätyyn päin, niin tulee umpikuja, koska kolmas on jo siellä ekan toisella puolella. Sama tilanne jos on kolmen risteyksessä josta kaksi tietä johtaa kauemmaksi mutta seuraavaksi valitaan se kolmas joka on umpikuja.
 

Zigh

Tittelitön
Liittynyt
17.10.2016
Viestejä
4 652
Ei pitäisi olla umpikujat ongelma kun aina otetaan kaikki haarat (naapurit) talteen niin aina löytyy joku mistä jatkaa. Sillähän ei periaatteessa ole edes mitään väliä missä järjestyksessä tuota naapuri-settiä käy läpi. Voi vaikka randomilla aina ottaa sieltä jonkun.
 
Liittynyt
20.10.2016
Viestejä
791
Ei pitäisi olla umpikujat ongelma kun aina otetaan kaikki haarat (naapurit) talteen niin aina
Entä jos on kaksi 4 palan neliötä kiinni vain kulmittain, kuten aloitusviestin punainen yläoikea? Siinä kun lähtee käymään sitä 2x2 palaa ympäri niin kaikki on kunnossa, mutta ei olekaan.
 
Liittynyt
17.10.2016
Viestejä
5 407
Entä jos on kaksi 4 palan neliötä kiinni vain kulmittain, kuten aloitusviestin punainen yläoikea? Siinä kun lähtee käymään sitä 2x2 palaa ympäri niin kaikki on kunnossa, mutta ei olekaan.
Tuo Zighin esittämä tapa ymmärtää tuonkin ja hylkää sen koska naapurit katsotaan jokaiselle ykköselle vain neljään suuntaan jolloin ei koskaan päästä siihen toiseen neljän ryhmään ja todetaan että lopputulos oli 4.
 
Liittynyt
20.10.2016
Viestejä
791
Tuo Zighin esittämä tapa ymmärtää tuonkin ja hylkää sen koska naapurit katsotaan
Juu totta ... pitää jatkaa vielä miettimistä. Olen jumittunut miettimään omasta näkökulmasta asiaa, kun yritin kaikenlaisilla helpoilla and-or-not jutuilla päätellä asian, tekemättä mitään iterointilooppia tms.
 
Liittynyt
17.10.2016
Viestejä
5 407
Paljon tuota yksinkertaisempaa ratkaisua ei taida kyllä löytyä ja ilman tuollaista iterointiluuppia tuohon pitäisi melkoinen and-or-not -matriisi virkata kasaan joka melkeinpä taitaakin olla monimutkaisempi juttu kuin kaikkien vaihtoehtojen ennalta generointi ja niihin vertaileminen. Ihan mielenkiinnosta, mihinkäs olet tuota juttua käyttämässä?
 
Liittynyt
20.10.2016
Viestejä
791
vertaileminen. Ihan mielenkiinnosta, mihinkäs olet tuota juttua käyttämässä?
Tämä on joku vanha puzzle, joka on helppo ihmiselle ... shakkilaudalla on palloja ja lauta pitää jakaa mantereisiin jotka ovat yhtenäisiä ja joissa jokaisessa on yksi pallo. Mutta oli ainakin siellä jollakin saitilla kommenttien perusteella hankala koodata. Näytti niin helpolta että päätin ratkaista asian (viikko sitten) minuutissa ... ei onnistunut :)
 
Liittynyt
28.12.2016
Viestejä
1 589
Laske joka ei tyhjän solun naapurit vaaka- ja pystysuuntaan. Jos löytyy solu jolla on nolla niin fail.
Sitten pitää vielä tarkistaa että kaikki solut on yhdessä. Tee lista soluista jotka ovat yhdessä. Lisää siihen yksi ja sen naapurit. Lisää naapureiden naapurit jos ei ole jo listassa. Jatka tätä kunnes ei enää uusia naapureita löydy. Jos kaikki on listassa niin kakki ok muuten fail.
 
Liittynyt
07.01.2021
Viestejä
687
Minä lähtisin ehkä miettimään rekursiivista funktiota, joka "liikkuu" tuossa kuviossa niin, että vain valittu solu on kulkukelpoinen. Eli valitaan yksi aloituspiste satunnaisesti. Tallennetaan kaikki vieressä olevat solut, jotka on "elossa". Sitten valitaan yksi elossa olevista ja siirrytään siihen. Tallennetaan taas kaikki paitsi jo vieraillut solut ja valitaan yksi. Kun päädytään soluun, jolla ei ole yhtään ei-vierailtua solua, palataan rekursioluupissa ylöspäin. Sitten kun koko funktio on käyty läpi, tarkistetaan, vierailtiinko kaikissa soluissa, esimerkiksi yksinkertaisesti laskemalla monessako käytiin.

Eli keskellä yötä nopeasti mietittynä jotain tällaista:
Koodi:
visit_cell(current):
  mark_visited(current)
  nl = find_unvisited_neighbours()
  if len(nl) == 0:
    return
  for n in nl:
    visit_cell(n)
Tarvitaan joku muuttuja vielä, johon solut tallennetaan ja niiden tilat ja status (onko käyty) merkataan. Nuo muut funktiot on triviaaleja. find tsekkaa vaan naapurisolut ja jos status on ei-vierailtu, niin palauttaa sen.
 
Liittynyt
15.10.2021
Viestejä
17
Hei! Kun kuviossa on korkeintaan 8 palaa, jokainen pala on vähintään yhden tyhjän kohdan vieressä vähintään kulmittain. Nyt voidaan käyttää labyrintin ratkaisumenetelmää, jossa pidetään koko ajan oikeaa kättää seinällä ja kuljetaan seinän viertä kunnes päästään ulos tai tässä tapauksessa löydetään kaikki 8 palaa tai palataan takaisin ensimmäisen palan luo. Hahmottelin tuon ajatuksen pythoniksi, joka toimi ainakin muutamaan kuvioon, joilla testasin.

Python:
R = 0
alue = [R,R,R,R,R,R,R,R,R,R,
        R,0,0,0,0,0,0,0,0,R,
        R,0,1,1,1,0,0,0,0,R,
        R,0,0,0,1,1,1,0,0,R,
        R,0,0,1,1,0,0,0,0,R,
        R,0,0,0,0,0,0,0,0,R,
        R,0,0,0,0,0,0,0,0,R,
        R,0,0,0,0,0,0,0,0,R,
        R,0,0,0,0,0,0,0,0,R,
        R,R,R,R,R,R,R,R,R,R]

# Oikea, ylös, vasen, alas
suunnat = [1,-10,-1,10]

# Etsitään kuvion vasen ylänurkka ja aloitetaan siitä
alkupaikka = alue.index(1)
# Ensimmäisen palan yläpuolella ja vasemmalla on aina "seinä"
# Lähdetään kulkemaan alaspäin pitäen oikeaa kättä seinää vasten
alkusuunta = 3

# Asetetaan paikka ja suunta alussa
paikka = alkupaikka
suunta = alkusuunta
# Kerätään löydetyt palat listaan
palat = [alkupaikka]

while(True):
    # Katsotaan pääseekö haluttuun suuntaan liikkumaan
    if alue[paikka + suunnat[suunta]] == 1:
        # Siirrytään seuraavalle palalle
        paikka += suunnat[suunta]
        # Listätään mahdollinen uusi pala listaan
        if paikka not in palat:
            palat.append(paikka)
        # Käännytään oikealle (oikean käden sääntö)
        suunta -= 1
        if suunta < 0:
            suunta = 3
    # Jos ei pääse jatketaan etsintää
    else:
        # Käännytään vasemmalle
        suunta += 1
        if suunta > 3:
            suunta = 0
    # Lopeteteaan jos kaikki 8 palaa on löydetty
    if len(palat) == 8:
        break
    # Lopetetaan jos on palattu takaisin alkupisteeseen
    if suunta == alkusuunta and paikka == alkupaikka:
        break

if (len(palat) == 8):
    print("Kuvio koostuu 8 yhtenäisestä palasta!")
else:
    print("Kuviossa on vain "+str(len(palat))+" palaa...")
 
Liittynyt
28.04.2020
Viestejä
47
Ja tuo ade07 koodi, näyttää toimivan hienosti.
Siirtelin ja kääntelin tuota aluetta ja aina tuli oikea vastaus.
:thumbsup:

Tosin tuota ohjelman antamaa palaute viestiä voisi vaihtaa, koska aluetta voi laajentaa,
ja viesti pysyy samana; Kuvio koostuu 8 yhtenäisestä palasta!
Python:
R = 0
alue = [R,R,R,R,R,R,R,R,R,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,1,1,0,1,0,0,R,
R,0,0,0,1,1,1,0,0,R,
R,0,0,0,0,1,1,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,R,R,R,R,R,R,R,R,R]
 
Viimeksi muokattu:
Liittynyt
27.10.2016
Viestejä
133
@Zigh tyylillä myös oma ratkaisu

Koodi:
fill char: 1
visited: list
visit: list
visit.add ( index of first element that is fill char )
while visit:
    current = visit.pop
    if current not in visited:
        visited.add( current )
       
       for element in left, right, up, down
           if element is fill char
               visit.add( index of element )
return visited
Koodi:
size = width * height
board = [0,...]
fill_board

visited = []
visit = []
# find index of first element that is not empty
visit.append( ... )

while visit:
    cur_index = visit.pop()
    if cur_index not in visited:
        visited.add(cur_index)

        # for element in left, right, up and down
        # if element is not empty 
        #   add index to nodes
        for i in (-1, 1, -width, width):
            next_index = cur_index + i
            if 0 <= next_index < size: # discard invalid indexes
                if board[next_index] == 1:
                    visit.append(next_index)
 
Viimeksi muokattu:
Liittynyt
15.10.2021
Viestejä
17
Ja tuo ade07 koodi, näyttää toimivan hienosti.
Siirtelin ja kääntelin tuota aluetta ja aina tuli oikea vastaus.
:thumbsup:

Tosin tuota ohjelman antamaa palaute viestiä voisi vaihtaa, koska aluetta voi laajentaa,
ja viesti pysyy samana; Kuvio koostuu 8 yhtenäisestä palasta!
Python:
R = 0
alue = [R,R,R,R,R,R,R,R,R,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,1,1,0,1,0,0,R,
R,0,0,0,1,1,1,0,0,R,
R,0,0,0,0,1,1,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,0,0,0,0,0,0,0,0,R,
R,R,R,R,R,R,R,R,R,R]
Hei! Kiitos vastauksesta ja testailusta :thumbsup: Tuo labyrintti menetelmä tosiaan toimii myös suuremmille kuvioille, jos kuvio pysyy labyrinttimaisena. Jos taas kuvioon tulee palasia, jotka eivät osu edes nurkittain reunaan ei menetelmä enää toimi. Helppona esimerkkinä on 9 palan kokoinen 3x3 laatta. Myöskään kuvion sisään jäävät tyhjät kohdat eivät toimi. Tuohon poikkeuksena on, jos kuvio on pelkkä kehä. Nuihin isompiin kuvioihin sopii paremmin tuo @Zigh tyylinen kattava haku. Jos tätä algoritmia haluaa testailla laajemmin ilman tuota 8 palan rajoitusta, niin se onnistuu kommentoimalla tai muuten poistamalla seuraavan kohdan esimerkiksi näin:
Python:
    # Lopeteteaan jos kaikki 8 palaa on löydetty
    #if len(palat) == 8:
    #    break
Viestistä voi tulla vähän erikoinen kyllä:
Kuviossa on vain 25 palaa...
 
Liittynyt
28.12.2016
Viestejä
1 589
Eihän tuo seinän seuraus toimi tällaiselle kuviolle:
XXX
XYX
XX

Missä Y voi joko olla tyhjä tai täysi. Saatan tosin olla väärässäkin...
 
Liittynyt
15.10.2021
Viestejä
17
Eihän tuo seinän seuraus toimi tällaiselle kuviolle:
XXX
XYX
XX

Missä Y voi joko olla tyhjä tai täysi. Saatan tosin olla väärässäkin...
Hei! Esimerkissäsi, jos Y on täysi kaikki palat käydään tuon oikean käden säännön mukaan läpi vastapäivään. Jos Y on tyhjä tilannetta varten koodissa on ovela kikka. Kun lähdetään oikeasta yläreunasta kiertämään alaspäin, joudutaan tuota oikealle lähtevää haaraa varten palaamaan lähtöpaikan ohi. Siksi tuossa koodissa alkupaikan lisäksi tallennetaan alkusuunta ja lopetusehto onkin:
Python:
    if suunta == alkusuunta and paikka == alkupaikka:
        break
Tällöin toiseen suuntaan mennessä koodi ei pysähdy aloituspaikkaan niin että osa kuviosta jää tarkistamatta. Aloituspaikkaan pysähdytään vasta kun suuntakin on sama kuin alussa, eli kun lähdettäisiin kiertämään uudestaan kuviota. Tuo pelastaa myös siinä tilanteessa että kuvio on vain yhden palan kokoinen. Algoritmi pyörii palan kerran ympäri ja huomaa sitten että on samassa asennossa kuin lähtiessä ja pysäyttää laskennan.
Testasin nuo molemmat tilanteet koodilla ja sain oikeat vastaukset. Löysin nettiselaimessa toimivan tulkin ja kopion tuon sinne, tuossa nyt se Y on tyhjä tilanne, mutta tuota "alue" listaa muuttamalla saa helposti muutkin tilanteet: Online Python - kuvio
 
Liittynyt
28.04.2020
Viestejä
47
Löysin sivun jolla tämä pähkinä on ratkaistu, mutta viivyttelin sen jakamisen kanssa, muutaman päivän, jotta mielenkiinto omaa ratkaisun löytämiseen ei katoaisi.
Python:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  6x6.py
#
#  https://www.geeksforgeeks.org/find-number-of-islands/
#  Ohjelma saarten laskemiseen 2D-matriisissa

class Graph:

    def __init__(self, row, col, graph):
        self.ROW = row
        self.COL = col
        self.graph = graph

    # 2D matriisin apufunktio DFS()
    # Se huomioi kaikki 8 naapuri solua, siis kulmat myös.
    # Tämä tosin on helppo muuttaa sellaiseksi, ettei
    # kulmia oteta huomioon, kuten tässä on tehty.
    def DFS(self, i, j):
        if i < 0 or i >= len(self.graph) or j < 0 or j >= len(self.graph[0]) or self.graph[i][j] != 1:
            return

        # merkitään se vierailuksi
        self.graph[i][j] = -1

        # Toisto 8:lle naapurisolulle
        # tai nyt muokattuna 4:lle naapurisolulle
        #self.DFS(i - 1, j - 1)
        self.DFS(i - 1, j)
        #self.DFS(i - 1, j + 1)
        self.DFS(i, j - 1)
        self.DFS(i, j + 1)
        #self.DFS(i + 1, j - 1)
        self.DFS(i + 1, j)
        #self.DFS(i + 1, j + 1)

    # Pää funktio joka laskee saarten määrän.
    def countIslands(self):
        count = 0                           # Saarten määrä nollaksi (0), ja tarkistetaan jokainen solu
        for i in range(self.ROW):
            for j in range(self.COL):
                if self.graph[i][j] == 1:   # Vierailematon solu on 1, ja osa uutta saarta
                    self.DFS(i, j)          # Vieraillaan saaren jokaisessa solussa
                    count += 1              # ja lisätään saarten määrää.

        return count

graph = [
[0,1,1,1,1,1],
[0,1,0,0,0,1],
[0,1,0,1,0,1],
[0,1,0,0,0,1],
[0,1,1,1,1,1],
[0,0,0,0,0,0]
]

row = len(graph)
col = len(graph[0])
g = Graph(row, col, graph)
print("Saarten määrä on:", g.countIslands())

# Tämän koodi on muokattu alkuperäisestä Shivam Shrey kirjoittamasta
# https://www.geeksforgeeks.org/find-number-of-islands/
 

hrk

Liittynyt
23.07.2017
Viestejä
1 738
Löysin sivun jolla tämä pähkinä on ratkaistu, mutta viivyttelin sen jakamisen kanssa, muutaman päivän, jotta mielenkiinto omaa ratkaisun löytämiseen ei katoaisi.
Python:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  6x6.py
#
#  https://www.geeksforgeeks.org/find-number-of-islands/
#  Ohjelma saarten laskemiseen 2D-matriisissa

class Graph:

    def __init__(self, row, col, graph):
        self.ROW = row
        self.COL = col
        self.graph = graph

    # 2D matriisin apufunktio DFS()
    # Se huomioi kaikki 8 naapuri solua, siis kulmat myös.
    # Tämä tosin on helppo muuttaa sellaiseksi, ettei
    # kulmia oteta huomioon, kuten tässä on tehty.
    def DFS(self, i, j):
        if i < 0 or i >= len(self.graph) or j < 0 or j >= len(self.graph[0]) or self.graph[i][j] != 1:
            return

        # merkitään se vierailuksi
        self.graph[i][j] = -1

        # Toisto 8:lle naapurisolulle
        # tai nyt muokattuna 4:lle naapurisolulle
        #self.DFS(i - 1, j - 1)
        self.DFS(i - 1, j)
        #self.DFS(i - 1, j + 1)
        self.DFS(i, j - 1)
        self.DFS(i, j + 1)
        #self.DFS(i + 1, j - 1)
        self.DFS(i + 1, j)
        #self.DFS(i + 1, j + 1)

    # Pää funktio joka laskee saarten määrän.
    def countIslands(self):
        count = 0                           # Saarten määrä nollaksi (0), ja tarkistetaan jokainen solu
        for i in range(self.ROW):
            for j in range(self.COL):
                if self.graph[i][j] == 1:   # Vierailematon solu on 1, ja osa uutta saarta
                    self.DFS(i, j)          # Vieraillaan saaren jokaisessa solussa
                    count += 1              # ja lisätään saarten määrää.

        return count

graph = [
[0,1,1,1,1,1],
[0,1,0,0,0,1],
[0,1,0,1,0,1],
[0,1,0,0,0,1],
[0,1,1,1,1,1],
[0,0,0,0,0,0]
]

row = len(graph)
col = len(graph[0])
g = Graph(row, col, graph)
print("Saarten määrä on:", g.countIslands())

# Tämän koodi on muokattu alkuperäisestä Shivam Shrey kirjoittamasta
# https://www.geeksforgeeks.org/find-number-of-islands/
Kun olen viime aikoina innostunut opettelemaan golang-kieltä, en malta olla näyttämättä hieman muokattua go-versiota tästä hauskasta pikku tehtävästä. Pythonistalle go on helppo opittava, ja eduista mainittakoon vahva tyypitys, joka nopeuttaa toimivan ohjelman aikansaantia huomattavasti, sekä oikea kääntäjä, joka tuottaa itseriittoisia kompakteja binäärejä. Joku saattaa pitää etuna sitäkin, että kielessä ei ole luokkia eikä siis ole kiusausta väkisin vääntää simppeliä koodia "objekti-orientoituneeseen" muotoon.

Koodi:
package main

import "fmt"

var areas = [][] int {
    {0,1,1,1,1,1},
    {0,1,0,0,0,1},
    {0,1,0,1,0,1},
    {0,1,0,0,0,1},
    {0,1,1,1,1,1},
    {0,0,0,0,0,0},
    {0,1,1,0,0,0},
}

func countIslands() int{
    var count = 0    // löytyneiden saarten lkm
    var expand func(int, int)

    // DepthFirstSearch...
    expand = func (i int, j int){
        // ollaanko vielä kartalla?
        if i < 0 || i >= len(areas) || j < 0 || j >= len(areas[0]) {return}
        // onko alue kuiva ja vapaa?
        if areas[i][j] != 1 {return}
        // juu on, siis otetaan käyttöön
        // ja liitetään saareen numero 'count'
        areas[i][j] = -count
        // tutkitaan naapurialueet
        expand(i - 1, j)
        expand(i, j - 1)
        expand(i, j + 1)
        expand(i + 1, j)
    }

    for i, row := range areas {
        for j, area := range row{
            if area == 1{
                // löytyi käymätöntä kuivaa maata,
                // eli uusi saari
                count++
                // tutkitaan voiko laajentua
                expand(i, j)
            }
        }
    }
    return count
}
func main() {
    fmt.Println("Saarten määrä on:", countIslands())
    // tulostetaan eräänlainen kartta
    for _, row := range areas{
        for _, area := range row {
            fmt.Printf("%2d", -area)
        }
        fmt.Println()
    }
}
 
Viimeksi muokattu:

hrk

Liittynyt
23.07.2017
Viestejä
1 738
Kun olen viime aikoina innostunut opettelemaan golang-kieltä, en malta olla näyttämättä hieman muokattua go-versiota tästä hauskasta pikku tehtävästä.
Tuossa ja esikuvissaan on kuitenkin sellainen vika, että se ei erota saarta mantereesta. Eli ei osaa hylätä sellaisia ykkösiä, joiden joka puolella on nollia. Tässäpä olisi näiltä osin parannettu ratkaisu, vaihteeksi pythoniksi:

Python:
areas = [
[0,1,1,1,1,1],
[0,1,0,0,0,1],
[0,1,0,1,0,1],
[0,0,0,0,0,0],
[0,1,1,1,1,1],
[1,0,0,0,0,0],
[0,1,1,0,1,0],
]

def continents():
    count = 0 # Löytyneiden mannerten määrä
   
    def expand(i, j, root):
        nonlocal expanding
        # ollaanko vielä kartalla?
        if i < 0 or i >= len(areas) or j < 0 or j >= len(areas[0]):
            return
        # onko alue kuiva ja uusi
        if areas[i][j] != 1: return
        # jos on, liitetään mantereeseen
        areas[i][j] = -count
        # yritetään laajentua joka suuntaan
        expanding = not root    # laajentuminen on onnistunut
        for k in range(i-1, i+2):
            for l in range(j-1, j+2):
                if i != k or j != l:
                    expand(k, l, False)

    for i, row in enumerate(areas):
        for j, area in enumerate(row):
            if area == 1:
                # löytyi uutta maata
                # saariko vai manner?
                # veikataan mannerta
                count += 1
                expanding = False
                expand(i, j, True)
                if not expanding:
                    # eipä ollut mantereen alku,
                    # vettä joka puolella
                    # pyyhitään kartalta
                    count -= 1
                    areas[i][j] = 0
    return count

if __name__ == "__main__":
    print("Mantereiden määrä on:", continents())
    for row in areas:
        for area in row:
            print("%2d" % -area, end="")
        print()
 
Liittynyt
23.10.2021
Viestejä
1
Näin aloittelijana varmaan tyhmä kysymys mutta, miten saan tohon kivi,paperi, sakset peliin lisättyä score counterin (Pelaajanvoitot, koneenvoitot)?
Sain sen toimimaan ilman aliohjelmia, mutta niiden kanssa en saa toimimaan.

C++:
#include <iostream>
#include <math.h>
#include <Windows.h>
#include <string>



int numMuunnin();
int valinnanMuunto(std::string);
void kone(int);
void voittaja(int, int);

int main()

{
    // Tulostuksen ääkköset :
    setlocale(LC_ALL, "");

    std::string pelaajanValinta;
    int pelaaja;
    int koneenValinta;
    int kierrokset = 0;
    int voitot = 0;
    int koneenVoitot = 0;
    //Kysytään käyttäjältä kuinka monta kierrosta halutaan pelata?
  
    std::cout << "Kuinka monta kierrosta haluat pelata?" << std::endl;

    std::cout << "Anna kierrokset >";
    std::cin >> kierrokset;

  
    //Kysytään käyttäjän valinta
    for (int kierros = 1; kierros <= kierrokset; kierros++)
    {
      
        std::cout << "Kierros numero:" << kierros << "/" << kierrokset << std::endl;

        std::cout << "\nValitse kivi, paperi tai sakset:";
        std::cin >> pelaajanValinta;
        std::cout << "\nSinun valintasi on: " << pelaajanValinta << "\n";

      
        //Aliohjelmat
        koneenValinta = numMuunnin();
        pelaaja = valinnanMuunto(pelaajanValinta);
        kone(koneenValinta);
        voittaja(koneenValinta, pelaaja); 
    }
  
}

int numMuunnin()
{
    std::srand(time(0));
    int randomi = rand() % 3 + 1;

    return randomi;
}

int valinnanMuunto(std::string pelaaja1)

{
    int merkinkoodi = 0;

    if (pelaaja1 == "kivi")
        merkinkoodi = 1;
    else if (pelaaja1 == "paperi")
        merkinkoodi = 2;
    else if (pelaaja1 == "sakset")
        merkinkoodi = 3;

    return merkinkoodi;
}

void kone(int pelaaja2)
{
    if (pelaaja2 == 1)
    {
        std::cout << "Kone valitsi kiven\n";
    }
    else if (pelaaja2 == 2)
    {
        std::cout << "Kone valitsi paperin\n";

    }
    else if (pelaaja2 == 3)
    {
        std::cout << "Kone valitsi sakset\n";
    }
}

void voittaja(int pelaaja1, int pelaaja2)
{
  
    if ((pelaaja1 == 1 && pelaaja2 == 2) || (pelaaja1 == 2 && pelaaja2 == 3) || (pelaaja1 == 3 && pelaaja2 == 1))
    {
        std::cout << "\nSinä voitit pelin! \n\n";
      
    }
    else if ((pelaaja1 == 1 && pelaaja2 == 3) || (pelaaja1 == 2 && pelaaja2 == 1) || (pelaaja1 == 3 && pelaaja2 == 2))
    {
        std::cout << "\nTietokone voitti pelin! \n\n";
      
    }
    else
    {
        std::cout << "\nTasapeli\n\n";
    }

}
 
Viimeksi muokattu:
Liittynyt
07.01.2021
Viestejä
687
Vaikka niin, että lisäät main-funktioon muuttujan tuota varten. Voittaja-funktion laitat palauttamaan -1 jos kone voitti ja 1 jos pelaaja voitti. Tasapelin sattuessa tuo palauttaa 0. Lisäät paluuarvon tuohon muuttujaan. Tällä näet siis voittojen erotuksen. Jos haluat tietää molempien tuloksen erikseen, niin tarvitset kaksi muuttujaa, joita kasvatat aina sen mukaan, kumman arvon voittaja() palautti.

Eli
Koodi:
tulos = voittaja(koneenValinta, pelaaja);
if (tulos == 1) { 
  voitot++;
} else if (tulos == -1) {
  koneenVoitot++;
}
Tai jos riittää pelkkä voittojen erotus, niin homma on näin simppeli:
Koodi:
tulos = voittaja(koneenValinta, pelaaja);
tilanne += tulos;
Ja voittaja()-funktioon siis noiden printtien jälkeen return 1, return -1 ja return 0.

(Nyt vasta huomasin, että voitot ja koneenVoitot oli jo määritelty, eli niitä ei edes tarvitse lisätä.)
 
Liittynyt
15.10.2021
Viestejä
17
Hei! Lasket ohjelmassasi voittaja() funktiossa kumpi pelaajista voittaa kyseisen erän. Tietoa voittajasta ei kuitenkaan palauteta funktiosta takaisin ohjelmalle vaan tieto lähetetään suoraan komentorivin vakio ulostulolle (cout). Funktiosta voi palauttaa C++ kielessä tietoa paluuarvona (return) ja viittauksena (tai osoittimella C tyyppisesti). Tässä tapauksessa paluuarvona voitaisiin antaa esimerkiksi numeromuodossa tulos: 0: tasapeli, 1: pelaaja1 voitti, 2: pelaaja2 voitti. Tätä tietoa voidaan sitten käyttää myöhemmin ohjelmassa pisteiden merkitsemiseen oikealle pelaajalle (kuten @Makis näyttää esimerkissään). Toinen mahdollisuus on tuoda pistelaskurit viittauksena funktiolle, jolloin funktion sisällä voidaan päivittää muuttujien arvot suoraan. Viitatut funktion syöteparametrit eivät ole tavalliseen tapaan kopioita alkuperäisestä muuttujasta vaan suora viittaus alkuperäiseen muuttujaan. Tällöin kaikki mikä tapahtuu funktiossa sisällä viitatulle muuttujalle tapahtuu myös alkuperäiselle. Viittauksen voi tehdä & merkillä parametrin tyypin määrittelyn perässä. Tässä sovellettuna ylläolevaan tilanteeseen:
C++:
void voittaja(int pelaaja1, int pelaaja2, int& voitot1, int& voitot2)
{
    if ((pelaaja1 == 1 && pelaaja2 == 2) || (pelaaja1 == 2 && pelaaja2 == 3) || (pelaaja1 == 3 && pelaaja2 == 1))
    {
        std::cout << "\nSinä voitit pelin! \n\n";
        voitot2++;
    }
    else if ((pelaaja1 == 1 && pelaaja2 == 3) || (pelaaja1 == 2 && pelaaja2 == 1) || (pelaaja1 == 3 && pelaaja2 == 2))
    {
        std::cout << "\nTietokone voitti pelin! \n\n";
        voitot1++;
    }
    else
    {
        std::cout << "\nTasapeli\n\n";
    }
}
C++:
voittaja(koneenValinta, pelaaja, koneenVoitot, voitot;
 
Liittynyt
28.04.2020
Viestejä
47
Tässä vielä yksi vaihtoehto:
C++:
/*
* kivi-paperi-sakset.cpp
*
*/

#include <iostream>
/* #include <math.h> */
/* #include <Windows.h> */
/* #include <string> */


int numMuunnin();
int valinnanMuunto(std::string);
void kone(int);
void voittaja(int, int);

int kierros = 0;
int kierrokset = 0;
int voitot = 0;
int koneenVoitot = 0;
void voittaja(int pelaaja1, int pelaaja2) {
    if (
    (pelaaja1 == 1 && pelaaja2 == 2) ||
    (pelaaja1 == 2 && pelaaja2 == 3) ||
    (pelaaja1 == 3 && pelaaja2 == 1))
    {
        voitot = voitot + 1;
        std::cout << "\nSinä voitit tämän kierroksen!\n"
        << "Tilanne on nyt koneen voitot: " << koneenVoitot
        << " sinun voitot: " << voitot << "\n\n";  }
    else if (
    (pelaaja1 == 1 && pelaaja2 == 3) ||
    (pelaaja1 == 2 && pelaaja2 == 1) ||
    (pelaaja1 == 3 && pelaaja2 == 2))
    {
        koneenVoitot = koneenVoitot + 1;
        std::cout << "\nKone voitti tämän kierroksen!\n"
        << "Tilanne on nyt koneen voitot: " << koneenVoitot
        << " sinun voitot: " << voitot << "\n\n";  }

    else {
        std::cout << "\nTämä kierros päättyi tasapeliin!\n"
        << "Tilanne on nyt koneen voitot: " << koneenVoitot
        << " sinun voitot: " << voitot << "\n\n";  }



    if (kierros == kierrokset) {
        std::cout << "\n\nPeli päättyi!\n";
        if (koneenVoitot > voitot) {
            std::cout << "Koneen voittoon, lukemin : "
            << koneenVoitot << "/" << voitot << "\n\n\n";
        }
        else if (voitot > koneenVoitot) {
            std::cout << "Sinun voittoon, lukemin : "
            << voitot << "/" <<  koneenVoitot << "\n\n\n";
        }
        else {
            std::cout << "tasapeliin, lukemin : "
            << voitot << "/" <<  koneenVoitot << "\n\n\n";
        }
    }
}





int main() {
    // Tulostuksen ääkköset :
    setlocale(LC_ALL, "");
    std::string pelaajanValinta;
    int pelaaja;
    int koneenValinta;

    //Kysytään käyttäjältä kuinka monta kierrosta halutaan pelata?
    std::cout << "Kuinka monta kierrosta haluat pelata?" << std::endl;
    std::cout << "Anna kierrokset > ";
    std::cin >> kierrokset;
    std::cout << "\n";


    //Kysytään käyttäjän valinta
    for (kierros = 1; kierros <= kierrokset; kierros++) {
        std::cout << "KIERROS NUMERO: " << kierros << "/" << kierrokset << std::endl;
        std::cout << "Valitse kivi, paperi tai sakset: ";
        std::cin >> pelaajanValinta;
        std::cout << "Sinun valintasi on: " << pelaajanValinta << "\n";

        //Aliohjelmat
        koneenValinta = numMuunnin();
        pelaaja = valinnanMuunto(pelaajanValinta);
        kone(koneenValinta);
        voittaja(koneenValinta, pelaaja);
        }
}




int numMuunnin() {
    std::srand(time(0));
    int randomi = rand() % 3 + 1;
    return randomi;
    }




int valinnanMuunto(std::string pelaaja1) {
    int merkinkoodi = 0;
    if (pelaaja1 == "kivi")         merkinkoodi = 1;
    else if (pelaaja1 == "paperi")  merkinkoodi = 2;
    else if (pelaaja1 == "sakset")  merkinkoodi = 3;
    return merkinkoodi;
    }




void kone(int pelaaja2) {
    if (pelaaja2 == 1) { std::cout << "Kone valitsi kiven\n"; }
    else if (pelaaja2 == 2) { std::cout << "Kone valitsi paperin\n"; }
    else if (pelaaja2 == 3) { std::cout << "Kone valitsi sakset\n"; }
    }
 
Viimeksi muokattu:
Liittynyt
28.04.2020
Viestejä
47
Hiukan asiaan liittyen, ihmetyttää ja kummastuttaa C++:san sleep( ) komento. Ennen komentoa olevat tulostukset tulostuvat vasta sleep( ) komennon jälkeen, no tuossa auttaa tuo cout.flush( ); joka näyttää pakottavan suorituksen etenemisen niin kuin se on kirjoitettu. Mutta tämä alla oleva ei kyllä jää odottelemaan jos sleep( ) käskyä on käytetty.

cout << "Press Enter to Continue";
cin.ignore();


Yritin soveltaa tuota tässä toisessa versiossa tuosta kivi-paperi-sakset.cpp pelistä, ja jouduin tahattomasti tekemään siitä melkein itsestään pelaavan version, jossa ei odotella käyttäjän lupaa uuden kierroksen aloittamiseen, vaan uusi kierros alkaa 5 sekunnin viiveellä.
C++:
#include <unistd.h>  // sleep(2);
#include <iostream>

/*
 * HUOM Näytön tyhjennys
 * Linux:   system ("clear");
 * Windows: system ("CLS");
*/

using namespace std;

int main() {
   int Oma_valinta = 0;
   int Omat_voitot = 0;
   int Koneen_valinta = 0;
   int Koneen_voitot = 0;
   bool OK = true;

   while (OK != false) {
      system ("clear");
      cout << "\n\n\n";
      cout << "\t\033[31mVALITSE [1,2,3,4]\033[0m\n";
      cout << "\t\033[31m=================\033[0m\n";
      cout << "\t\033[32m1 - Kivi\033[0m\n";
      cout << "\t\033[32m2 - Paperi\033[0m\n";
      cout << "\t\033[32m3 - Sakset\033[0m\n";
      cout << "\t\033[32m4 - Lopetus\033[0m\n";
      cout << "\n\t\033[36mAnna valintasi ja paina Enter: \033[0m";

      cin >> Oma_valinta;

      switch (Oma_valinta) {
         case 1: cout << "\n\n\tValitsit\t KIVEN\n\t"; cout.flush(); sleep(1); break;
         case 2: cout << "\n\n\tValitsit\t PAPERIN\n\t"; cout.flush(); sleep(1); break;
         case 3: cout << "\n\n\tValitsit\t SAKSET\n\t"; cout.flush(); sleep(1); break;
         case 4: cout << "\n\n\tValitsit\t LOPETUKSEN\n\t"; cout.flush(); OK = false; break;
         default: cout << "\n\n\tVirheellinen valinta.\n\tYritä uudestaan!"; cout.flush(); sleep(1); break;
         }

      if (Oma_valinta == 1 || Oma_valinta == 2 || Oma_valinta == 3) {
         srand(time(0));
         Koneen_valinta = rand() % 3 + 1;

         switch (Koneen_valinta) {
            case 1: cout << "Kone valitsi\t KIVEN\n"; cout.flush(); sleep(1); break;
            case 2: cout << "Kone valitsi\t PAPERIN\n"; cout.flush(); sleep(1); break;
            case 3: cout << "Kone valitsi\t SAKSET\n"; cout.flush(); sleep(1); break;
            }


         if (
         (Oma_valinta == 1 && Koneen_valinta == 2) ||
         (Oma_valinta == 2 && Koneen_valinta == 3) ||
         (Oma_valinta == 3 && Koneen_valinta == 1))
         {
           Omat_voitot = Omat_voitot + 1; cout << "\n\tSinä voitit tämän kierroksen!\n\n";
           }
         else if (
         (Oma_valinta == 1 && Koneen_valinta == 3) ||
         (Oma_valinta == 2 && Koneen_valinta == 1) ||
         (Oma_valinta == 3 && Koneen_valinta == 2))
         {
           Koneen_voitot = Koneen_voitot + 1; cout << "\n\tKone voitti tämän kierroksen!\n\n";
           }
         else {
            cout << "\n\tTämä kierros päättyi tasapeliin!\n\n";
         }


         cout  << "\t\033[31mTILANNE NYT:\033[0m\n"
         << "\t\033[33mKoneen voitot: \033[0m" << Koneen_voitot << "\n"
         << "\t\033[33mSinun voitot:  \033[0m" << Omat_voitot << "\n\n"; cout.flush();

         cout  << "\n\tOdota peli jatkuu 5 sekunnin kuluttua ."; cout.flush(); sleep(1);
         cout  << "."; cout.flush(); sleep(1);
         cout  << "."; cout.flush(); sleep(1);
         cout  << "."; cout.flush(); sleep(1);
         cout  << "."; cout.flush(); sleep(1);

         Oma_valinta = 0;
      }
   }
   return 0;
}
 
Liittynyt
17.10.2016
Viestejä
1 123
Hiukan asiaan liittyen, ihmetyttää ja kummastuttaa C++:san sleep( ) komento. Ennen komentoa olevat tulostukset tulostuvat vasta sleep( ) komennon jälkeen, no tuossa auttaa tuo cout.flush( ); joka näyttää pakottavan suorituksen etenemisen niin kuin se on kirjoitettu. Mutta tämä alla oleva ei kyllä jää odottelemaan jos sleep( ) käskyä on käytetty.
Ammattikielellä kutsutaan myös funktioiksi... Mutta käytti niistä mitä nimeä tahansa niin sleep() ei ole osa C++ APIa.

Vastauksena varsinaiseen kysymykseen, std::cout on puskuroitu eikä tulosta suoraan kutsuttaessa, vasta puskurin tyhjäys puskee puskurin sisällön ulos. Tämä, kuten huomasitkin, voidaan suorittaa milloin tahansa flush()-funktiolla.
 
Liittynyt
28.04.2020
Viestejä
47
OK, kiitän ja kumarran,
mutta tässä olisi toinen kysymys, kuinka nämä merkit saadaan tulostumaan oikein, nyt tulostuu tällaista:
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsS�š�tTuUvVwWxXyYzZ�ž��å��ä��ö�"
C++:
#include <iostream>
using namespace std;

int main () {
   char abc[] = "abcdefghijklmnopqrsštuvwxyzžåäö";
   char ABC[] = "ABCDEFGHIJKLMNOPQRSŠTUVWXYZŽÅÄÖ";

   int j = sizeof(abc);

   for(int i = 0; i < j; i++) {
      cout << abc[i] << ABC[i];
   }

  return 0;
}
 
Liittynyt
17.10.2016
Viestejä
1 123
OK, kiitän ja kumarran,
mutta tässä olisi toinen kysymys, kuinka nämä merkit saadaan tulostumaan oikein, nyt tulostuu tällaista:
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsS�š�tTuUvVwWxXyYzZ�ž��å��ä��ö�"
C++:
#include <iostream>
using namespace std;

int main () {
   char abc[] = "abcdefghijklmnopqrsštuvwxyzžåäö";
   char ABC[] = "ABCDEFGHIJKLMNOPQRSŠTUVWXYZŽÅÄÖ";

   int j = sizeof(abc);

   for(int i = 0; i < j; i++) {
      cout << abc[i] << ABC[i];
   }

  return 0;
}
Tervetuloa merkistökoodauksien maailmaan :geek:

Lyhyt ja mutkat suoriksi-tyylinen sepostus:
Jotta tuo toimisi odotetulla tavalla pitää olla jotenkin synkassa tiedoston (eli editorin) merkistö, terminaalin merkistö ja sisäinen tietotyyppi. Yleensä char on tavun kokoinen , eli siihen ei mahdu kuin 8-bittisen merkistön yksi merkki. Jos editori käyttää merkistöä jossa merkin koko voi olla >8 bittiä, esim. UTF8, niin osa merkeistä ei mahdu chariin.

Joka tapauksessa, vaikka merkit menisivät taulukoihin oikein, pitää terminaalin/promptin/vastaavan merkistökoodauksen täsmätä editorin tallentamaan tai lopputulos on vähän muuta kuin odotettu riippuen vähän käytetyistä merkeistä ja koodauksista.

Lisäksi bonuksena terminaalin fontti vaatii ko. merkit tai tuloksena on laatikoita niille merkeille joille ei ole kirjasinta.
 
Liittynyt
07.01.2021
Viestejä
687
Heh, piti muutamia vuosia sitten kirjoittaa Android-luuriin buutiin (siis ennen kuin Android edes lähtee käynnistymään) softa, joka näyttää tietyn ruudun ja ottaa inputtia vastaan. Tein sen kirjoittamalla suoraan framebufferiin, mutta siinä tuli wchar_t tutuksi kun piti tietysti tukea muutakin kuin 8-bittisiä merkkejä (jotta lokalisointi olisi mahdollista).

Harvemmin onneksi omat C(++)-koodaukset vaatii ylipäätään unicodea.
 
Liittynyt
07.01.2021
Viestejä
687
Nyt tuli sellainen ongelma, että en edes tiedä, miten tätä pitäisi debugata. Selaimen konsoliin ei tule mitään virhettä, kuten ei myöskään palvelimen logiin. Ainakin useimmilla sivuilla toiminto toimii, mutta tässä ei: SuomiSF - Sinisalo, Johanna: Ennen päivänlaskua ei voi

Eli pitää kirjautua admin/admin, sen jälkeen ylläpitovalikosta "Muokkaa sivua" ja klikkaa "Palkinnot"-tekstin perässä olevaa plussaa. Pitäisi aueta modaali, mutta ainoastaan tuo modaalin aiheuttama sivun tummennus tapahtuu, modaali ei aukea. Inspectorista päätellen se ei siis aukea ollenkaan. Ja siis muilla testatuilla sivuilla toimii. En keksi mikä tuossa teoksessa on eri tavalla.

(Tuo on testiserveri, jonka kanta resetoituu johonkin aikaan yöllä, joten vahinkoa ei pysty aiheuttamaan.)

Toistakymmentä muuta sivua kokeilin ja nyt löytyi toinen, jossa käy samoin: SuomiSF - Paasilinna, Arto: Ukkosenjumalan poika. Ja lisää: SuomiSF - Paasilinna, Arto: Maailman paras kylä, SuomiSF - Paasilinna, Arto: Hirnuva maailmanloppu. Että kyllähän noita näyttää olevan. Ensisilmäyksellä vaikuttaisi, että kyse on teoksista joilla on useampi painos, mutta noistakin useimmat tuntuvat aukeavan.
 
Liittynyt
18.10.2016
Viestejä
69
Nyt tuli sellainen ongelma, että en edes tiedä, miten tätä pitäisi debugata. Selaimen konsoliin ei tule mitään virhettä, kuten ei myöskään palvelimen logiin. Ainakin useimmilla sivuilla toiminto toimii, mutta tässä ei: SuomiSF - Sinisalo, Johanna: Ennen päivänlaskua ei voi

Eli pitää kirjautua admin/admin, sen jälkeen ylläpitovalikosta "Muokkaa sivua" ja klikkaa "Palkinnot"-tekstin perässä olevaa plussaa. Pitäisi aueta modaali, mutta ainoastaan tuo modaalin aiheuttama sivun tummennus tapahtuu, modaali ei aukea. Inspectorista päätellen se ei siis aukea ollenkaan. Ja siis muilla testatuilla sivuilla toimii. En keksi mikä tuossa teoksessa on eri tavalla.

(Tuo on testiserveri, jonka kanta resetoituu johonkin aikaan yöllä, joten vahinkoa ei pysty aiheuttamaan.)

Toistakymmentä muuta sivua kokeilin ja nyt löytyi toinen, jossa käy samoin: SuomiSF - Paasilinna, Arto: Ukkosenjumalan poika. Ja lisää: SuomiSF - Paasilinna, Arto: Maailman paras kylä, SuomiSF - Paasilinna, Arto: Hirnuva maailmanloppu. Että kyllähän noita näyttää olevan. Ensisilmäyksellä vaikuttaisi, että kyse on teoksista joilla on useampi painos, mutta noistakin useimmat tuntuvat aukeavan.
Jos katsot Elements-tabilta, niin kyllähän se modaali tuolla sivulla on, mutta se on sellaisen divin sisällä, jolla on tyylinä display: none eli jää piiloon.
Screenshot from 2021-10-26 20-27-58.png
 
Liittynyt
07.01.2021
Viestejä
687
Aa, eli divit sekaisin. Pitääpä fiksailla. Tuonhan ei tietysti pitäisi olla tuon divin sisällä, eli /div väärässä paikassa/puuttuu.

Hjoo. Vika siis oli templatessa (jinja2), jossa oli endfor väärässä paikassa. Tuossa taisi käydä niin, että jos painosten määrä oli pariton, niin sitten tuo bugi ilmaantui...
 
Liittynyt
28.04.2020
Viestejä
47
Tämänkö ei pitäisi näkyä? Minulla kuitenkin näkyy normaalisti, ja muu alue on harmaan peiton alla.
ScreenShot Tool -20211026203833.png
 
Liittynyt
15.10.2021
Viestejä
17
OK, kiitän ja kumarran,
mutta tässä olisi toinen kysymys, kuinka nämä merkit saadaan tulostumaan oikein, nyt tulostuu tällaista:
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsS�š�tTuUvVwWxXyYzZ�ž��å��ä��ö�"
Hei! Testailin koodiasi Windows 10 alustalla MinGW-W64 g++ 8.1.0 kääntäjällä. Komentorivin "cmd.exe" fonttina minulla on "Lucida Console". Alkuperäinen tulostus näytti minullakin väärältä:
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsS┼┼íátTuUvVwWxXyYzZ┼┼╛╜├├Ñà├├ñä├├╢û"
Löysin internetistä hieman apuja ja sain tulostuksen toimimaan seuraavilla muutoksilla:
C++:
#include <iostream>
#include <fcntl.h> // _O_U16TEXT, _O_U8TEXT
#include <io.h>    // _setmode

int main() {
    _setmode(_fileno(stdout), _O_U16TEXT);

    wchar_t abc[] = L"abcdefghijklmnopqrsštuvwxyzžåäö";
    wchar_t ABC[] = L"ABCDEFGHIJKLMNOPQRSŠTUVWXYZŽÅÄÖ";

    int j = sizeof(abc) / sizeof(abc[0]);

    for (int i = 0; i < j; i++) {
        std::wcout << abc[i] << ABC[i];
    }
}
Taikana tuossa on "wchar_t" tyypin käyttö, johon unicode merkit mahtuvat (.cpp tiedosto käyttää UTF-8 merkistökoodausta myös). wchar merkkijono literaalit saadaan tehtyä tuolla L"tekstiä" tavalla. Windows puolella tarvitsee käyttää "_setmode()" funktiota vaihtamaan stdout konsoliulostulon tyyppimuunnos UTF-8 tai UTF-16 muotoon (minulla molemmat toimivat samalla tavalla). Merkkijonon pituutta ei enää saa suoraan sizeof() funktiolla, sillä yksi merkki on nyt kahden tavun mittainen. Viimeiseksi ulostulona pitää käyttää "std::wcout" ia "std::cout" sijasta.

Samojen temppujen pitäisi ilmeisesti toimia myös Visual Studio kääntäjällä. Lisäksi tuossa on lukemani mukaan melko paljon ylimääräisiä rajoituksia joten eksoottisemmat unicode hymiöt tuskin tulostuvat oikein. Saa tuolla sentään ääkköset toimimaan.
Tässä vielä miltä lopputulos näyttää minulla:
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsSšŠtTuUvVwWxXyYzZžŽåÅäÄöÖ"

Edit: Testasin myös MS Gothic fontilla, jolloin japanin kirjoitusmerkkien tulostus näyttää toimivan samalla menetelmällä.
 
Viimeksi muokattu:
Liittynyt
07.01.2021
Viestejä
687
Merkkijonon pituutta ei enää saa suoraan sizeof() funktiolla, sillä yksi merkki on nyt kahden tavun mittainen. Viimeiseksi ulostulona pitää käyttää "std::wcout" ia "std::cout" sijasta.
Tuohon merkkijonon pituuteen on sellainen funktio kuin wcslen().
 
Liittynyt
07.01.2021
Viestejä
687
Ai niin, pitää vielä lisätä se, että sizeof():ia ei muutenkaan saa käyttää merkkijonon pituuden lukemiseen. Siihen tarkoitukseen on strlen(). sizeof():n arvo määritetään käännösaikana.
 
Liittynyt
15.10.2021
Viestejä
17
Ai niin, pitää vielä lisätä se, että sizeof():ia ei muutenkaan saa käyttää merkkijonon pituuden lukemiseen. Siihen tarkoitukseen on strlen(). sizeof():n arvo määritetään käännösaikana.
Totta. Nuissa aiemmissa koodipätkissä on tosiaan bugit tuohon liittyen. sizeof() funktio antaa kyseisessä tapauksessa tekstille varatun muistialueen koon. Nyt tuossa for loopissa käydään koko muistialue mukaan luettuna merkkijonon terminointimerkki null "\0" (tai sen leveä versio tuossa wchar_t tyypissä). Tekstin muistialueet voivat olla paljon pidemmät kuin mitä sen hetkinen tekstisisältö vaatii. Esimerkiksi, kun tekstiä luetaan syötteeltä, tekstille on varattu vain jokin maksimikoko ja itse tekstiosio päätetään tuolla terminointimerkillä.

Edit: Tosiaan tuo sizeof on oikeasti operaattori eikä funktio. Vain tyypien koko vaatii funktiomaisen muodon. Eli näin:
Koodi:
sizeof abc / sizeof abc[0];   // kääntyy
sizeof abc / sizeof(wchar_t); // kääntyy
sizeof abc / sizeof wchar_t;  // ei käänny
 
Viimeksi muokattu:
Liittynyt
28.04.2020
Viestejä
47
Valinta_014.png
Linux ympäristössä, tuosta 19 rivistä tulee ongelma, jotain pitäisi muuttaa, tai löytää <fcntl.h> kirjastosta Linux vastine. Nyt olen käynyt läpi nuo alla olevat joita esiintyi sivulla joille ajauduin milloin minkäkin hakusanan tuloksena.

//#include <sys/io.h>
//#include 'dmlite.h'
//#include 'any.h'
//#include 'pool.h'
//#include <sys/uio.h>
//#include <unistd.h>
//#include <linux/types.h>
//#include <linux/init.h>
//#include <linux/bug.h>
//#include <linux/err.h>
//#include <asm/io.h>
//#include <asm/page.h>
//#define _LINUX_IO_H
//#include <linux/types.h>
 
Viimeksi muokattu:
Liittynyt
15.10.2021
Viestejä
17
Hei! Tuo _setmode() on tosiaan vain Windowsin komentoriviä koskeva asetus. Testasin koodia Fedora 34 linux ympäristössä, g++ 11.2.1 kääntäjällä ja gnome terminaalilla. Terminaalin asetuksissa on valittu järjestelmän vakio fontti (DejaVu Sans Mono?) ja merkistöksi Unicode - UTF-8. locale komennon ulostulo ja koodimuutos ovat:
Koodi:
$ locale
LANG=fi_FI.UTF-8
LC_CTYPE="fi_FI.UTF-8"
LC_NUMERIC="fi_FI.UTF-8"
LC_TIME="fi_FI.UTF-8"
LC_COLLATE="fi_FI.UTF-8"
LC_MONETARY="fi_FI.UTF-8"
LC_MESSAGES="fi_FI.UTF-8"
LC_PAPER="fi_FI.UTF-8"
LC_NAME="fi_FI.UTF-8"
LC_ADDRESS="fi_FI.UTF-8"
LC_TELEPHONE="fi_FI.UTF-8"
LC_MEASUREMENT="fi_FI.UTF-8"
LC_IDENTIFICATION="fi_FI.UTF-8"
LC_ALL=
C++:
#include <iostream>
#include <locale>

int main() {

    std::setlocale(LC_CTYPE, "");

    wchar_t abc[] = L"abcdefghijklmnopqrsštuvwxyzžåäö";
    wchar_t ABC[] = L"ABCDEFGHIJKLMNOPQRSŠTUVWXYZŽÅÄÖ";

    int j = std::wcslen(abc);

    for (int i = 0; i < j; i++) {
        std::wcout << abc[i] << ABC[i];
    }
}

std::setlocale() tyhjällä merkkijonolla asettaa ympäristön vakio kielen ja alueen muotoilun. LC_CTYPE llä asetetaan merkistön tyyppi. Tuohon tyhjän merkkijonon tilalle voi laittaa jonkun UTF-8 tyypin, jos järjestelmän vakio ei ole UTF-8 tyyppinen kuten minulla oli.

Edit: std::setlocale - cppreference.com Tuolta löytyi tieto miksi tuo locale pitää käsin asettaa koodissa:
During program startup, the equivalent of std::setlocale(LC_ALL, "C"); is executed before any user code is run.
 
Viimeksi muokattu:
Liittynyt
07.01.2021
Viestejä
687
Onko weppisivun asemointikysymykset oikea aihe tälle ketjulle, mutta kysyn silti.

Eli miten minun kannattaisi määritellä tooltipit tällä sivulla, että kaikki näyttävät suht samalta?


Tuossa siis sisältö heittelee sen mukaan, miten leveä otsikko on. Olen määritellyt minimileveyden ja kuvalle tarkan leveyden mutta silti tuo tekstiosio heittelee sivusuunnassa miten sattuu. Saako tuota jotenkin vakioitua? Ja olisikohan muuten tuolle varsin köpelölle tooltipille jotain vaihtoehtoa jos haluaa mutkikkaampaa sisältöä?
 
Liittynyt
07.01.2021
Viestejä
687
Vaihdoin sitten kuitenkin popoveriin. Joku hitto tuossa kanitti, kun en meinannut saada millään toimimaan. Ei vaan suostunut alustumaan tms. Laitoin sitten testiksi sivulle ihan feikki-linkin ja siihen samat asetukset ja pum. Popoverit alkoivat toimia. Ja nyt ne toimii vaikka poistin sen feikin. Tuotakin sai kiroilla hyvän tovin.
 
Liittynyt
07.01.2021
Viestejä
687
Ei saakeli, edelleen tuolta löytyy popovereita, joiden leveys on väärä, vaikka olen määritellyt max-width: 100% !important; ja container: body (kuten SO:ssa opetettiin). Mitään logiikkaa en keksi, enkä myöskään sitä, miten näkisin noiden popovereiden CSS:n. Esimerkiksi Derlethin "Cthulhun jäljet" on väärin, kun yläpuolella oleva Delanyn Nova on oikein. Ei tuo edes tunnu oikein sisältöönkään liittyvän, milloin menee oikein ja milloin väärin.

E. Ainoa keino saada tuo toimimaan on laittaa min-width pikseleinä. Mutta näköjään tuota popoverin aktivointiokoodia ei sitten voi siirtää omaan tiedostoon vaan pitää kopipeistata tuo jokaiselle sivulle. Kun nimittäin yritin, niin lakkasi koko homma taas toimimasta.
 
Viimeksi muokattu:

jad

Liittynyt
22.10.2016
Viestejä
1 216
Ei saakeli, edelleen tuolta löytyy popovereita, joiden leveys on väärä, vaikka olen määritellyt max-width: 100% !important; ja container: body (kuten SO:ssa opetettiin). Mitään logiikkaa en keksi, enkä myöskään sitä, miten näkisin noiden popovereiden CSS:n. Esimerkiksi Derlethin "Cthulhun jäljet" on väärin, kun yläpuolella oleva Delanyn Nova on oikein. Ei tuo edes tunnu oikein sisältöönkään liittyvän, milloin menee oikein ja milloin väärin.

E. Ainoa keino saada tuo toimimaan on laittaa min-width pikseleinä. Mutta näköjään tuota popoverin aktivointiokoodia ei sitten voi siirtää omaan tiedostoon vaan pitää kopipeistata tuo jokaiselle sivulle. Kun nimittäin yritin, niin lakkasi koko homma taas toimimasta.
Ainakin tällä hetkellä siellä on markup hieman sekaisin. Ylimääräisiä </a> tageja, sekä ainakin yksi ylimääräinen </div>

 
Liittynyt
28.04.2020
Viestejä
47
Hei! Tuo _setmode() on tosiaan vain Windowsin komentoriviä koskeva asetus. Testasin koodia Fedora 34 linux ympäristössä, g++ 11.2.1 kääntäjällä ja gnome terminaalilla. Terminaalin asetuksissa on valittu järjestelmän vakio fontti (DejaVu Sans Mono?) ja merkistöksi Unicode - UTF-8. locale komennon ulostulo ja koodimuutos ovat:
Koodi:
$ locale
LANG=fi_FI.UTF-8
LC_CTYPE="fi_FI.UTF-8"
LC_NUMERIC="fi_FI.UTF-8"
LC_TIME="fi_FI.UTF-8"
LC_COLLATE="fi_FI.UTF-8"
LC_MONETARY="fi_FI.UTF-8"
LC_MESSAGES="fi_FI.UTF-8"
LC_PAPER="fi_FI.UTF-8"
LC_NAME="fi_FI.UTF-8"
LC_ADDRESS="fi_FI.UTF-8"
LC_TELEPHONE="fi_FI.UTF-8"
LC_MEASUREMENT="fi_FI.UTF-8"
LC_IDENTIFICATION="fi_FI.UTF-8"
LC_ALL=
C++:
#include <iostream>
#include <locale>

int main() {

    std::setlocale(LC_CTYPE, "");

    wchar_t abc[] = L"abcdefghijklmnopqrsštuvwxyzžåäö";
    wchar_t ABC[] = L"ABCDEFGHIJKLMNOPQRSŠTUVWXYZŽÅÄÖ";

    int j = std::wcslen(abc);

    for (int i = 0; i < j; i++) {
        std::wcout << abc[i] << ABC[i];
    }
}

std::setlocale() tyhjällä merkkijonolla asettaa ympäristön vakio kielen ja alueen muotoilun. LC_CTYPE llä asetetaan merkistön tyyppi. Tuohon tyhjän merkkijonon tilalle voi laittaa jonkun UTF-8 tyypin, jos järjestelmän vakio ei ole UTF-8 tyyppinen kuten minulla oli.

Edit: std::setlocale - cppreference.com Tuolta löytyi tieto miksi tuo locale pitää käsin asettaa koodissa:
Kiitän ja kumarran
Tässä se oli, nyt toimii hienosti, olet nero, :thumbsup:
 

EKM

Liittynyt
05.02.2021
Viestejä
4
Tietäisikös joku neuvoa jotain hyvää itseopiskelumateriaalia microservices-arkkitehtuureista? Microservices-arkkitehtuurin pohjalta rakennettu verkkopalvelu siis kiinnostaa. Verkkosivujen backendin rakentaminen esim. jonkun php-kielellä toteutetun MVC-kirjaston varaan on enemmän tai vähemmän tuttua, mutta microservices-periaatteella rakennettu verkkopalvelu ei.
 
Liittynyt
18.10.2016
Viestejä
69
Tietäisikös joku neuvoa jotain hyvää itseopiskelumateriaalia microservices-arkkitehtuureista? Microservices-arkkitehtuurin pohjalta rakennettu verkkopalvelu siis kiinnostaa. Verkkosivujen backendin rakentaminen esim. jonkun php-kielellä toteutetun MVC-kirjaston varaan on enemmän tai vähemmän tuttua, mutta microservices-periaatteella rakennettu verkkopalvelu ei.
Tähän on itse tullut tutustuttua: What are microservices?
 
Liittynyt
23.12.2016
Viestejä
653
Pieniä pulmia koulun tehtävien kanssa (koulun kalvoista ei mitään apua), eli pitäs tehdä tämmöinen tehtävä:
Create a program which is able to calculate and output (as double value, with 3 decimals) the
average value of the integer numbers given by the user. New numbers are asked until the user
enters a negative value, for example -1.
Yritin tuonne (vanhan tehtävän pohjalle jossa laskettiin syötettyjen lukujen neliöt) pohjalle tehdä tuota uudempaa tehtävää mutta en saa toimimaan tuonne while loopissa sitä että lasketaan keskiarvo ja sitä mukaa kun käyttäjä lisää numeroita keskiarvo muuttuu. Eli loopissa täytyy säilyttää arvot ja ne päivittyy sitä mukaa kun käyttäjä lisää numeroita.
Console.WriteLine("Give the first number to calculate average from or skip the whole thing by entering -1");
int n = Convert.ToInt32(Console.ReadLine());
while(n >= 0)
{
Console.WriteLine(n*n);
Console.WriteLine("Give a new number to calculate a square from or end with -1");
n = Convert.ToInt32(Console.ReadLine());
}

Tuo siis on se aiempi tehtävä esimerkkinä
 
Toggle Sidebar

Uusimmat viestit

Statistiikka

Viestiketjut
240 193
Viestejä
4 194 384
Jäsenet
70 870
Uusin jäsen
liianvanha

Hinta.fi

Ylös Bottom