首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >杠杆拼图

杠杆拼图
EN

Code Review用户
提问于 2022-06-11 06:21:13
回答 1查看 61关注 0票数 0

我开始玩开拓者:王者,很快就进了一个有6个杠杆的房间,还有一项通过操纵杠杆打开秘密门的任务。我以为所有杠杆的正确位置都是上升的。但是当你转动一个杠杆时,其他一两根杠杆也会翻转。例如,如果你翻转杠杆一,那么杠杆二和四也翻转,当你翻转杠杆二,杠杆一也翻转,等等。

但是你知道吗,编程比玩游戏更有趣,所以让我们弄清楚我们需要用什么样的杠杆来把它们都拉起来!

征求反馈意见:我刚在金刚,什么都行!

代码语言:javascript
复制
package main

import (
    "fmt"
    "strings"
)

type node struct {
    state      int         // a bitmask for every possible levers' configuration, lever one is the least significant bit, 1 is up, 0 is down
    neighbours []int       // all configurations (states, above) that are reachable by flipping a single lever
    levers     map[int]int // lookup that given a neighbour state gives what lever is pulled to reach this state
}

// given levers configuration, print it out in human-readable format
func formatState(state int, width int) string {
    var sb strings.Builder
    for i := 0; i < width; i++ {
        var desc string
        if state&1 == 0 {
            desc = "down"
        } else {
            desc = "up"
        }
        state >>= 1
        sb.WriteString(fmt.Sprintf("%d - %s; ", i+1, desc))
    }
    result := sb.String()
    if len(result) > 2 { // remove final "; "
        result = result[:len(result)-2]
    }
    return result
}

func printSolution(graph []node, prev map[int]int, start, end, width int) {
    path := []int{end}
    for z := end; z != start; z = prev[z] {
        path = append(path, prev[z])
    }
    for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
        path[i], path[j] = path[j], path[i]
    }
    for i := 1; i < len(path); i++ {
        fmt.Printf("Pull lever %d:\n", graph[path[i-1]].levers[path[i]]+1)
        fmt.Println(formatState(path[i], width))
    }
}

// Simplified Dijkstra's algorithm
// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm#Pseudocode
func search(graph []node, start, end int) map[int]int {
    q := []int{start}
    prev := map[int]int{}
    dist := map[int]int{}
    for len(q) > 0 {
        u := q[0]
        q = q[1:]
        if u == end {
            return prev
        }
        for _, v := range graph[u].neighbours {
            alt := dist[u] + 1
            if i, ok := dist[v]; !ok || alt < i {
                prev[v] = u
                dist[v] = alt
                q = append(q, v)
            }
        }
    }
    return nil
}

func initGraph(levers []int) []node {
    var graph = make([]node, 1<<len(levers))
    for i := 0; i < len(graph); i++ {
        graph[i].state = i
        graph[i].levers = make(map[int]int)
        for j := 0; j < len(levers); j++ {
            n := i ^ levers[j]
            graph[i].neighbours = append(graph[i].neighbours, n)
            graph[i].levers[n] = j
        }
    }
    return graph
}

func main() {
    // This can come from an external input, but let's not overcomplicate:
    var levers = []int{
        0b001011, // lever one flips levers one, two and four
        0b000011, // lever two flips levers one, and two
        0b100100, // lever three flips levers three, two and six
        0b011001, // lever four flips levers one, four and five
        0b111000, // lever five flips levers four, five and six
        0b110100, // lever six flips levers three, five and six
    }
    width := len(levers)
    graph := initGraph(levers)
    start := 0b011111
    end := 0b111111
    fmt.Printf("Starting poisition:\n%s\n", formatState(start, width))
    fmt.Printf("Goal poisition:\n%s\n", formatState(end, width))
    prev := search(graph, start, end)
    if prev != nil {
        printSolution(graph, prev, start, end, width)
    } else {
        fmt.Println("Solution not found")
    }
}

程序输出:

代码语言:javascript
复制
Starting poisition:
1 - up; 2 - up; 3 - up; 4 - up; 5 - up; 6 - down
Goal poisition:
1 - up; 2 - up; 3 - up; 4 - up; 5 - up; 6 - up
Pull lever 1:
1 - down; 2 - down; 3 - up; 4 - down; 5 - up; 6 - down
Pull lever 2:
1 - up; 2 - up; 3 - up; 4 - down; 5 - up; 6 - down
Pull lever 3:
1 - up; 2 - up; 3 - down; 4 - down; 5 - up; 6 - up
Pull lever 5:
1 - up; 2 - up; 3 - down; 4 - up; 5 - down; 6 - down
Pull lever 6:
1 - up; 2 - up; 3 - up; 4 - up; 5 - up; 6 - up
EN

回答 1

Code Review用户

发布于 2022-06-13 08:45:10

代码语言:javascript
复制
prev := map[int]int{}

使用var和make (而不是空映射的简写声明)可能更符合习惯吗?您通常会使用速记声明来分配初始值,并使用var初始化为零值。

你这样做是在initGraph。在您的代码中保持这一点的一致性可能会更好。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/277257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档