Nice. Software developer, gamer, occasionally 3d printing, coffee lover.

  • 0 Posts
  • 115 Comments
Joined 2 years ago
cake
Cake day: July 1st, 2023

help-circle

  • You’re right. And my library aversion definitely made it harder. I think the day I learned the most was day 19, the towel one. Seemed simple at first but I just couldn’t wrap my mind around it, looked at a few solutions and one of the dynamic programming one solutions just blew my mind. Took me an hour or so to just wrap my head around it and then once I understood it I was able to write that abomination I posted from scratch (well, without needing to reference what I studied).



  • Javascript

    Spent 10 minutes debugging my solution until I reread and found out they wanted the number of keys that fit, not the ones that overlapped. Reading comprehension is not it tonight.

    const [locks, keys] = require('fs').readFileSync(0, 'utf-8').split(/\r?\n\r?\n/g).filter(v => v.length > 0).map(s => s.split(/\r?\n/g).filter(v => v.length > 0)).reduce((acc, s) => {
        const lock = s[0].split('').every(v => v === '#');
        const schema = s.slice(1, -1);
        let rotated = [];
        for (let i = 0; i < schema[0].length; i += 1) {
            for (let j = 0; j < schema.length; j += 1) {
                if (!rotated[i]) rotated[i] = [];
                rotated[i].push(schema[j][i]);
            }
        }
        if (!lock) {
            rotated = rotated.map(v => v.reverse());
        }
        const pinHeights = [];
        for (const row of rotated) {
            const height = row.indexOf('.');
            pinHeights.push(height !== -1 ? height : 5);
        }
        if (lock) {
            acc[0].push(pinHeights);
        } else {
            acc[1].push(pinHeights);
        }
        return acc;
    }, [[],[]]);
    
    let fits = 0;
    for (const lock of locks) {
        for (const key of keys) {
            let overlapped = false;
            for (let i = 0; i < lock.length; i += 1) {
                if ((lock[i] + key[i]) > 5) {
                    overlapped = true;
                }
            }
            if (!overlapped) {
                fits += 1;
            }
        }
    }
    
    console.log('Part One', fits);
    

  • Javascript

    Part one was easy, though despite starting at midnight I only placed 1786 for part one. I think my tendency to want to do OOP makes it take longer…

    Part two… Well, I figured it was some sort of binary circuit for trying to add binary numbers. So I hoped that the sum of the x registers and the y registers was the expected result of simulating the circuit like in part one. I later verified that it is the expected result.

    I didn’t want to try and manually figure out the bad outputs, coffee wasn’t helping, I wanted sleep. So I uh… I wrote logic to randomly create swaps. And then just hoped RNG got me covered. To help my chances, I ran it on 8 different processes.

    When I woke up in the morning I discovered 8 stopped processes, each with “a solution” that was different. Turns out, if you just randomly swap wires at some point you get a system that outputs the desired result - but only because you sufficiently screwed it up more to produce the expected result, even if the system itself would not work for other input.

    I could probably change the registers to another value, run it, and see if they match, thus ruling out an incorrect set of swaps causing a correct result with the original binary inputs. But at this point I just decided to do it the manual way following advice on here. My brain is fried, I’m stepping away to take a shower and get ready to visit family.

    I had really hoped the bruteforce would work, I modified the bruteforce to run even after it finds a match and I’ll let it run while I’m gone today and see if RNG produces any correct result at some point - I just fear the exponential answer timeout will prevent me from submitting these correctly incorrect combinations lol. I might modify it later with my theory above and just run it on a server indefinitely and see if it produces the correct result eventually.

    https://blocks.programming.dev/Zikeji/9e4d6e81595d4845b88cf98eb91852d8

    Edit:

    Created a raw multithreaded bruteforce variant: topaz


  • Go

    Re-familiarizing myself with Go. The solution to Part 2 is fairly simply, the whole packing of the sequence into a single integer to save on memory was an optimization I did afterwards based on looking at other solutions. I thought it was cool.

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    	"strconv"
    )
    
    type SequenceMap struct {
    	Data map[int32]int
    }
    
    func PackSeq(numbers [4]int8) int32 {
    	var packed int32
    	for i, num := range numbers {
    		packed |= int32(num+9) << (i * 5)
    	}
    	return packed
    }
    
    func UnpackSeq(packed int32) [4]int8 {
    	var numbers [4]int8
    	for i := range numbers {
    		numbers[i] = int8((packed>>(i*5))&0x1F) - 9
    	}
    	return numbers
    }
    
    func NewSequenceMap() SequenceMap {
    	return SequenceMap{make(map[int32]int)}
    }
    
    func (m *SequenceMap) Increment(seq [4]int8, val int) {
    	pSeq := PackSeq(seq)
    	acc, ok := m.Data[pSeq]
    	if ok {
    		m.Data[pSeq] = acc + val
    	} else {
    		m.Data[pSeq] = val
    	}
    }
    
    func (m *SequenceMap) Has(seq [4]int8) bool {
    	pSeq := PackSeq(seq)
    	_, ok := m.Data[pSeq]
    	return ok
    }
    
    type Generator struct {
    	Secret         int64
    	LastPrice      int8
    	ChangeSequence []int8
    }
    
    func NewGenerator(Secret int64) Generator {
    	var ChangeSequence []int8
    	return Generator{Secret, int8(Secret % 10), ChangeSequence}
    }
    
    func (g *Generator) Mix(value int64) *Generator {
    	g.Secret = g.Secret ^ value
    	return g
    }
    
    func (g *Generator) Prune() *Generator {
    	g.Secret = g.Secret % 16777216
    	return g
    }
    
    func (g *Generator) Next() {
    	g.Mix(g.Secret * 64).Prune().Mix(g.Secret / 32).Prune().Mix(g.Secret * 2048).Prune()
    	Price := int8(g.Secret % 10)
    	g.ChangeSequence = append(g.ChangeSequence, Price-g.LastPrice)
    	g.LastPrice = Price
    	if len(g.ChangeSequence) > 4 {
    		g.ChangeSequence = g.ChangeSequence[1:]
    	}
    }
    
    func ParseInput() []int64 {
    	if fileInfo, _ := os.Stdin.Stat(); (fileInfo.Mode() & os.ModeCharDevice) != 0 {
    		fmt.Println("This program expects input from stdin.")
    		os.Exit(1)
    	}
    	scanner := bufio.NewScanner(os.Stdin)
    
    	var numbers []int64
    	for scanner.Scan() {
    		line := scanner.Text()
    		num, err := strconv.ParseInt(line, 10, 64)
    		if err != nil {
    			fmt.Printf("ERROR PARSING VALUE: %s\n", line)
    			os.Exit(1)
    		}
    		numbers = append(numbers, num)
    	}
    
    	return numbers
    }
    
    func main() {
    	numbers := ParseInput()
    
    	m := NewSequenceMap()
    	sum := int64(0)
    
    	for i := 0; i < len(numbers); i += 1 {
    		g := NewGenerator(numbers[i])
    		tM := NewSequenceMap()
    		for j := 0; j < 2000; j += 1 {
    			g.Next()
    			if len(g.ChangeSequence) == 4 {
    				if !tM.Has([4]int8(g.ChangeSequence)) {
    					tM.Increment([4]int8(g.ChangeSequence), 1)
    					if g.LastPrice > 0 {
    						m.Increment([4]int8(g.ChangeSequence), int(g.LastPrice))
    					}
    				}
    			}
    		}
    		sum += g.Secret
    	}
    
    	fmt.Printf("Part One: %d\n", sum)
    
    	var bestSeq [4]int8
    	bestPrice := 0
    	for pSeq, price := range m.Data {
    		if price > bestPrice {
    			bestPrice = price
    			bestSeq = UnpackSeq(pSeq)
    		}
    	}
    
    	fmt.Printf("Part Two: %d\n", bestPrice)
    	fmt.Printf("Best Sequence: %d\n", bestSeq)
    }
    

  • Javascript

    Behold an abomination!

    const input = require('fs').readFileSync(0, 'utf-8').toString();
    const towels = new Set(input.split(/\r?\n\r?\n/g)[0].split(', '));
    const count = (p, t) => [...new Array(p.length).keys()].reduce((acc, i) => [...new Array(i + 1).keys()].forEach(j => acc[j] > 0n && t.has(p.substring(j, i + 1)) ? acc[i + 1] += acc[j] : null) ? acc : acc, [1n, ...new Array(p.length).fill(0n)])[p.length];
    input.split(/\r?\n\r?\n/g)[1].split(/\r?\n/g).filter(p => p.length > 0).reduce((acc, p) => { let c = count(p, towels); acc[0] += c > 0 ? 1 : 0; acc[1] += c; return acc }, [0, 0n]).forEach((v, i) => console.log(`Part ${i+1}: ${v}`));
    


  • Javascript

    So my friend tells me my solution is close to Dijkstra but honestly I just tried what made sense until it worked. I originally wanted to just bruteforce it and get every single possible path explored but uh… Yeah that wasn’t gonna work, I terminated that one after 1B operations.

    I created a class to store the state of the current path being explored, and basically just clone it, sending it in each direction (forward, 90 degrees, -90 degrees), then queue it up if it didn’t fail. Using a priority queue (array based) to store them, I inverted it for the second answer to reduce the memory footprint (though ultimately once I fixed the issue with the algorithm, which turned out to just be a less than or equal to that should have been a less than, I didn’t really need this).

    Part two “only” took 45 seconds to run on my Thinkpad P14 Gen1.

    My code was too powerful for Lemmy (or verbose): https://blocks.programming.dev/Zikeji/ae06ca1ca88649c99581eefce97a708e




  • I’ve had bad tinkering break my system before, but never had an update break it irreversibly. The closest would actually be on Silverblue itself, when an update to the kernel was using different signing keys that cause the system not to boot. Fortunately it was simple, I selected the previous deployment and I was in (on a non versioned OS I would have selected the previous kernel which most are configured to retain the last few). A quick Google revealed Ublue had a whole kerfuffle and after verifying it was legit, I enrolled the new certs into my MOK.

    Although one time on Arch I had installed an experimental version of Gnome from one of their repos, and was pleasantly surprised when that version finally released and I removed the experiment repo and did an update absolutely nothing at all broke. Nothing.


  • Zikeji@programming.devtoLinux@lemmy.mlVPS encryption
    link
    fedilink
    English
    arrow-up
    5
    ·
    9 months ago

    LUKS, or anything that relies on the server encrypting, is highly vulnerable (see schizo@forum.uncomfortable.business’s response).

    Your best bet would be encrypting client side before it arrives on the server using a solution like rclone, restic, borg, etc.







  • The article that user links is referring to GrapheneOS (and other OSS software) as not being “free software” - and they (GNU) delves into it more here.

    Basically, GNU is saying software shouldn’t claim to be free and open source if they contain non free binaries / other non-free blobs.

    The nuances between FOSS and OSS can be confusing. GrapheneOS is not claiming to be FOSS.