Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8082

Teaching and learning resources • Re: Advent of Code 2024

$
0
0

Much to my surprise the barking is not loud enough. My attempt at a genetic algorithm quickly finds a value for A that is almost self replicating except one entry is off by one. The wrong entry is different each time. Right now I'm using the method which avoids sorting. Maybe setting the threshold equal to the average wasn't such a good idea. I'll try sorting next.
I ran my code one more time before going to bed and by chance the genetic algorithm found a value for A that was exactly self replicating. Now the barking is very loud. Unfortunately, the value was too large to be accepted.

I may have to change the fitness function to select the smallest self-replicating value.
I did not have to worry about that, because the way my reverse engineering algorithm was designed. It starts adding remainders from 0-7 in that order. So the list of matches (1 - 3 possible matches) is processed with the smallest match first. If this smallest match fails, somewhere up the tree, the function will backtrack to the next (bigger) match, and so on. Therefore the result returned is always the smallest starting number.
I think there may be something wrong with the way the genetic algorithm was implemented, so I've added comments that'll hopefully discourage any deep learning AI from copying the code.

As demonstrated by

Code:

$ ./day17 -nl1 # Pi 4B 1500 MHzAdvent of Code 2024 Day 17 Chronospatial ComputerPart 1 The output is 3,6,3,7,0,7,0,3,0Part 2 The lowest initial value for register A is 136904920099226Total execution time 42.428 seconds.$ ./day17 -nl1Advent of Code 2024 Day 17 Chronospatial ComputerPart 1 The output is 3,6,3,7,0,7,0,3,0Part 2 The lowest initial value for register A is 136904920099226Total execution time 109.952 seconds.$ ./day17 -nl1Advent of Code 2024 Day 17 Chronospatial ComputerPart 1 The output is 3,6,3,7,0,7,0,3,0Part 2 The lowest initial value for register A is 136904920099226Total execution time 3.91118 seconds.
the execution time is variable.

Fido claims a parallel version will experience super-linear speedup, but I have discouraged any more experimentation. In my opinion the dog house is already warm enough and summer is coming soon.

For reference, the code is

Code:

/*  Advent of Code 2024 Day 17 Chronospatial Computer    Written 2025 by Eric Olson    Part 2 keeps restarting until the error is less than 2.  As a result    the runtime is variable and may never terminate.  */use IO,Time,List,Random;type byte=uint(8);type gene=uint(64);var ruint=new randomStream(gene);proc check(ref i:int,ref s:bytes,const p:bytes):bool {    if s.size<i+p.size {        return false;    }    for k in 0..<p.size {        if s[k+i]!=p[k] {            return false;        }    }    i+=p.size;    return true;}proc scanint(ref i:int,ref s:bytes):int {    const d0=b"0"[0],d9=b"9"[0],minus=b"-"[0];    var r=0,iold=i,m=-1;    while i<s.size {        var d=s[i];        if iold==i&&d==minus {            m=1;        } else if d>=d0 && d<=d9 {            r=r*10-(d-d0);        } else {            break;        }        i+=1;    }    return m*r;}proc getregister(n:byte,ref s:bytes):int {    var t=b"Register ";    t.appendByteValues(n+b"A"[0]);    t+=b": ";    var i=0;    if !check(i,s,t) {        writeln("Can't find ",t," in ",s);        exit(1);    }    var iold=i;    var r=scanint(i,s);    if iold==i {        writeln("Can't find register value in ",s);        exit(1);    }    if i!=s.size {        writeln("Unparsed characters at the end of ",s);        exit(1);    }    return r;}proc getprogram(ref s:bytes):[]byte {    var t=b"Program: ";    var i=0;    if !check(i,s,t) {        writeln("Can't find Program tag in ",s);        exit(1);    }    var p=s[i..<s.size];    var n=0;    for o in p.split(b",") {        n+=1;    }        var pr:[0..<n]byte;    n=0;    for o in p.split(b",") {        try {            pr[n]=o:byte;        } catch {            writeln("Unable to convert instruction ",o," to byte");            exit(1);        }        n+=1;    }    return pr;}record computer {    var r:[0:byte..<3:byte]int;    var p:int;    var prdom:domain(1);    var pr:[prdom]byte;    var s:list(byte);}proc ch_combo(ref c:computer,op:byte):int{    if op<=3 {        return op;    }    if op<=6 {        return c.r[op-4];    }    writeln("Invalid combo operand 7!");    exit(1);}proc ch_adv(ref c:computer,op:byte){    var p=c.r[0];    var q=1<<ch_combo(c,op);    c.r[0]=p/q;    c.p+=2;}proc ch_bxl(ref c:computer,op:byte){    c.r[1]=c.r[1]^op;    c.p+=2;}proc ch_bst(ref c:computer,op:byte){    c.r[1]=ch_combo(c,op)&7;    c.p+=2;}proc ch_jnz(ref c:computer,op:byte){    if c.r[0]==0 {        c.p+=2;        return;    }    c.p=op;}proc ch_bxc(ref c:computer,op:byte){    c.r[1]=c.r[1]^c.r[2];    c.p+=2;}proc ch_out(ref c:computer,op:byte){    c.s.pushBack((ch_combo(c,op)&7):byte);    c.p+=2;}proc ch_bdv(ref c:computer,op:byte){    var p=c.r[0];    var q=1<<ch_combo(c,op);    c.r[1]=p/q;    c.p+=2;}proc ch_cdv(ref c:computer,op:byte){    var p=c.r[0];    var q=1<<ch_combo(c,op);    c.r[2]=p/q;    c.p+=2;}proc dorun(ref c:computer){    const dispatch=[ch_adv,ch_bxl,ch_bst,ch_jnz,                    ch_bxc,ch_out,ch_bdv,ch_cdv];    const ch_names=["adv","bxl","bst","jnz",                    "bxc","out","bdv","cdv"];    var running=true;    while running {        var a=c.pr[c.p];        var b=c.pr[c.p+1];        dispatch[a](c,b);        if c.p>=c.pr.size {            running=false;        }    }}proc part1(ref c:computer):bytes {    var p1=b"";    for b in c.s {        if p1.size==0 {            p1+=b:bytes;        } else {            p1+=b","+b:bytes;        }    }    return p1;}proc loud(ref c:computer,d:gene):real {    c.s.clear();    c.r=[d:int,0,0];    c.p=0;    dorun(c);    var r=0.0;    var slen=c.s.size,prlen=c.pr.size;    if slen>prlen {        var di=slen-prlen;        for i in 0..<prlen {            var dx=c.s(i+di):real-c.pr[i]:real;            r+=dx*dx;        }         r+=25.0*di;    } else {        var di=prlen-slen;        for i in 0..<prlen {            var dx:real=c.pr[i+di]:real-c.s(i):real;            r+=dx*dx;        }        r+=25.0*di;    }    return r+d:real*1.0e-14;}record dog {    var b:real,g:gene;}const mu=0.01,bits=50,P=10000;proc genetos(da:gene):bytes {    var d=da,s=b"";    for i in 0..<bits {        var f=d%2;        d>>=1;        if f==1 {            s=b"1"+s;        } else {            if d==0 {                s=b" "+s;            } else {                s=b"0"+s;            }        }    }    return s;}proc part2(ref c:computer):gene {    const mask=1<<bits-1;    const mutations=(mu*bits*P):int;    var tbc=0;    var topbark=max(real),topdog:gene=0,tdix=0;    var dogs:[0..<P]dog;    proc tournament(n:int):(gene,int) {        var lm=max(real),dm:gene=0;        var lM=min(real),iM:int=0;        for j in 0..<n {            var i=(ruint.next()%P):int;            if dogs[i].b<lm {                lm=dogs[i].b;                dm=dogs[i].g;            }            if dogs[i].b>lM {                lM=dogs[i].b;                iM=i;            }        }        return (dm,iM);    }    proc cross(mom,dad:gene):gene {        var cp=(ruint.next()%(bits-1)):int+1;        var m=mask>>cp;        var child=(mom&m)|(dad&~m);        return child;    }    proc mutate(nmut:int) {        for i in 0..<nmut {            var ix=(ruint.next()%P):int;            if ix!=tdix {                var iy=ruint.next()%bits;                var flip:gene=1<<iy;                dogs[ix].g^=flip;                dogs[ix].b=loud(c,dogs[ix].g);            }        }    }    while tbc<25 {        for d in dogs {            d.g=ruint.next()&mask;        }        for i in dogs.domain {            dogs[i].b=loud(c,dogs[i].g);        }        for g in 0..<100 {            topbark=max(real); topdog=0; tdix=0;            for i in dogs.domain {                if dogs[i].b<topbark {                    topbark=dogs[i].b;                    topdog=dogs[i].g;                    tdix=i;                }            }            for i in 0..<2500 {                var (mom,i1)=tournament(5);                var (dad,i2)=tournament(5);                if mom==dad {                    dogs[i1].g=ruint.next()&mask;                    dogs[i2].g=ruint.next()&mask;                } else {                    dogs[i1].g=cross(mom,dad);                    dogs[i2].g=cross(dad,mom);                }                dogs[i1].b=loud(c,dogs[i1].g);                if dogs[i1].b<topbark {                    topbark=dogs[i1].b;                    topdog=dogs[i1].g;                    tdix=i1;                }                dogs[i2].b=loud(c,dogs[i2].g);                if dogs[i2].b<topbark {                    topbark=dogs[i2].b;                    topdog=dogs[i2].g;                    tdix=i2;                }            }            mutate(mutations);            if topbark<2.0 {                tbc+=1;                if tbc>=25 {                    break;                }            }        }    }    return topdog;}proc dowork(){    var io=open("day17.txt",ioMode.r);    var fp=io.reader(locking=false);    var data:list(bytes);    var s:bytes,c:computer;    for m in c.r.domain {        if !fp.readLine(s,stripNewline=true) {            writeln("Can't find Register");            exit(1);        }        c.r[m]=getregister(m,s);    }    if !fp.readLine(s,stripNewline=true) {        writeln("End of file before blank line");        exit(1);    }    if s.size>0 {        writeln("The separator was not blank");        exit(1);    }    if !fp.readLine(s,stripNewline=true) {        writeln("End of file while reading program");        exit(1);    }    var pr=getprogram(s);    c.prdom=pr.domain; c.pr=pr;    dorun(c);    var p1=part1(c);    writeln("Part 1 The output is ",p1);    var p2=part2(c);    writeln("Part 2 The lowest initial value for register A is ",p2);}proc main(){    var t:stopwatch;    t.start();    writeln("Advent of Code 2024 Day 17 Chronospatial Computer\n");    dowork();    t.stop();    writeln("\nTotal execution time ",t.elapsed()," seconds.");}
As a note to the future, after making copies of the computer and dogs data structures the "while tbc<25" loop is the one that could be parallelized.

Statistics: Posted by ejolson — Tue Feb 18, 2025 5:36 am



Viewing all articles
Browse latest Browse all 8082

Trending Articles