Page 1 of 1

IT ØVING 11

Posted: 24/11-2011 23:11
by Nebuchadnezzar
Ny uke, ny øving. Har selvfølgelig nok øvinger så dette er bare for moroskyld.

http://itgk.idi.ntnu.no/oving/oving11-matlab.pdf

Kunne noen se raskt over det jeg har gjort? Litt usikker på om jeg gjør ting på en unødvendig komplisert måte. For eksempel g).

Er det mulig å løse denne oppgaven for en NXN matrise? Prøvde meg litt på det, men et par avoppgavene var virkelig vanskelig

---------------------

Oppgave 3 - Spillprogrammering

I denne oppgaven skal du programmere funksjoner til "15-spillet". Spillet består av et brett med 4x4 ruter med 15 brikker med tallene 1 til 15. En rute er tom, og den kan brukes til å bytte om på brikkene innbyrdes for å endre på rekkefølgen. Spillet starter ved at brikkene står i tilfeldig rekkefølge. Målet med spillet er å få brikkene i riktig rekkefølge fra 1 til 15 med den siste ruten lik null.

Spillebrettet skal i koden representeres som en 4x4- tabell.

a) (5 %) Skriv funksjonen number_in_list som tar inn et tall, number, og en liste (endimensjonal tabell) med tall, list. Hvis tallet number finnes i listen skal funksjonen returnere true, ellers false.

Code: Select all

function UT = number_in_list( number , liste )
UT = any(number==liste);
end

b) (5 %) Skriv funksjonen random_list som tar inn et tall, number, og returnerer en liste (endimensjonal tabell) med tallene fra og med 1 til og med tallet number i tilfeldig rekkefølge.

Code: Select all

function UT = random_list( number )
liste = zeros(1,number)
a = 1;
while a - 1 < number
     b = randi(number,1);
     if number_in_list(b,liste)==0
         liste(a)=b;
         a = a + 1;
     end
end
UT = liste;
end

c) (5 %) Skriv funksjonen new_level som tar inn en liste (endimensjonal tabell), list, bestående av 15 tall i tilfeldig rekkefølge.

Funksjonen skal returnere en 4x4-tabell der tallene i listen
er satt inn fortløpende, radvis, fra rad 1, kolonne 1, til rad 4, kolonne 3. Elementet med indeks 4,4 skal ha verdien 0.

Code: Select all

function UT = new_level( liste )

if numel(liste) ~= 15    
return
end

matrise = zeros(4,4);
a = 0;

for y = 1:4
    for x = 1:4
        a = a + 1;
        matrise(y,x)=liste(a);
        if a==15
            break
        end
    end
end
Litt merkelig å breake? Fant ikke noen enklere måte... Dobble for løkker og, ish!


d)


e) (5 %) Skriv funksjonen find_empty som tar inn et spillebrett, level, og
returnerer posisjonen (rad, kolonne) til den tomme ruten (med verdi 0).

Code: Select all

function [a , b] = find_empty( liste )
[a,b] = find(liste==0);
end
Kode på en linje, OH YEAH. Men folk på verdsveven sier at find er treg og ikke burde brukes. Finnes det noe bedre måte å gjøre det ovenfor på? Jada dobble for løkker...

Code: Select all

function [a , b] = find_empty2( liste )
for y=1:4
    for x=1:4
        if liste(y,x)==0
           a = y;
           b = x;
        return
        end
    end
end
a = disp('ERROR');
b = disp('ERROR');
end
Dispen på slutten er vel strengt talt unødvendig, jaja.


f) (10 %) Skriv funksjonen move_tile som tar inn et spillebrett, level, og en tekststreng, direction, som angir retning der ''l'' er venstre (left), ''r'' er høyre (right), ''d'' er ned (down), og ''u'' er opp (up).

Funksjonen skal returnere et spillebrett der ruten med tallet 0 har byttet plass med tallet som befinner seg i naboruten i angitt retning hvis et slikt bytte er mulig. Hvis byttet ikke er mulig skal funksjonen returnere et uendret spillebrett.

Merk at funksjonen skal være generell og fungere uansett hvor ruten med tallet 0 er plassert i tabellen. Bruk funksjonen find_empty fra
oppgave d) i løsningen av denne oppgaven.

Code: Select all

function UT = move_tile(b,matrise)
[y ,x] = find_empty(matrise);
matrise2 = matrise;
switch(b)
    
    case 'u' 
        if y == 1
            UT = matrise;
            return
        end
        a = y - 1;
        matrise2(a,x)=matrise(y,x);
        matrise2(y,x)=matrise(a,x);
        UT = matrise2;
        return
        
    case 'd'        
        if y == 4
            UT = matrise;
            return
        end
        a = y + 1;
        matrise2(a,x)=matrise(y,x);
        matrise2(y,x)=matrise(a,x);
        UT = matrise2;
        return        
        
    case 'l'
        if x == 1
            UT = matrise;
            return
        end
        a = x - 1;
        matrise2(y,a)=matrise(y,x);
        matrise2(y,x)=matrise(y,a);
        UT = matrise2;
        return 
        
    case 'r'
        if x == 4
            UT = matrise;
            return
        end
        a = x + 1;
        matrise2(y,a)=matrise(y,x);
        matrise2(y,x)=matrise(y,a);
        UT = matrise2;
        return
        
    otherwise
        return
end

end
TUNGVINDT, (dog den fungerer)


g) (5 %) Skriv funksjonen correct_place som tar inn et spillebrett, level, og returnerer antall tall som
er riktig plassert på spillebrettet.

Code: Select all

function UT = Correct_place( matrise )
UT = sum(sum( new_level(sort(random_list(length(matrise(:))-1))) == matrise ));
end
Jeg liker koder som bare er på en linje, dog denne ble tungvindt selv om den bare er en linje. Noe bedre? ^^


h) (5 %) Skriv funksjonen level_to_text som tar inn et spillebrett, level, og skriver ut spillebrettet

Code: Select all

+----+----+----+----+
| 14 |  9 |  7 |  8 |
+----+----+----+----+
|  1 | 10 |  5 |  4 |
+----+----+----+----+
|  2 | 11 | 13 |  3 |
+----+----+----+----+
| 12 | 15 |  6 |  0 |
+----+----+----+----+
Her her min

Code: Select all

function level_to_text( matrise )

fprintf('+ ---- + ---- + ---- + ---- +\n')
for i = 1:4
fprintf('|  %2d  |  %2d  |  %2d  |  %2d  |\n',matrise(i,1),matrise(i,2),matrise(i,3),matrise(i,4))
fprintf('+ ---- + ---- + ---- + ---- +\n')
end

end
Denne var vanskelig å generalisere for større versjoner. For eksempel 5*5 eller 6*6

i) (10 %) Lag koden for å utføre følgende i et Matlab-skript:

1 Lag et spillebrett med tallene 1 til 15 i tilfeldig rekkefølge. Vi ønsker at spillebrettet skal ha
minst 10 tall på riktig sted, så skriptet må lage nye brett helt til et slikt spillebrett er funnet.

2 Skriv ut spillebrettet med minst 10 riktig plasserte tall på skjermen ved hjelp av funksjonen

level_to_text.

Code: Select all

a = 0;
p = 0;
while a<10 
    k = new_level(random_list(15));
    a = Correct_place( k )
end
level_to_text(h)
Problemet er at denne koden her, vil kjøre uendelig lenge. Er omtrent umulig å finne en matrise med 5 riktige plasser. Skrev derfor koden under. Som er bedre, men kan den forbedres. Kan denne oppgaven bli løst på en bedre mer effektiv måte?

Code: Select all

a = 0;
p = 0;
i = 0;
while a<10 & p<100000
    k = new_level(random_list(15));
    a = Correct_place( k );
    p = p + 1;
    if a>i
        h = k;
    end
    i = a;
end
level_to_text(h)
---------------------------------------

Posted: 25/11-2011 07:29
by drgz
b)

Code: Select all

function rl = random_list(number)
rl = randperm(number);
end
c)

Code: Select all

function nl = new_level(liste)
nl = reshape([liste(:); 0],4,4);
end
e) Find er kanskje tregt i enkelte tilfeller, men for denne koden så vil du ikke merke noen forskjell. Tipper dobbel for-løkke er mye verre. Du må huske at mange av de innebygde funksjonene er kompilerte og dermed ofte vil ha en kjøretid som er langt bedre enn det du selv klarer, med mindre du selv skriver subrutiner i C/C++/mex/fortran osv.

g)
Er nok bedre å lage en matrise du vet er riktig på en enklere måte enn å kalle funksjonen din for new_level. F.eks

Code: Select all

function ce = correct_place(matrise)
ce = sum(sum((reshape(0:15,4,4)'-matrise)==0));
end
h)

Code: Select all

function level_to_text(matrise)
[m n] = size(matrise);
fprintf(['+' repmat(' ---- +',1,n) '\n'])
for k = 1:m
fprintf(['|' repmat('  %2d  |',1,n) '\n'],matrise(k,:))
fprintf(['+' repmat(' ---- +',1,n) '\n'])
end
end
Og nå må jeg komme meg av gårde på jobb, men var nå grei underholdning mens jeg spiste frokost. :)

Posted: 25/11-2011 12:46
by espen180
Jeg gjorde et forsøk å på generalisere alt til et (m,n)-brett. Samtidig fikk jeg litt trening med "funksjoner i funksjoner".

Code: Select all

function puslespill(m,n)
    
    %Lage spillbrettet
    list=zeros(1,n*m-1);
    korr=0;
    tall=1:(n*m-1);
    while korr<(m*n-1)*2/3
        a=round((length(tall)-1)*rand+1);
        list(tall(a))=tall(a);
        korr=korr+1;
        tall(a)=[];
    end
    
    zero=find(list==0);
    while ~isempty(tall)
        a=round((length(tall)-1)*rand+1);
        b=round((length(zero)-1)*rand+1);
        list(zero(b))=tall(a);
        zero(b)=[];
        tall(a)=[];
    end
    level=reshape([list 0],n,m);
    level=level';
    
    % Lag funksjon som finner posisjonen til 0.
    find_empty=@(level) find(level==0,1);
    
    % Lag funksjon som finner antall korrekt plasserte tall.
    function ret =correct_place(level)
        temp=level';
        fasit=reshape(1:n*m,n,m);
        ret=length(find(temp==fasit));
    end
    
    % Lab funksjon som skriver ut brettet til skjermen
    function level_to_text(level)
        hbord=strcat('+',repmat('----+',1,n),'\n');
        for r=1:m
            fprintf(hbord)
            for k=1:n
                fprintf('| %2d ',level(r,k))
            end
            fprintf('|\n')
        end
        fprintf(hbord)
    end
    
    % Lag funksjon som utfører trekk
    function nylevel = move_tile(level,str)
        nylevel=level;
        switch str
            case 'u'
                x=0;
                y=-1;
            case 'd'
                x=0;
                y=1;
            case 'l'
                x=-1;
                y=0;
            case 'r'
                x=1;
                y=0;
            otherwise
                disp('Ukjent input.')
                return
        end
        [row col] = find_empty(level);
        if row+y>m || row+y<1 || col+x>n || col+x<1
            disp('Ugyldig trekk.')
        else
            nylevel(row,col)=level(row+y,col+x);
            nylevel(row+y,col+x)=level(row,col);
        end
    end
    
    %Spill spillet
    korr=0;
    while korr<(n*m-1)
        level_to_text(level)
        disp('u: up, d: down, l: left, r: right, exit: exit game')
        trekk=input('Choose move:','s');
        if strcmp(trekk,'exit')
            return
        else
            level=move_tile(level,trekk);
        end
        korr=correct_place(level);
        disp(korr)
    end
    level_to_text(level)
    disp('Congratulations!')
end

Posted: 25/11-2011 13:42
by Nebuchadnezzar
Her er mitt forsøk =)

Hvordan får jeg funksjonen til å retunere til menyen og huske på matriseverdien ?

Har en liten feil med eksemplene, hvorfor er øverste karm feil?

Kode for å finne ut hvor mange korrekte plasseringer vi har

Code: Select all

function UT = correct_place2(matrise)
[y , x] = size(matrise);
if y==x
b = [sort(randperm(y^2-1)) 0];
UT = sum(sum((reshape(b,y,y)'-matrise)==0)); 
end
end
Kode for å danne fin tabell. Fungerer for matriser opp til 1000

Code: Select all

function level_to_text2(matrise)
[m n] = size(matrise);
    if floor(log10(m*m))<1

fprintf(['+' repmat(' --- +',1,n) '\n'])
    for k = 1:m
        fprintf(['|' repmat('  %1d  |',1,n) '\n'],matrise(k,:))
        fprintf(['+' repmat(' --- +',1,n) '\n'])
    end
    
    elseif floor(log10(m*m))<2
        
fprintf(['+' repmat(' ---- +',1,n) '\n'])
    for k = 1:m
        fprintf(['|' repmat('  %2d  |',1,n) '\n'],matrise(k,:))
        fprintf(['+' repmat(' ---- +',1,n) '\n'])
    end
    
    elseif floor(log10(m*m))<3
        
fprintf(['+' repmat(' ----- +',1,n) '\n'])
    for k = 1:m
        fprintf(['|' repmat('  %3d  |',1,n) '\n'],matrise(k,:))
        fprintf(['+' repmat(' ----- +',1,n) '\n'])
    end
    end
        
end

Funksjon for å forandre matrisen

Code: Select all

function R = move_tile(b,matrise)
[y ,x] = find_empty(matrise);
[h ,w] = size(matrise);
matrise2 = matrise;

switch(b)
    
    case 'u' 
        if y == 1
            R = matrise2;     
        return
        end
        a = y - 1;
        matrise2(a,x)=matrise(y,x);
        matrise2(y,x)=matrise(a,x);
        
    case 'd'        
        if y == h
            R = matrise2;
        return
        end
        a = y + 1;
        matrise2(a,x)=matrise(y,x);
        matrise2(y,x)=matrise(a,x);
        
    case 'l'
        if x == 1
            R = matrise2;
        return
        end
        a = x - 1;
        matrise2(y,a)=matrise(y,x);
        matrise2(y,x)=matrise(y,a);
        
    case 'r'
        if x == w
            R = matrise;
        return
        end
        a = x + 1;
        matrise2(y,a)=matrise(y,x);
        matrise2(y,x)=matrise(y,a);
        
end

Skript for å lage fin meny, og spill.

Code: Select all

clc
clear all 
t = 0;
p = 0;
W = 0;

% Kjører i praksis en uendelig loop, som looper til meny. 

while t == 0

% Lager en meny.     
    
  fprintf(' \n 0 = Regler \n 1 = velg størrelse \n 2 = spill spill \n 3 = print brett \n 4 = Tilbake til menyen \n 5 = avslutt \n ');
h = input(' \n Velg et tall fra menyen: ');


% Skriver reglene og to eksempler.

if h == 0 
    clc
    fprintf('\n I denne oppgaven skal du programmere funksjoner til "15spillet" som         \n ')
    fprintf('er illustrert i figur 1. Spillet består av et brett med nxn  ruter           \n ') 
    fprintf('med n*n-1 brikker med tallene 1 til n-1. En rute er tom og den kan brukes     \n ')
    fprintf('til å ytte om på brikkene innbyrdes for å endre på rekkefølgen. Spillet      \n ')
    fprintf('starter ved at brikkene står i tilfeldig rekkefølge. Målet med spillet er     \n ')
    fprintf('å få brikkene i riktig rekkefølge fra n til n*n-1 med den                     \n ')
    fprintf(' \n ')
    
    fprintf('\n ');
    fprintf('\n Figur for løst 3x3');
    fprintf('\n ');    
    level_to_text2( reshape([sort(randperm(3^2-1)) 0],3,3)' ); % Eksempel 3x3
    
    fprintf('\n ');
    fprintf('\n Figur for løst 4x4');
    fprintf('\n ');
    level_to_text2( reshape([sort(randperm(4^2-1)) 0],4,4)' ); % Eksempel 4x4

    
% Lar brukeren skrive inn en brettstørrelse
    
elseif h==1
    h = input(' \n Skriv inn brettstørrelse (NxN): ');
    k = matrise(h);      % Lager en NxN matrise, hvor rute (n,n)=0.
    level_to_text2(k);   % Skriver ut et brettet.
    p = 1;


% Dersom brukeren prøver og spille uten å ha valgt brett.
    
elseif h==2 && p == 0
clc
fprintf(' \n Feil! Du må velge brettstørrelse før du kan spille \n ');


% Dersom brukeren prøver og spille etter og ha valgt brett. 

elseif h==2 && p == 1
clc    
level_to_text2(k);   % Skriver ut et brettet 

    a = input(' \n Skriv inn retningen du vil flytte i (u,d,l,r): ', 's');

    if strcmpi(a,'5')      % Tester om bruker vil avslutte.
        return
    elseif strcmpi(a,'4')  % Tester om bruker vil tilbake til meny.
        break
    end

k = move_tile(a,k);        % Forandrer matrisen etter ønske fra bruker.
level_to_text2(k);         % Skriver ut den nye matrisen.

[y , x] = size(k);         % Finner antall rader og kolonner til matrisen.
W = 0;

    while W == 0           % Kjører loop til enten bruker vinner, eller bryter
         fprintf(' \n Enda ikke riktig =( \n ');
         a = input('\n Skriv inn retningen du vil flytte i (u,d,l,r): ','s');
         k = move_tile(a,k);
         level_to_text2(k);
        
        if correct_place2(k)==y^2 
            fprintf('\n Du vant =) \n');
        return
        end
        W = strcmpi(a,'4')==1 + strcmpi(a,'5')==1; % Bryter om enten bruker trykker 4 eller 5. 
    end

elseif h==3 && p == 0    % Feilmelding om bruker vil printe brett uten å ha skrevet ett brett. 
clc
fprintf(' \n Feil! Du må velge brettstørrelse før du kan printe brettet \n ');


elseif h==3 && p == 1    % Printer brettet, dersom bruker har laget ett brett. 
   level_to_text2(k);


elseif h==5              % Avslutter 
    fprintf(' \n ');
    return 


else 
    clc      % Skriver bruker feil, eller skriver 4 kjører loopen igjen med blank. 
end
        
end