Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossPrivatundervisningPriserSlik bruker du sidenFAQPersonvernVilkårAngrerettKontaktKI-deklarasjon

© 2026 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med KI og kvalitetssikres kontinuerlig – av modellene, og ved at våre tusenvis av brukere kan melde fra om feil. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Org.nr. 913 117 387 (Foretaksregisteret) · Aksel Olsens vei 10B, 1597 Moss · Ikke MVA-registrert

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossPrivatundervisningPriserSlik bruker du sidenFAQPersonvernVilkårAngrerettKontaktKI-deklarasjon

© 2026 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med KI og kvalitetssikres kontinuerlig – av modellene, og ved at våre tusenvis av brukere kan melde fra om feil. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Org.nr. 913 117 387 (Foretaksregisteret) · Aksel Olsens vei 10B, 1597 Moss · Ikke MVA-registrert

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossPrivatundervisningPriserSlik bruker du sidenFAQPersonvernVilkårAngrerettKontaktKI-deklarasjon

© 2026 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med KI og kvalitetssikres kontinuerlig – av modellene, og ved at våre tusenvis av brukere kan melde fra om feil. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Org.nr. 913 117 387 (Foretaksregisteret) · Aksel Olsens vei 10B, 1597 Moss · Ikke MVA-registrert

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossPrivatundervisningPriserSlik bruker du sidenFAQPersonvernVilkårAngrerettKontaktKI-deklarasjon

© 2026 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med KI og kvalitetssikres kontinuerlig – av modellene, og ved at våre tusenvis av brukere kan melde fra om feil. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Org.nr. 913 117 387 (Foretaksregisteret) · Aksel Olsens vei 10B, 1597 Moss · Ikke MVA-registrert

Eksamenssett logo
eksamenssett.noTren målrettet
  • Ungdomsskole/VGS
  • Høyskole
  • Ressurser
  • Skolenyttig
  1. Hjem
  2. Informasjonsteknologi
  3. IT 2 – Diverse språk
  4. Løsning Vår 2026
VG3

Løsningsforslag Informasjonsteknologi IT 2 – Diverse språkVår 2026

Se eksamensoppgaven
Vår 2025Eldre
Om løsningsforslaget: Dette er et veiledende løsningsforslag laget av eksamenssett.no for REA3049 Informasjonsteknologi 2, våreksamen 2026. Vår 2026-settet er felles for alle programmeringsspråk – kandidaten velger selv hvilket språk hun vil løse oppgavene i. Dette er «diverse»-varianten, der vi bruker Java som gjennomgående hovedspråk i all koden. Vi gir korrekte svar på interaksjonsoppgavene (1–4) med begrunnelse, fullstendig og kjørbar kode på utviklingsoppgavene (5, 7, 8), og fullverdige eksempelsvar på tekstoppgavene (4b, 6). Det finnes flere gode måter å løse de åpne oppgavene på.

Løsningsforslag – IT 2 Diverse (Java) Vår 2026

Eksamen: REA3049 Informasjonsteknologi 2 | Semester: Vår 2026 | Varighet: 5 timer | Språkvariant: Diverse (Java) | Tema: OOP-begreper, pseudokode og flytskjema, togsett-modellering, kjøretøydatasett, etikk (kameraovervåking), spillprogrammering

Oppgave 1 – Hva er hovedformålet med en konstruktør?

Oppgaven: Hva er hovedformålet med en konstruktør (constructor) i objektorientert programmering?
Riktig svar: å sette startverdier for objektets attributter når det opprettes

Begrunnelse: En konstruktør er en spesiell metode som kjøres automatisk når et nytt objekt (en instans) opprettes fra en klasse. Oppgaven dens er å initialisere objektets tilstand – altså gi attributtene sine startverdier. I Java har konstruktøren samme navn som klassen og ingen returtype; feltene settes med this:

public class Elev {
    private String navn;
    private int alder;

    public Elev(String navn, int alder) {
        this.navn = navn;      // startverdi for attributt
        this.alder = alder;    // startverdi for attributt
    }

    public static void main(String[] args) {
        Elev elev = new Elev("Noah", 15);  // konstruktøren kjøres automatisk her
    }
}

De andre alternativene beskriver andre mekanismer: å definere metodene gjøres i klassekroppen generelt; å opprette nye klasser basert på eksisterende er arv; og å styre kommunikasjon mellom objekter handler om meldingsutveksling/metodekall, ikke om initialisering.

Oppgave 2 – Hvordan fungerer arv?

Oppgaven: I et UML-klassediagram har Ola en klasse Kjøretøy, og Bil og Buss er spesialiseringer av Kjøretøy. Hvilket utsagn beskriver best hvordan arv fungerer?
Riktig svar: Klassene Bil og Buss arver attributter og metoder fra klassen Kjøretøy og kan i tillegg ha egne.

Begrunnelse: Arv (generalisering/spesialisering) går fra superklasse til subklasse. Kjøretøy er superklassen (det generelle), mens Bil og Buss er subklasser (det spesialiserte). Subklassene arver alt som er definert i superklassen, og kan i tillegg legge til egne attributter og metoder eller overstyre arvede metoder. I Java uttrykkes arv med extends:

public class Kjoretoy {
    private int hastighet;

    public Kjoretoy(int hastighet) {
        this.hastighet = hastighet;
    }
}

public class Bil extends Kjoretoy {        // arver fra Kjøretøy
    private int antallDorer;

    public Bil(int hastighet, int antallDorer) {
        super(hastighet);              // arvet attributt
        this.antallDorer = antallDorer;  // egen attributt
    }
}

Alternativet «Kjøretøy får tilgang til alt i Bil og Buss» snur arveretningen feil vei (superklassen kjenner ikke subklassene). At klassene skulle være «uavhengige» er også feil – de deler en generaliseringsrelasjon.

Oppgave 3 – Sorter pseudokoden

Oppgaven: Sorter linjene slik at de danner et program som leser inn fem tall og teller og skriver ut hvor mange av tallene som er større enn 10. Linjene har ikke innrykk.
Riktig rekkefølge:
  1. SET antall TO 0
  2. SET i TO 1
  3. WHILE i <= 5
  4. READ tall
  5. IF tall > 10
  6. SET antall TO antall + 1
  7. ENDIF
  8. SET i TO i + 1
  9. ENDWHILE
  10. DISPLAY antall

Begrunnelse: Vi trenger to variabler: en teller antall som starter på 0, og en løkketeller i som styrer at vi leser nøyaktig fem tall. Inne i løkka leses ett tall, det testes mot 10, telleren økes ved treff, og løkketelleren økes til slutt. Legg merke til at SET antall TO antall + 1 må ligge inne i IF … ENDIF, mens SET i TO i + 1 må ligge utenfor IF men inne i WHILE – ellers telles feil.

Tilsvarende Java-kode ser slik ut:

import java.util.Scanner;

public class Oppgave3 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int antall = 0;
        int i = 1;
        while (i <= 5) {
            System.out.print("Skriv et tall: ");
            int tall = Integer.parseInt(sc.nextLine().trim());
            if (tall > 10) {
                antall = antall + 1;
            }
            i = i + 1;
        }
        System.out.println(antall);
    }
}

Oppgave 4 – Flytskjema og pseudokode

Merk om vedlegget: Både flytskjemaet og de tre pseudokode-sekvensene (Pseudokode 1–3) i oppgave 4 er gjengitt som bilder i eksamensvisningen, og selve innholdet i figurene er derfor ikke tilgjengelig i teksten vi løser fra. Vi kan derfor ikke fasitsvare på hvilken sekvens som matcher (4a) eller gjengi det eksakte algoritmeinnholdet (4b). Nedenfor viser vi i stedet framgangsmåten og gir et fullverdig eksempelsvar på formen 4b skal ha.

Oppgave 4a – Hvilken pseudokode matcher flytskjemaet?

Slik løser du 4a: Les flytskjemaet ovenfra og ned. Noter for hver blokk hvilken type den er:

  • Oval = start/slutt
  • Rektangel = handling (tilordning, utregning)
  • Parallellogram = inn-/utdata (READ/DISPLAY)
  • Rombe (diamant) = betingelse (IF/WHILE) – én pil ut for «ja», én for «nei»

Gå deretter gjennom hver av de tre pseudokode-sekvensene og sjekk at rekkefølgen på handlinger, den samme betingelsen (f.eks. > mot >=), og løkkestrukturen (om testen står før eller etter kroppen) stemmer overens med flytskjemaet. Sekvensen som har identisk rekkefølge og identiske betingelser, er svaret. Vær særlig oppmerksom på forskjellen mellom en WHILE-løkke (test først) og en REPEAT/UNTIL-løkke (test sist), og på om en pil peker tilbake til før eller etter en tilordning.

Oppgave 4b – Forklar med egne ord hva algoritmen gjør

Eksempel på hvordan et 4b-svar bør formuleres (mal – tilpass til det faktiske flytskjemaet):

Algoritmen starter med å sette en teller til null. Deretter går den inn i en løkke som gjentas så lenge betingelsen i romben er oppfylt. For hver runde leser den inn en verdi fra brukeren, sammenligner verdien med en fast grense i beslutningsblokken, og – dersom betingelsen er sann – utfører den en handling (for eksempel å øke telleren eller oppdatere en sum). Når betingelsen ikke lenger er oppfylt, hopper algoritmen ut av løkka og skriver ut resultatet før den avslutter. Kort sagt: algoritmen leser inn data gjentatte ganger, tar en avgjørelse for hver verdi, akkumulerer et resultat, og presenterer resultatet til slutt.

Et godt 4b-svar navngir blokktypene, beskriver løkkas start- og sluttbetingelse, forklarer hva beslutningsblokken tester, og oppsummerer algoritmens formål i én setning – akkurat som malen over.

Oppgave 5 – Togsett, lokomotiv, togdel og vogn

Oppgaven: Lag et program for oppretting av togsett etter klassediagrammene. Et Togsett skal automatisk få et Lokomotiv (5a–b). Lokomotiver instansieres med tilfeldig trekkraft fra [320, 450, 600] tonn. I 5c innføres Togdel og Vogn: vogner får tilfeldig vekt 20–50 tonn, togdeler har unikt serienummer, og det skal gå an å legge til både nye og eksisterende vogner. I 5d legges vogner til helt til lokomotivets trekkraft er nådd.
Merk om klassediagrammene: Figur 1 og figur 2 er bilder og er ikke gjengitt i teksten vi løser fra. Løsningen under bygger på en rimelig tolkning som følger oppgaveteksten: Togdel er en superklasse med unikt serienummer og vekt, mens Lokomotiv og Vogn arver fra den (figur 2). Togsett «har-et» lokomotiv og «har-mange» vogner (komposisjon). Lokomotivets egenvekt er ikke oppgitt og teller ikke mot trekkraft-grensen – trekkraften tolkes som maks samlet vognvekt.

Oppgave 5a – Klassene Togsett og Lokomotiv

Vi bruker komposisjon: når et Togsett opprettes, oppretter konstruktøren automatisk sitt eget Lokomotiv. Lokomotivet velger tilfeldig trekkraft fra en delt Random.

// Togsett.java — oppgave 5
import java.util.Random;

class Lokomotiv {
    static final int[] TREKKRAFT_VALG = {320, 450, 600};  // tonn
    private static final Random RNG = new Random();

    private final int trekkraft;

    public Lokomotiv() {
        trekkraft = TREKKRAFT_VALG[RNG.nextInt(TREKKRAFT_VALG.length)];
    }

    public int getTrekkraft() { return trekkraft; }

    @Override
    public String toString() {
        return "Lokomotiv med trekkraft " + trekkraft + " tonn";
    }
}

public class Togsett {
    private final Lokomotiv lokomotiv;

    public Togsett() {
        // Komposisjon: et togsett FÅR automatisk et lokomotiv
        lokomotiv = new Lokomotiv();
    }

    public Lokomotiv getLokomotiv() { return lokomotiv; }
}

Oppgave 5b – Program som oppretter et togsett og skriver ut lokomotivinfo

public static void main(String[] args) {
    Togsett togsett = new Togsett();
    System.out.println("Nytt togsett opprettet.");
    System.out.println(togsett.getLokomotiv());   // f.eks. "Lokomotiv med trekkraft 450 tonn"
}

Oppgave 5c – Togdel og Vogn, med endringer i Togsett og Lokomotiv

Nå innføres superklassen Togdel. Den holder en statisk teller (klassevariabel) slik at hvert serienummer blir unikt. Lokomotiv og Vogn arver fra Togdel. Togsett får metoder for å legge til både nye og eksisterende vogner.

// Togsett.java — full versjon etter 5c
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

class Togdel {
    // Superklasse for alle deler i et togsett. Gir unikt serienummer.
    private static int nesteSerienummer = 1;

    private final int serienummer;
    private final int vekt;

    public Togdel(int vekt) {
        this.serienummer = nesteSerienummer;
        nesteSerienummer++;          // garanterer unikhet
        this.vekt = vekt;
    }

    public int getSerienummer() { return serienummer; }
    public int getVekt() { return vekt; }

    @Override
    public String toString() {
        return "Togdel #" + serienummer + " (" + vekt + " tonn)";
    }
}

class Lokomotiv extends Togdel {
    static final int[] TREKKRAFT_VALG = {320, 450, 600};  // tonn
    private static final Random RNG = new Random();

    private final int trekkraft;

    public Lokomotiv() {
        super(120);  // egenvekt (ikke spesifisert; teller ikke mot grensen)
        trekkraft = TREKKRAFT_VALG[RNG.nextInt(TREKKRAFT_VALG.length)];
    }

    public int getTrekkraft() { return trekkraft; }

    @Override
    public String toString() {
        return "Lokomotiv #" + getSerienummer() + ": trekkraft " + trekkraft + " tonn";
    }
}

class Vogn extends Togdel {
    private static final Random RNG = new Random();

    public Vogn() {
        super(20 + RNG.nextInt(31));  // tilfeldig 20–50 tonn
    }

    @Override
    public String toString() {
        return "Vogn #" + getSerienummer() + ": vekt " + getVekt() + " tonn";
    }
}

public class Togsett {
    private final Lokomotiv lokomotiv;
    private final List<Vogn> vogner = new ArrayList<>();

    public Togsett() {
        lokomotiv = new Lokomotiv();   // komposisjon
    }

    public Lokomotiv getLokomotiv() { return lokomotiv; }
    public List<Vogn> getVogner() { return vogner; }

    public int samletVognvekt() {
        return vogner.stream().mapToInt(Vogn::getVekt).sum();
    }

    public boolean kanLeggeTil(Vogn vogn) {
        // Sant hvis vognen får plass innenfor trekkraften.
        return samletVognvekt() + vogn.getVekt() <= lokomotiv.getTrekkraft();
    }

    public Vogn leggTilVogn(Vogn vogn) {
        vogner.add(vogn);   // legg til en eksisterende vogn
        return vogn;
    }

    public Vogn leggTilVogn() {
        return leggTilVogn(new Vogn());   // overload: opprett en ny vogn hvis ingen gis
    }
}

Oppgave 5d – Utvidet program: fyll opp til trekkraften er nådd

public static void main(String[] args) {
    Togsett togsett = new Togsett();
    System.out.println("Nytt togsett opprettet.");
    System.out.println(togsett.getLokomotiv());

    // Legg til vogner helt til neste vogn ikke får plass innenfor trekkraften
    while (true) {
        Vogn vogn = new Vogn();
        if (!togsett.kanLeggeTil(vogn)) {
            break;
        }
        togsett.leggTilVogn(vogn);
    }

    System.out.printf("%nLa til %d vogner (samlet vekt %d av maks %d tonn):%n",
        togsett.getVogner().size(), togsett.samletVognvekt(), togsett.getLokomotiv().getTrekkraft());
    for (Vogn vogn : togsett.getVogner()) {
        System.out.println("  " + vogn);
    }
}
Eksempel-kjøring:
Nytt togsett opprettet.
Lokomotiv #1: trekkraft 450 tonn
La til 12 vogner (samlet vekt 431 av maks 450 tonn):
  Vogn #2: vekt 34 tonn
  Vogn #3: vekt 41 tonn … (osv.)

Oppgave 6 – Etisk dilemma ved kameraovervåking

Oppgaven: Drøft et etisk dilemma som kan oppstå når det brukes overvåkingskameraer i klasserommet og kantina (jf. Noah, 15 år, i forskningsprosjektet). Inntil 600 ord.
Eksempelsvar (ca. 500 ord):

Innledning. Å filme all undervisning og aktivitet i kantina reiser et grunnleggende etisk dilemma: hensynet til et tryggere og bedre læringsmiljø står mot elevenes rett til personvern og frihet. Jeg vil drøfte dette dilemmaet med utgangspunkt i Noahs situasjon.

Argumenter for overvåking. Skolen begrunner kameraene med at de kan redusere konflikter, hærverk og bråk, og gi lærerne innsikt i arbeidsro og samarbeid. I kantina kan kameraer virke avskrekkende og gjøre det lettere å oppklare hendelser i etterkant, slik at elever som Noah kan føle seg tryggere i friminuttene. Nytteargumentet er altså at overvåkingen kan gi en gevinst for fellesskapet: færre konflikter og et roligere miljø for de mange.

Argumenter mot overvåking. Samtidig opplever Noah det som ubehagelig at alt han gjør i timen blir filmet – særlig når han spør om hjelp eller er usikker. Her ligger kjernen i dilemmaet: konstant overvåking kan gjøre at elever slutter å tørre å prøve og feile. Læring krever nettopp at man våger å stille «dumme» spørsmål og gjøre feil. Når kameraet alltid ser på, kan det oppstå en nedkjølingseffekt der elevene endrer atferd for å unngå å bli vurdert – ikke fordi de lærer bedre, men fordi de føler seg overvåket. Dette går ut over både trivsel og reell læring.

Personvern og samtykke. Videoopptak av navngitte, mindreårige elever er sensitive personopplysninger. Etter personvernregelverket (GDPR/personopplysningsloven) må formålet være tydelig, nødvendig og forholdsmessig, og det må finnes et gyldig behandlingsgrunnlag. Når en ekstern teknologibedrift analyserer opptakene, blir spørsmålene skjerpet: Hvem eier dataene? Hvor lenge lagres de? Kan de brukes til å trene analysemodeller som selges videre? At elevene er 15 år gjør kravet til reelt, informert samtykke – og til foreldrenes involvering – enda viktigere.

Forholdsmessighet. Et sentralt etisk prinsipp er at inngrepet må stå i forhold til gevinsten. Kanskje er kameraer i kantina lettere å forsvare (åpent fellesareal, dokumentert hærverk) enn kameraer som filmer hver enkelt elev gjennom hele undervisningen. Mindre inngripende tiltak – flere voksne til stede, bedre klasseledelse, anonymiserte observasjoner – bør vurderes før man tyr til totalovervåking. Noahs egen usikkerhet på om overvåkingen «faktisk hjelper, eller bare fører til stress» peker nettopp på at gevinsten er usikker, mens ulempen (tap av frihet) er konkret.

Konklusjon. Dilemmaet lar seg ikke løse ved å velge bort det ene hensynet helt. En etisk forsvarlig løsning krever at overvåkingen begrenses til det som er strengt nødvendig og forholdsmessig, at formål og datalagring er åpne og tidsavgrensede, at elever og foresatte gis reell medbestemmelse, og at man aktivt måler om tiltaket faktisk virker. Uten disse rammene veier tapet av trygghet, frihet og læringsvilje tyngre enn den usikre gevinsten – og da bør elevenes personvern gå foran.

Oppgave 7 – Registrerte kjøretøy 2008–2024 (datasett)

Oppgaven: Les inn datasettet (CSV/JSON, UTF-8) med registrerte nye kjøretøy per drivstofftype og region 2008–2024. (7a) Regn ut totalt antall registrerte elbiler per år på tvers av regioner, og vis 2014–2024 i et tabelliknende oppsett. (7b) La brukeren velge et år 2014–2024, og vis elbiler per region i synkende rekkefølge samt hvor stor andel elbilene utgjorde av totalen i hver region. (7c) La brukeren velge en region og vis utviklingen 2008–2024 i et linjediagram fordelt på drivstofftype.
Merk om datasettet: Selve datafilene lastes ned separat fra eksamensvisningen og er ikke inkludert i teksten. Koden under antar et «langt» CSV-format med kolonnene aar;region;drivstofftype;antall (semikolon-separert, UTF-8). Er formatet «bredt» eller JSON, endrer du bare innlesningen i lesData() – resten av logikken er uendret. Elbiler gjenkjennes på drivstofftypen «Elektrisk».

Oppgave 7a – Totalt antall elbiler per år (2014–2024)

// Kjoretoy.java — oppgave 7
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.*;
import java.awt.*;

public class Kjoretoy {
    private static final Path DATAFIL = Path.of("kjoretoy_2008_2024.csv");
    private static final String EL = "elektrisk";   // drivstofftype for elbil (sammenlignes med equalsIgnoreCase)

    static List<Map<String, String>> lesData(Path filsti) throws IOException {
        // Les CSV og returner liste av rader: aar, region, drivstofftype, antall.
        List<Map<String, String>> rader = new ArrayList<>();
        try (BufferedReader br = Files.newBufferedReader(filsti, StandardCharsets.UTF_8)) {
            String[] kolonner = br.readLine().split(";");
            String linje;
            while ((linje = br.readLine()) != null) {
                String[] verdier = linje.split(";", -1);
                Map<String, String> rad = new LinkedHashMap<>();
                for (int i = 0; i < kolonner.length; i++) {
                    rad.put(kolonner[i].trim(), i < verdier.length ? verdier[i].trim() : "");
                }
                rader.add(rad);
            }
        }
        return rader;
    }

    static Map<Integer, Integer> elbilerPerAar(List<Map<String, String>> data) {
        // Sum av elbiler per år på tvers av alle regioner.
        Map<Integer, Integer> resultat = new TreeMap<>();
        for (Map<String, String> rad : data) {
            if (rad.get("drivstofftype").equalsIgnoreCase(EL)) {
                int aar = Integer.parseInt(rad.get("aar"));
                resultat.merge(aar, Integer.parseInt(rad.get("antall")), Integer::sum);
            }
        }
        return resultat;
    }

    static void visElbiltabell(List<Map<String, String>> data, int fra, int til) {
        Map<Integer, Integer> perAar = elbilerPerAar(data);
        System.out.printf("%n%-6s%12s%n", "År", "Elbiler");
        System.out.println("-".repeat(18));
        for (int aar = fra; aar <= til; aar++) {
            System.out.printf("%-6d%12d%n", aar, perAar.getOrDefault(aar, 0));
        }
    }

Oppgave 7b – Elbiler per region for valgt år (sortert + andel)

    static Map<String, int[]> regionStatistikk(List<Map<String, String>> data, int aar) {
        // For gitt år: region -> {elbiler, totalt}
        Map<String, int[]> stat = new LinkedHashMap<>();
        for (Map<String, String> rad : data) {
            if (Integer.parseInt(rad.get("aar")) != aar) {
                continue;
            }
            int antall = Integer.parseInt(rad.get("antall"));
            int[] tall = stat.computeIfAbsent(rad.get("region"), r -> new int[2]);
            tall[1] += antall;                         // totalt
            if (rad.get("drivstofftype").equalsIgnoreCase(EL)) {
                tall[0] += antall;                     // elbiler
            }
        }
        return stat;
    }

    static void visAar(List<Map<String, String>> data, int aar) {
        Map<String, int[]> stat = regionStatistikk(data, aar);
        // Sorter synkende etter antall elbiler
        List<Map.Entry<String, int[]>> rader = new ArrayList<>(stat.entrySet());
        rader.sort((a, b) -> Integer.compare(b.getValue()[0], a.getValue()[0]));

        System.out.printf("%nElbiler per region i %d (synkende):%n", aar);
        System.out.printf("%-20s%10s%10s%n", "Region", "Elbiler", "Andel");
        System.out.println("-".repeat(40));
        for (Map.Entry<String, int[]> e : rader) {
            int elbiler = e.getValue()[0];
            int totalt = e.getValue()[1];
            double andel = totalt != 0 ? (double) elbiler / totalt * 100 : 0;
            System.out.printf("%-20s%10d%8.1f %%%n", e.getKey(), elbiler, andel);
        }
    }

Oppgave 7c – Linjediagram for valgt region (per drivstofftype)

Vi tegner linjediagrammet selv i et JPanel via paintComponent med Graphics2D.drawLine – helt uten ekstern diagrampakke (som JFreeChart). Standard Swing/AWT holder.

    static void linjediagram(List<Map<String, String>> data, String region) {
        // drivstofftype -> (aar -> antall)
        Map<String, Map<Integer, Integer>> perType = new TreeMap<>();
        for (Map<String, String> rad : data) {
            if (!rad.get("region").equalsIgnoreCase(region)) {
                continue;
            }
            perType.computeIfAbsent(rad.get("drivstofftype"), t -> new TreeMap<>())
                   .merge(Integer.parseInt(rad.get("aar")),
                          Integer.parseInt(rad.get("antall")), Integer::sum);
        }

        if (perType.isEmpty()) {
            System.out.println("Fant ingen data for regionen '" + region + "'.");
            return;
        }

        List<Integer> aarListe = data.stream()
            .map(r -> Integer.parseInt(r.get("aar")))
            .distinct().sorted().collect(Collectors.toList());

        JFrame ramme = new JFrame("Registrerte kjøretøy i " + region + " (2008–2024)");
        ramme.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ramme.add(new LinjeDiagramPanel(perType, aarListe, region));
        ramme.pack();
        ramme.setLocationRelativeTo(null);
        ramme.setVisible(true);
    }

    public static void main(String[] args) throws IOException {
        List<Map<String, String>> data = lesData(DATAFIL);
        visElbiltabell(data, 2014, 2024);                  // 7a

        Scanner sc = new Scanner(System.in);
        System.out.print("\nVelg et år (2014–2024): ");
        int aar = Integer.parseInt(sc.nextLine().trim());
        visAar(data, aar);                                 // 7b

        System.out.print("Velg en region (f.eks. Telemark): ");
        String region = sc.nextLine().trim();
        linjediagram(data, region);                        // 7c
    }
}

// Egendefinert linjediagram tegnet med Graphics2D — ingen ekstern pakke
class LinjeDiagramPanel extends JPanel {
    private final Map<String, Map<Integer, Integer>> perType;
    private final List<Integer> aarListe;
    private final String region;
    private static final Color[] FARGER = {
        new Color(33, 150, 243), new Color(76, 175, 80),
        new Color(244, 67, 54), new Color(255, 152, 0),
        new Color(156, 39, 176), new Color(0, 188, 212)
    };

    LinjeDiagramPanel(Map<String, Map<Integer, Integer>> perType,
                      List<Integer> aarListe, String region) {
        this.perType = perType;
        this.aarListe = aarListe;
        this.region = region;
        setPreferredSize(new Dimension(900, 560));
        setBackground(Color.WHITE);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int venstre = 70, hoyre = 200, topp = 50, bunn = 60;
        int b = getWidth() - venstre - hoyre;
        int h = getHeight() - topp - bunn;

        int maks = 1;
        for (Map<Integer, Integer> serie : perType.values()) {
            for (int v : serie.values()) maks = Math.max(maks, v);
        }

        // Akser
        g2.setColor(Color.DARK_GRAY);
        g2.drawLine(venstre, topp, venstre, topp + h);
        g2.drawLine(venstre, topp + h, venstre + b, topp + h);

        // Y-akse-merker og rutenett
        for (int i = 0; i <= 5; i++) {
            int y = topp + h - i * h / 5;
            int verdi = maks * i / 5;
            g2.setColor(new Color(220, 220, 220));
            g2.drawLine(venstre, y, venstre + b, y);
            g2.setColor(Color.DARK_GRAY);
            g2.drawString(String.valueOf(verdi), 10, y + 4);
        }

        // X-akse-merker
        int n = aarListe.size();
        for (int i = 0; i < n; i++) {
            int x = venstre + (n == 1 ? b / 2 : i * b / (n - 1));
            g2.drawString(String.valueOf(aarListe.get(i)), x - 14, topp + h + 20);
        }

        // Én linje per drivstofftype
        int fargeIdx = 0, legendY = topp;
        for (Map.Entry<String, Map<Integer, Integer>> e : perType.entrySet()) {
            Color farge = FARGER[fargeIdx % FARGER.length];
            g2.setStroke(new BasicStroke(2f));
            int forrigeX = -1, forrigeY = -1;
            for (int i = 0; i < n; i++) {
                int aar = aarListe.get(i);
                int verdi = e.getValue().getOrDefault(aar, 0);
                int x = venstre + (n == 1 ? b / 2 : i * b / (n - 1));
                int y = topp + h - verdi * h / maks;
                g2.setColor(farge);
                if (forrigeX != -1) g2.drawLine(forrigeX, forrigeY, x, y);
                g2.fillOval(x - 3, y - 3, 6, 6);
                forrigeX = x;
                forrigeY = y;
            }
            // Forklaring (legend)
            g2.setColor(farge);
            g2.fillRect(venstre + b + 20, legendY, 12, 12);
            g2.setColor(Color.BLACK);
            g2.drawString(e.getKey(), venstre + b + 38, legendY + 11);
            legendY += 22;
            fargeIdx++;
        }

        g2.setColor(Color.BLACK);
        g2.setFont(getFont().deriveFont(Font.BOLD, 15f));
        g2.drawString("Registrerte kjøretøy i " + region + " (2008–2024)", venstre, 30);
    }
}

Oppgave 8 – Spillet «stolpebyggeren»

Oppgaven: Lag et objektorientert spill. Hovedscenen er 800×400 px. Stolpebyggeren (150×70 px) står midt nederst, styres til venstre/høyre og starter med tre liv. Stolpedeler (høyde 50, bredde 50/100/150, to farger) faller fra tilfeldige posisjoner langs øvre kant, minst 50 px fra sidene, uten å overlappe. Byggeren fanger deler ved kollisjon og bygger to stolper med vekslende farge – først til høyre, så til venstre. Riktig farge roteres 90° og legges på toppen av stolpen; feil farge koster ett liv. Spillet slutter når begge stolpene er ferdige eller alle liv er tapt, og viser en oppsummering.
Om implementasjonen: Vi bruker Java Swing (javax.swing/java.awt), som følger med JDK-en – ingen eksterne pakker trengs. Siden delene alltid er 50 px høye, blir de 50 px brede etter kvartrotasjonen, og stolpene stables ryddig oppover. En stolpe regnes som ferdig når den samlede høyden når 400 px (toppen av scenen). Piltastene styrer byggeren. Kompiler med javac Stolpebyggeren.java og kjør med java Stolpebyggeren.
// Stolpebyggeren.java — oppgave 8
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Stolpebyggeren {
    static final int BREDDE = 800, HOYDE = 400;
    static final int FANGER_B = 150, FANGER_H = 70;
    static final int DEL_H = 50;
    static final int[] DEL_BREDDER = {50, 100, 150};
    static final int KANT = 50;                // deler minst 50 px fra sidene
    static final int STOLPE_B = DEL_H;         // bredde på en rotert del
    static final int FART_FANGER = 9;
    static final int FART_FALL = 3;
    static final int SPAWN_MS = 1300;
    static final int FPS = 60;
    static final Color BG = new Color(240, 240, 245);
    static final Random RNG = new Random();

    static Color farge(String navn) {
        return navn.equals("blå") ? new Color(33, 150, 243) : new Color(76, 175, 80);
    }

    // ---- En enkelt stolpedel som faller ----
    static class Stolpedel {
        Rectangle rect;
        String fargenavn;

        Stolpedel(int x, int bredde, String fargenavn) {
            this.rect = new Rectangle(x, -DEL_H, bredde, DEL_H);
            this.fargenavn = fargenavn;
        }

        void fall() {
            rect.y += FART_FALL;
        }

        void roter() {
            // Kvart rotasjon (90°): bredde og høyde bytter plass
            int tmp = rect.width;
            rect.width = rect.height;
            rect.height = tmp;
        }

        void tegn(Graphics2D g) {
            g.setColor(farge(fargenavn));
            g.fillRoundRect(rect.x, rect.y, rect.width, rect.height, 8, 8);
            g.setColor(new Color(30, 30, 30));
            g.drawRoundRect(rect.x, rect.y, rect.width, rect.height, 8, 8);
        }
    }

    // ---- En sidestolpe som bygges nedenfra og opp med vekslende farger ----
    static class Stolpe {
        final int x;
        final List<Stolpedel> deler = new ArrayList<>();

        Stolpe(int xVenstre) {
            this.x = xVenstre;
        }

        int hoyde() {
            return deler.stream().mapToInt(d -> d.rect.height).sum();
        }

        String nesteFarge() {
            if (deler.isEmpty()) {
                return "blå";                 // første del kan være hvilken som helst; vi krever blå
            }
            return deler.get(deler.size() - 1).fargenavn.equals("blå") ? "grønn" : "blå";
        }

        boolean ferdig() {
            return hoyde() >= HOYDE;
        }

        void leggTil(Stolpedel del) {
            del.roter();                      // blir STOLPE_B bred, gammel bredde blir høyde
            del.rect.width = STOLPE_B;
            del.rect.x = x;
            del.rect.y = HOYDE - hoyde() - del.rect.height;
            deler.add(del);
        }

        void tegn(Graphics2D g) {
            for (Stolpedel d : deler) d.tegn(g);
        }
    }

    // ---- Spilleren som fanger deler ----
    static class Stolpebygger {
        Rectangle rect = new Rectangle((BREDDE - FANGER_B) / 2, HOYDE - FANGER_H, FANGER_B, FANGER_H);
        int liv = 3;

        void flytt(int dx) {
            rect.x = Math.max(0, Math.min(BREDDE - FANGER_B, rect.x + dx));
        }

        void tegn(Graphics2D g) {
            g.setColor(new Color(90, 90, 90));
            g.fillRoundRect(rect.x, rect.y, rect.width, rect.height, 12, 12);
            g.setColor(new Color(20, 20, 20));
            g.drawRoundRect(rect.x, rect.y, rect.width, rect.height, 12, 12);
        }
    }

    // ---- Spill-løkke og tilstand (JPanel med Swing-timer) ----
    static class Spill extends JPanel {
        final Stolpebygger bygger = new Stolpebygger();
        final List<Stolpedel> fallende = new ArrayList<>();
        final Stolpe hoyre = new Stolpe(BREDDE - STOLPE_B);   // bygges først, helt til høyre
        final Stolpe venstre = new Stolpe(0);               // bygges sist, helt til venstre
        long sistSpawn = 0;
        boolean slutt = false;
        boolean venstreTast, hoyreTast;
        final Timer timer;

        Spill() {
            setPreferredSize(new Dimension(BREDDE, HOYDE));
            setBackground(BG);
            setFocusable(true);
            addKeyListener(new KeyAdapter() {
                @Override public void keyPressed(KeyEvent e) { settTast(e.getKeyCode(), true); }
                @Override public void keyReleased(KeyEvent e) { settTast(e.getKeyCode(), false); }
            });
            timer = new Timer(1000 / FPS, e -> steg());
        }

        void settTast(int kode, boolean nede) {
            if (kode == KeyEvent.VK_LEFT) venstreTast = nede;
            if (kode == KeyEvent.VK_RIGHT) hoyreTast = nede;
        }

        Stolpe aktivStolpe() {
            return !hoyre.ferdig() ? hoyre : venstre;
        }

        void spawnDel() {
            for (int forsok = 0; forsok < 20; forsok++) {     // prøv å finne ledig posisjon uten overlapp
                int bredde = DEL_BREDDER[RNG.nextInt(DEL_BREDDER.length)];
                int x = KANT + RNG.nextInt(BREDDE - 2 * KANT - bredde + 1);
                Rectangle ny = new Rectangle(x, -DEL_H, bredde, DEL_H);
                boolean overlapp = fallende.stream().anyMatch(d -> ny.intersects(d.rect));
                if (!overlapp) {
                    String fargenavn = RNG.nextBoolean() ? "blå" : "grønn";
                    fallende.add(new Stolpedel(x, bredde, fargenavn));
                    return;
                }
            }
        }

        void oppdater(int dtMs) {
            sistSpawn += dtMs;
            if (sistSpawn >= SPAWN_MS) {
                spawnDel();
                sistSpawn = 0;
            }

            for (Stolpedel del : new ArrayList<>(fallende)) {
                del.fall();
                if (del.rect.intersects(bygger.rect)) {
                    fang(del);
                    fallende.remove(del);
                } else if (del.rect.y > HOYDE) {
                    fallende.remove(del);           // bommet — ingen straff
                }
            }

            if ((hoyre.ferdig() && venstre.ferdig()) || bygger.liv <= 0) {
                slutt = true;
            }
        }

        void fang(Stolpedel del) {
            Stolpe stolpe = aktivStolpe();
            if (del.fargenavn.equals(stolpe.nesteFarge())) {
                stolpe.leggTil(del);                // riktig farge
            } else {
                bygger.liv--;                       // feil farge koster et liv
            }
        }

        void steg() {
            if (slutt) {
                timer.stop();
                repaint();
                return;
            }
            if (venstreTast) bygger.flytt(-FART_FANGER);
            if (hoyreTast) bygger.flytt(FART_FANGER);
            oppdater(1000 / FPS);
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            hoyre.tegn(g2);
            venstre.tegn(g2);
            for (Stolpedel d : fallende) d.tegn(g2);
            bygger.tegn(g2);

            g2.setColor(Color.BLACK);
            g2.setFont(new Font("SansSerif", Font.PLAIN, 18));
            g2.drawString("Liv: " + bygger.liv + "   Neste farge: " + aktivStolpe().nesteFarge(), 10, 24);

            if (slutt) visResultat(g2);
        }

        void visResultat(Graphics2D g) {
            g.setColor(new Color(255, 255, 255, 220));
            g.fillRect(0, 0, BREDDE, HOYDE);
            String tittel = bygger.liv > 0
                ? "Gratulerer! Begge stolpene er ferdig bygd."
                : "Game over – du mistet alle livene.";
            String[] linjer = {
                tittel,
                "Deler i høyre stolpe:  " + hoyre.deler.size(),
                "Deler i venstre stolpe: " + venstre.deler.size()
            };
            g.setColor(Color.BLACK);
            g.setFont(new Font("SansSerif", Font.PLAIN, 20));
            for (int i = 0; i < linjer.length; i++) {
                int bredde = g.getFontMetrics().stringWidth(linjer[i]);
                g.drawString(linjer[i], BREDDE / 2 - bredde / 2, 150 + i * 34);
            }
        }

        void start() {
            timer.start();
        }
    }

    public static void main(String[] args) {
        JFrame ramme = new JFrame("Stolpebyggeren");
        ramme.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Spill spill = new Spill();
        ramme.add(spill);
        ramme.pack();
        ramme.setLocationRelativeTo(null);
        ramme.setVisible(true);
        spill.requestFocusInWindow();
        spill.start();
    }
}
Designvalg verdt å nevne for sensor:
  • Objektorientering: Ansvaret er delt på Stolpedel (én del), Stolpe (en sidestolpe under bygging), Stolpebygger (spilleren) og Spill (spill-løkke og tilstand).
  • Vekslende farge: Stolpe.nesteFarge() avgjør hvilken farge som må fanges neste gang; feil farge håndteres i fang() med tap av liv.
  • Rekkefølge: aktivStolpe() bygger høyre stolpe først og går over til venstre når høyre er ferdig.
  • Rotasjon: Kvartrotasjonen bytter bredde og høyde, slik at delene stables 50 px brede oppover.
  • Ingen overlapp: spawnDel() prøver på nytt til den finner en posisjon som ikke kolliderer med deler som allerede faller.
  • Spill-løkke: En javax.swing.Timer driver game-loopen på Event Dispatch Thread, og KeyAdapter fanger piltastene.

Oppgave 9 – Innlevering

Oppgaven: Last opp ett komprimert arkiv (.zip/.tar/.7z/.gz/.rar) med kandidatnummer som filnavn, som inneholder svarene på 4b, 5, 7 og 8.

Foreslått mappestruktur (f.eks. 123456.zip):

123456/
├── oppgave4b/
│   └── forklaring_algoritme.txt      (tekstsvaret ditt til 4b)
├── oppgave5/
│   └── Togsett.java                  (Togdel, Lokomotiv, Vogn, Togsett)
├── oppgave7/
│   ├── Kjoretoy.java                 (inkl. LinjeDiagramPanel)
│   └── kjoretoy_2008_2024.csv        (datasettet)
├── oppgave8/
│   └── Stolpebyggeren.java
└── README.txt   (hvordan hver fil kompileres/kjøres med javac/java, og hvilken JDK)
Sjekkliste før innlevering:
  • Alt kompilerer og kjører uten at sensor må endre filnavn eller stier
  • Hver public-klasse ligger i en fil med samme navn (Togsett.java, Kjoretoy.java, Stolpebyggeren.java)
  • Ingen navn eller brukernavn i kode eller metadata (eksamen er anonym)
  • Datasettet ligger sammen med koden til oppgave 7
  • README.txt forklarer hvordan hver fil kompileres (javac) og kjøres (java), og at bare standard JDK 11 eller nyere trengs – Swing/AWT følger med, ingen eksterne pakker
  • Arkivet er < 500 MB og har kandidatnummeret som filnavn

Om oppgaveteksten: Oppgaveteksten i dette løsningsforslaget er gjengitt fra Utdanningsdirektoratets (UDIR) eksamen i Informasjonsteknologi IT 2 – Diverse språk (våren 2026). Vi gjengir oppgaveteksten bevisst, slik at du kan følge løsningen uten å veksle mellom dokumenter. Eksamensoppgaver fra offentlige myndigheter er uten opphavsrettsvern etter åndsverkloven § 14 og kan gjengis fritt. Selve løsningsforslaget, forklaringene og figurene er utarbeidet av Eksamenssett.no. Opphavsrettsbeskyttede bilder og illustrasjoner fra originaleksamen er fjernet.

Eldre løsning
Vår 2025

Alle løsningsforslag for IT 2 – Diverse språk

Vår 2026Vår 2025Høst 2024Vår 2024Høst 2023
Se eksamensoppgaven
eksamenssett.noTren målrettet

Komplett samling av eksamensoppgaver og løsninger for norsk skole.

Om ossPrivatundervisningPriserSlik bruker du sidenFAQPersonvernVilkårAngrerettKontaktKI-deklarasjon

© 2026 Eksamenssett.no · Alle rettigheter forbeholdt

Innholdet er utviklet med KI og kvalitetssikres kontinuerlig – av modellene, og ved at våre tusenvis av brukere kan melde fra om feil. Slik jobber vi med kvalitet →

Eksamenssett.no eies og drives av Studenthjelp Privatundervisning AS

Org.nr. 913 117 387 (Foretaksregisteret) · Aksel Olsens vei 10B, 1597 Moss · Ikke MVA-registrert