[-] kartoffelsaft@programming.dev 2 points 2 weeks ago

Damn you, Sonic the Hedgehog!

[-] kartoffelsaft@programming.dev 2 points 1 month ago

~~Yeah I'm on voyager too and home stopped working for me at the same time as this hidden community issue. Home and All are literally the same feed now. Curious if these issues are related.~~

Lol it refused to post this reply until I logged out then back in, whereupon the issue was fixed. Guess that answers that.

[-] kartoffelsaft@programming.dev 4 points 2 months ago

I live in Washington state and I'm pretty certain the sales tax here is 10% (slightly higher than your maximum figure of 9.56%). It's a pretty well known trick here that you can account for tax just by decimal shifting and adding (ex: 5.29$ without would be 5.29$ + 0.529$ ~= 5.81$ with tax). Is that 9.56% an "in practice" figure that accounts for rounding down? I'm curious where you read it.

[-] kartoffelsaft@programming.dev 4 points 2 months ago

I agree pretty strongly with this generally. The farside has a way of having jokes that are so simple on it's face that I'm left thinking "surely I've missed something?" Usually it turns out that no, in fact, I got the joke and was just vastly underwhelmed.

For whatever reason I found this one to be mildly funny. Couldn't tell you why. Perhaps it's the idea that the people who built the atomic bomb weren't that smart after all?

[-] kartoffelsaft@programming.dev 5 points 3 months ago

I honestly assumed I was colorblind in one eye (I am diagnosed, at least)

[-] kartoffelsaft@programming.dev 2 points 4 months ago

Surprised TOEM isn't on your list, given the premise is pretty much exactly what you describe. Last I checked it comes up on the first page or something if you sort steam by highest rated.

Lunacid might also be a good game. I think it fits your criteria for me, but that might just be for me.

[-] kartoffelsaft@programming.dev 4 points 11 months ago* (last edited 11 months ago)

Odin

When I read the problem description I expected the input to also be 2 digit numbers. When I looked at it I just had to say "huh."

Second part I think you definitely have to do in reverse (edit: if you are doing a linear search for the answer), as that allows you to nope out as soon as you find a match, whereas with doing it forward you have to keep checking just in case.

Formatted code

package day5

import "core:fmt"
import "core:strings"
import "core:slice"
import "core:strconv"

Range :: struct {
    dest: int,
    src: int,
    range: int,
}

Mapper :: struct {
    ranges: []Range,
}

parse_range :: proc(s: string) -> (ret: Range) {
    rest := s

    parseLen := -1

    destOk: bool
    ret.dest, destOk = strconv.parse_int(rest, 10, &parseLen)
    rest = strings.trim_left_space(rest[parseLen:])

    srcOk: bool
    ret.src, srcOk = strconv.parse_int(rest, 10, &parseLen)
    rest = strings.trim_left_space(rest[parseLen:])

    rangeOk: bool
    ret.range, rangeOk = strconv.parse_int(rest, 10, &parseLen)

    return
}

parse_mapper :: proc(ss: []string) -> (ret: Mapper) {
    ret.ranges = make([]Range, len(ss)-1)
    for s, i in ss[1:] {
        ret.ranges[i] = parse_range(s)
    }

    return
}

parse_mappers :: proc(ss: []string) -> []Mapper {
    mapsStr := make([dynamic][]string)
    defer delete(mapsStr)

    restOfLines := ss
    isLineEmpty :: proc(s: string)->bool {return len(s)==0}

    for i, found := slice.linear_search_proc(restOfLines, isLineEmpty); 
        found; 
        i, found  = slice.linear_search_proc(restOfLines, isLineEmpty) {
        
        append(&mapsStr, restOfLines[:i])
        restOfLines = restOfLines[i+1:]
    }
    append(&mapsStr, restOfLines[:])

    return slice.mapper(mapsStr[1:], parse_mapper)
}

apply_mapper :: proc(mapper: Mapper, num: int) -> int {
    for r in mapper.ranges {
        if num >= r.src && num - r.src < r.range do return num - r.src + r.dest
    }

    return num
}

p1 :: proc(input: []string) {
    maps := parse_mappers(input)
    defer {
        for m in maps do delete(m.ranges)
        delete(maps)
    }

    restSeeds := input[0][len("seeds: "):]
    min := 0x7fffffff

    for len(restSeeds) > 0 {
        seedLen := -1
        seed, seedOk := strconv.parse_int(restSeeds, 10, &seedLen)
        restSeeds = strings.trim_left_space(restSeeds[seedLen:])

        fmt.print(seed)
        for m in maps {
            seed = apply_mapper(m, seed)
            fmt.print(" ->", seed)
        }
        fmt.println()

        if seed < min do min = seed
    }

    fmt.println(min)
}

apply_mapper_reverse :: proc(mapper: Mapper, num: int) -> int {
    for r in mapper.ranges {
        if num >= r.dest && num - r.dest < r.range do return num - r.dest + r.src
    }

    return num
}

p2 :: proc(input: []string) {
    SeedRange :: struct {
        start: int,
        len: int,
    }

    seeds := make([dynamic]SeedRange)
    restSeeds := input[0][len("seeds: "):]

    for len(restSeeds) > 0 {
        seedLen := -1
        seedS, seedSOk := strconv.parse_int(restSeeds, 10, &seedLen)
        restSeeds = strings.trim_left_space(restSeeds[seedLen:])

        seedL, seedLOk := strconv.parse_int(restSeeds, 10, &seedLen)
        restSeeds = strings.trim_left_space(restSeeds[seedLen:])

        append(&seeds, SeedRange{seedS, seedL})
    }

    maps := parse_mappers(input)
    defer {
        for m in maps do delete(m.ranges)
        delete(maps)
    }

    for i := 0; true; i += 1 {
        rseed := i
        #reverse for m in maps {
            rseed = apply_mapper_reverse(m, rseed)
        }

        found := false
        for sr in seeds {
            if rseed >= sr.start && rseed < sr.start + sr.len {
                found = true
                break
            }
        }
        if found {
            fmt.println(i)
            break
        }
    }
}
[-] kartoffelsaft@programming.dev 3 points 11 months ago

Did mine in Odin. Found this day's to be super easy, most of the challenge was just parsing.

package day2

import "core:fmt"
import "core:strings"
import "core:strconv"
import "core:unicode"

Round :: struct {
    red: int,
    green: int,
    blue: int,
}

parse_round :: proc(s: string) -> Round {
    ret: Round

    rest := s
    for {
        nextNumAt := strings.index_proc(rest, unicode.is_digit)
        if nextNumAt == -1 do break
        rest = rest[nextNumAt:]

        numlen: int
        num, ok := strconv.parse_int(rest, 10, &numlen)
        rest = rest[numlen+len(" "):]

        if rest[:3] == "red" {
            ret.red = num
        } else if rest[:4] == "blue" {
            ret.blue = num
        } else if rest[:5] == "green" {
            ret.green = num
        }
    }

    return ret
}

Game :: struct {
    id: int,
    rounds: [dynamic]Round,
}

parse_game :: proc(s: string) -> Game {
    ret: Game

    rest := s[len("Game "):]

    idOk: bool
    idLen: int
    ret.id, idOk = strconv.parse_int(rest, 10, &idLen)
    rest = rest[idLen+len(": "):]

    for len(rest) > 0 {
        endOfRound := strings.index_rune(rest, ';')
        if endOfRound == -1 do endOfRound = len(rest)

        append(&ret.rounds, parse_round(rest[:endOfRound]))
        rest = rest[min(endOfRound+1, len(rest)):]
    }

    return ret
}

is_game_possible :: proc(game: Game) -> bool {
    for round in game.rounds {
        if round.red   > 12 ||
           round.green > 13 ||
           round.blue  > 14 {
            return false
        }
    }
    return true
}

p1 :: proc(input: []string) {
    totalIds := 0

    for line in input {
        game := parse_game(line)
        defer delete(game.rounds)

        if is_game_possible(game) do totalIds += game.id
    }

    fmt.println(totalIds)
}

p2 :: proc(input: []string) {
    totalPower := 0

    for line in input {
        game := parse_game(line)
        defer delete(game.rounds)

        minRed   := 0
        minGreen := 0
        minBlue  := 0
        for round in game.rounds {
            minRed   = max(minRed  , round.red  )
            minGreen = max(minGreen, round.green)
            minBlue  = max(minBlue , round.blue )
        }

        totalPower += minRed * minGreen * minBlue
    }

    fmt.println(totalPower)
}
[-] kartoffelsaft@programming.dev 2 points 11 months ago

Did this in Odin (very hashed together, especially finding the last number in part 2):

spoiler

package day1

import "core:fmt"
import "core:strings"
import "core:strconv"
import "core:unicode"

p1 :: proc(input: []string) {
    total := 0

    for line in input {
        firstNum := line[strings.index_proc(line, unicode.is_digit):][:1]
        lastNum := line[strings.last_index_proc(line, unicode.is_digit):][:1]

        calibrationValue := strings.concatenate({firstNum, lastNum})
        defer delete(calibrationValue)

        num, ok := strconv.parse_int(calibrationValue)

        total += num
    }

    // daggonit thought it was the whole numbers
    /*
    for line in input {
        firstNum := line

        fFrom := strings.index_proc(firstNum, unicode.is_digit)
        firstNum = firstNum[fFrom:]

        fTo := strings.index_proc(firstNum, proc(r:rune)->bool {return !unicode.is_digit(r)})
        if fTo == -1 do fTo = len(firstNum)
        firstNum = firstNum[:fTo]


        lastNum := line
        lastNum = lastNum[:strings.last_index_proc(lastNum, unicode.is_digit)+1]
        lastNum = lastNum[strings.last_index_proc(lastNum, proc(r:rune)->bool {return !unicode.is_digit(r)})+1:]

        calibrationValue := strings.concatenate({firstNum, lastNum})
        defer delete(calibrationValue)

        num, ok := strconv.parse_int(calibrationValue, 10)
        if !ok {
            fmt.eprintf("%s could not be parsed from %s", calibrationValue, line)
            return
        }

        total += num;
    }
    */

    fmt.println(total)
}

p2 :: proc(input: []string) {
    parse_wordable :: proc(s: string) -> int {
        if len(s) == 1 {
            num, ok := strconv.parse_int(s)
            return num
        } else do switch s {
            case "one"  : return 1
            case "two"  : return 2
            case "three": return 3
            case "four" : return 4
            case "five" : return 5
            case "six"  : return 6
            case "seven": return 7
            case "eight": return 8
            case "nine" : return 9
        }

        return -1
    }

    total := 0

    for line in input {
        firstNumI, firstNumW := strings.index_multi(line, {
            "one"  , "1",
            "two"  , "2",
            "three", "3",
            "four" , "4",
            "five" , "5",
            "six"  , "6",
            "seven", "7",
            "eight", "8",
            "nine" , "9",
        })
        firstNum := line[firstNumI:][:firstNumW]


        // last_index_multi doesn't seem to exist, doing this as backup
        lastNumI, lastNumW := -1, -1
        for {
            nLastNumI, nLastNumW := strings.index_multi(line[lastNumI+1:], {
                "one"  , "1",
                "two"  , "2",
                "three", "3",
                "four" , "4",
                "five" , "5",
                "six"  , "6",
                "seven", "7",
                "eight", "8",
                "nine" , "9",
            })

            if nLastNumI == -1 do break

            lastNumI += nLastNumI+1
            lastNumW  = nLastNumW
        }
        lastNum := line[lastNumI:][:lastNumW]

        total += parse_wordable(firstNum)*10 + parse_wordable(lastNum)
    }

    fmt.println(total)
}

Had a ton of trouble with part 1 until I realized I misinterpreted it. Especially annoying because the example was working fine. So paradoxically part 2 was easier than 1.

[-] kartoffelsaft@programming.dev 4 points 1 year ago

I don't think this can really be answered until after the fact. Anything that I (and I suspect most) people could say about an artstyle are going to be particular to an instance of that artsyle. If I'd give advice as someone who is neither an artist nor a game designer, what attracts me more than anything is a unique artstyle, which, if I'm gonna give a brutal opinion, starting from a vague category like 'pixel', 'hand drawn' or '3D' probably won't get you there.

I feel like I even struggle to answer your question at face value because it doesn't align well at all with how I conceptualize game art. For example, Cruelty Squad is a game that I don't think I'd have gotten if not for it's artsyle. Like, sure, it's 3D, but it's a lot more like a PilotRedSun animation than it is a game like TF2. Or take a game like Factorio: most of the assets of that game are pre-rendered 3D sprites, so despite being artisticly unique in a way that interests me it doesn't fit into the categories you've asked about. The best I can say is "I dunno", and I don't think anyone else can answer it further than that.

[-] kartoffelsaft@programming.dev 5 points 1 year ago* (last edited 1 year ago)

There is the Anno series of games, which are technically RTS games but if I'm honest I find them the most fun when I go out of my way to avoid combat/micromanagement. I've only played 1404, 2070, and 2205, 2070 being the best in my opinion, but it has a bad history with DRM so I'd suggest 1404 (known as "Dawn of Discovery" in the US because us americans are afraid of numbers apparently).

Edit: looking at the steam page it looks like they decided to take 1404 down and made a new page where the game is (mostly) unchanged besides requiring you to jump through all the BS hoops that 2070 did, so I'd say if you're gonna spend money get 1404 on GOG, or if you are willing to do unspeakable things go with 2070.

[-] kartoffelsaft@programming.dev 5 points 1 year ago

It's a setting you can change. The default is a "quick generation" mode which looks as similar to the world seed/settings as it can without taking the performance hit of actually generating it. But it can either be changed to generate the chunks genuinely out to the render distance (which would be lag hell for 128 chunks) or to only render already generated chunks (like you suspect). Only the latter works in multiplayer though.

view more: โ€น prev next โ€บ

kartoffelsaft

joined 1 year ago