이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

rikudo게임

rikudo라는 게임입니다.
1부터 36까지 순서대로 이어지도록 숫자를 채우세요.

input:
------24--00--00--00------
----00--00--26--36--00----
--00--21--00--00--28--32--
18--00--15------00--00--00
--00--00--00--08--01--00--
----00--10--00--00--03----
------12--00--00--05------

output:
------24--25--35--34------
----20--23--26--36--33----
--19--21--22--27--28--32--
18--16--15------29--30--31
--17--14--09--08--01--02--
----13--10--07--04--03----
------12--11--06--05------
재귀 트랙백 미로

2018/07/27 16:36

박범수

+1 http://www.rikudo-puzzle.com/ - Noname, 2018/07/28 19:23
링크 감사합니다:) - 박범수, 2018/07/30 08:02

7개의 풀이가 있습니다.

class rikudo:
    def __init__(self,data):
        self.board = [ [ int(i[j:j+2]) if i[j:j+2].isdigit() else i[j:j+2] for j,k in enumerate(i) if not j&1 ] for i in data.split('\n') ]
        self.row, self.clm = len(self.board), len(self.board[0])
        self.nums = { self.board[i][j]:(i,j) for i in range(self.row)
                                             for j in range(self.clm) if self.board[i][j] not in (0,'--') }

    def answer(self):
        flag = False
        stc,stc2,cun = [self.nums[1]],[0],1

        nib = ( (0,2),(1,1),(1,-1),(0,-2),(-1,-1),(-1,1) )

        while cun < 36:
            if cun+1 in self.nums:
                if (self.nums[cun+1][0]-stc[-1][0], self.nums[cun+1][1]-stc[-1][1]) in nib:
                    stc.append(self.nums[cun+1])
                    stc2.append(0)
                    cun += 1
                    continue
                else: stc.pop(); stc2.pop(); cun -= 1; continue

            while 1:
                if stc2[-1] == 6: flag = True; break
                dx,dy = nib[stc2[-1]]
                stc2[-1] += 1
                if 0<=stc[-1][0]+dx<self.row and 0<=stc[-1][1]+dy<self.clm and self.board[stc[-1][0]+dx][stc[-1][1]+dy] == 0 and (stc[-1][0]+dx,stc[-1][1]+dy) not in stc: break

            if flag: flag=False; stc.pop(); stc2.pop(); cun -= 1; continue

            stc.append((stc[-1][0]+dx,stc[-1][1]+dy))
            stc2.append(0)
            cun += 1
        return stc

    def print_ans(self):
        for i,j in enumerate(self.answer()): self.board[j[0]][j[1]] = i+1
        for i in range(self.row):
            for j in range(self.clm):
                print('{:0>2}'.format(self.board[i][j]),end='')
            print()


sample = '''\
------24--00--00--00------
----00--00--26--36--00----
--00--21--00--00--28--32--
18--00--15------00--00--00
--00--00--00--08--01--00--
----00--10--00--00--03----
------12--00--00--05------'''

x = rikudo(sample)
x.print_ans()

------24--25--35--34------
----20--23--26--36--33----
--19--21--22--27--28--32--
18--16--15------29--30--31
--17--14--09--08--01--02--
----13--10--07--04--03----
------12--11--06--05------

2018/07/28 01:21

Creator

Python

1) 주어진 예에서 처음에 보드에 적혀 있는 수들을 정렬하면 [1, 3, 5, 8, 10, 12, 15, 18, 21, 24, 26, 28, 32, 36] 인데,

여기서 가장 차이가 작은 수 두 개를 찾습니다: closest_nums()

그래서 제일 먼저 찾는 게 [1, 3], 즉 1과 3이 가장 가까우니 먼저 연결해 보겠다는 뜻. (이 과정에서, 이미 앞뒤로 연결된 수는 볼 필요가 없으므로 제외합니다).

2) 가장 가까운 두 수 [1, 3]을 찾았으니 이제 1~~>3 경로들을 찾습니다: find_paths() => [경로1, 경로2, ...]

1~~>3은 2개의 경로가 존재하는데, 찾은 경로들을 각각 그려본 후(draw()) 백트래킹을 사용하면서(erase()) 1)과 2)를 반복합니다.

1~~>3 다음에는

[1, 2, 3, 5, 8, 10, 12, 15, 18, 21, 24, 26, 28, 32, 36]

이렇게 되니까 3~~>5, 8~~>10, 10~~>12, 24~~>26, 26~~>28 순서로 찾게 됩니다.

class Rikudo:
    brd, inv_brd, size = {}, {}, 0

    def __init__(self, data):
        # arr <- 2차원 배열(data)
        arr = [[int(s) for s in row.split('-') if s.isdigit()] for row in data.split('\n')]
        arr[len(arr) // 2].insert(len(arr) // 2, -1)  # 가운데 안 쓰는 한 칸
        self.size = len(arr)

        # self.brd <- {(i, j):숫자, ... }
        for i in range(len(arr)):
            for j in range(len(arr[i])):
                if arr[i][j] >= 0:
                    self.brd[(i, j)] = arr[i][j]

        # inv_brd <- {숫자:(i, j), ... }, brd 와 inv_brd는 동기화되어야 함
        self.inv_brd = {v : k for k, v in self.brd.items() if v > 0}

    def closest_nums(self):
        nums = sorted(self.inv_brd.keys())  # 현재 보드에 적힌 숫자들을 정렬
        return min(
                    [[ x[0], x[1], x[1] - x[0] ] for x in zip(nums[:-1], nums[1:]) if x[1] - x[0] > 1],
                    key = lambda x:x[2]
                )[:2]   # 연속하지 않으면서 간격이 최소인 [nums[i], nums[i+1]을 리턴

    # 좌표 cbase와 인접하면서 유효한 좌표들을 리턴
    def adjacent(self, cbase, dest):
        def writable(c): return c == dest or c in self.brd.keys() and self.brd[c] == 0
        x, y = cbase
        if x < self.size // 2:    result = {(x, y-1), (x, y+1), (x-1, y-1), (x-1, y), (x+1, y), (x+1, y+1)}
        elif x > self.size // 2:  result = {(x, y-1), (x, y+1), (x-1, y), (x-1, y+1), (x+1, y-1), (x+1, y)}
        else:                      result = {(x, y-1), (x, y+1), (x-1, y-1), (x-1, y), (x+1, y-1), (x+1, y)}

        return {c for c in result if writable(c)}

    # path[-1]에서 dest에 이르는 길이 plen인 경로를 찾는다.(recursion)
    def find_paths(self, path, plen, dest):
        if plen == 0:
            return [path] if (path[-1] == dest) else []
        else:
            result = []
            for c in self.adjacent(path[-1], dest) - set(path):  # 지나온 경로 제외
                result += self.find_paths(path + [c], plen - 1, dest)

            return result

    def draw(self, path):
        n = self.brd[path[0]]
        for c in path[1:-1]:
            n += 1
            self.brd[c] = n
            self.inv_brd[n] = c

    def erase(self, path):
        n = self.brd[path[0]]
        for c in path[1:-1]:
            n += 1
            self.brd[c] = 0
            del self.inv_brd[n]

    def print_n_exit(self):
        arr = [['--' for y in range(self.size)] for x in range(self.size)]
        for x, y in self.brd.keys():
            arr[x][y] = "%02d--" % self.brd[(x, y)]

        output = ''
        for x in range(self.size):
            if x == self.size // 2:
                tmp = ''.join(arr[x])[:-2]
                output += tmp[:self.size * 2] + '--' + tmp[self.size * 2:]  + '\n'
            else:
                output += '--' * arr[x].count('--') + ''.join(arr[x][:-1]) + '\n'
        print(output)
        exit()

    def solve(self):
        if 0 not in self.brd.values():
            self.print_n_exit()
        else:
            n1, n2 = self.closest_nums()
            paths = self.find_paths([self.inv_brd[n1]], n2 - n1, self.inv_brd[n2])
            for path in paths:
                self.draw(path)
                self.solve()
                self.erase(path)

data = "------24--00--00--00------\n----00--00--26--36--00----\n--00--21--00--00--28--32--\n18--00--15------00--00--00\n--00--00--00--08--01--00--\n----00--10--00--00--03----\n------12--00--00--05------"
game = Rikudo(data)
game.solve()

2018/07/29 04:45

Noname

import string
import re
import random
inputdata='''------24--00--00--00------
----00--00--26--36--00----
--00--21--00--00--28--32--
18--00--15------00--00--00
--00--00--00--08--01--00--
----00--10--00--00--03----
------12--00--00--05------'''

MAX=36
OUTnumbers=list(range(1,MAX+1))
INnumbers=[]
row=re.split('\n',inputdata)
datalen=len(row)

data=[]
lenlist=[]
for i in range(datalen):
    temp=[int(x) for x in re.split('[\-]+',row[i]) if x] #split rowdata
    data.append(temp)
    lenlist.append(len(data[i])) #datalength vector

##insert 'c' at enter
mid=int(datalen/2)
data[mid].insert(mid,0)
lenlist[mid]=lenlist[mid]+1

##make Axial coordinates
##https://www.redblobgames.com/grids/hexagons/
xy_to_axial={}
axial_to_xy={}
numbers_dic={}
for i in range(datalen):
    for j in range(lenlist[i]):
        xy_to_axial[(i,j)]=(-min(i,3)+j,i-mid)
        axial_to_xy[(-min(i,3)+j,i-mid)]=(i,j)
        if data[i][j]!=0:
            OUTnumbers.remove(data[i][j])
            INnumbers.append(data[i][j])
            numbers_dic[data[i][j]]=(i,j)
INnumbers.sort()

def nearindex(index,dest):
    # input : axial_coord output :  axial_coord
    # 빈칸이나 dest의 인덱스를 반환합니다.
    _near_indice=[]
    (q,r)=index
    for offset_q,offset_r in [(0,1),(1,0),(1,-1),(0,-1),(-1,0),(-1,1)]:
        index_new=(q+offset_q,r+offset_r)
        if (index_new in axial_to_xy) and (index_new!=(0,0)):
            _i,_j=axial_to_xy[index_new]
            if ((data[_i][_j]==0) or (index_new==dest)):
                _near_indice.append((q+offset_q,r+offset_r))
    return _near_indice


def location(num):
    #return xy cord
    index=()
    for i in range(datalen):
        if num in data[i]:
            index=(i,data[i].index(num))
    try:
        return xy_to_axial[index]
    except:
        return ()

def find_routes(route,plen,dest):
    if plen == 0:
        return [route] if (route[-1] == dest) else []
    else:
        result = []
        for c in set(nearindex(route[-1],dest)):
            result += find_routes(route + [c], plen - 1, dest)
        return result


def draw(route):
    (i,j)=axial_to_xy[route[0]]
    n=data[i][j]
    for c in route[1:-1]:
        n += 1
        (i,j)=axial_to_xy[c]
        if (not data[i][j]) and (location(n)==()):
            data[i][j] = n
def erase(route):
    (_i,_j)=axial_to_xy[route[0]]
    for c in route[1:-1]:
        (_i,_j)=axial_to_xy[c]
        if (data[_i][_j]) and (data[_i][_j] not in INnumbers):
            data[_i][_j] = 0
def check():
    data[mid][mid]='c'
    result=True
    for i in range(datalen):
        if 0 in data[i]:
            result=False
    return result

def printdata():
    result=''
    for i in data:
        result+='-'*(14-2*len(i))
        for j in i:
            temp = str(j)
            if len(temp)==1:
                temp='0'+temp
            if (i.index(j)==0):
                result=result+temp
            else:
                result=result+'-'*2+temp
        result+='-'*(14-2*len(i))
        result+='\n'
    print(result)

def solve(i):
        if (check()):
            print("hooray!",data)
            printdata()
            exit()
        else:
            if (i<13):
                n1=INnumbers[i]
                n2=INnumbers[i+1]
            else:
                n1=INnumbers[12]
                n2=INnumbers[13]

            routes = find_routes([location(n1)], n2 - n1, location(n2))
            for route in routes:
                erase(route)
                draw(route)
                solve(i+1)
                erase(route)

solve(0)

hooray! [[24, 25, 35, 34], [20, 23, 26, 36, 33], [19, 21, 22, 27, 28, 32], [18, 16, 15, 'c', 29, 30, 31], [17, 14, 9, 8, 1, 2], [13, 10, 7, 4, 3], [12, 11, 6, 5]] ------24--25--35--34------ ----20--23--26--36--33---- --19--21--22--27--28--32-- 18--16--15--0c--29--30--31 --17--14--09--08--01--02-- ----13--10--07--04--03---- ------12--11--06--05------

2018/08/01 02:36

hyun soo kim

트랙백으로 풀었습니다. 01에서 여섯 방향으로 가능한 곳에 02를 넣어보고.. 36까지 계속 반복..


class rikudo:
    def __init__(self, s):
        self.solved = False
        self.board = [[i[j:j + 2] for j, k in enumerate(i) if j % 2 == 0] for i in s.split('\n')]
        self.rows = len(self.board)
        self.cols = len(self.board[0])

    def solve(self):
        # 01 번에서 시작
        for i in range(self.rows):
            for j in range(self.cols):
                if '01' == self.board[i][j]:
                    self.next(i, j, '01')
                    break

    def next(self, y, x, n):
        if n == '36':
            self.solved = True
            return

        # 1, 3, 5, 7, 9, 11시 방향
        direction = ((1, 1), (0, 2), (-1, 1), (-1, -1), (0, -2), (1, -1))
        for d in direction:
            # 다음좌표
            ny = y + d[0]
            nx = x + d[1]

            # 가능 범위
            if ny >= 0 and ny < self.rows and nx >= 0 and nx < self.cols:
                # 다음수
                next_n = self.next_num(n)

                # 00 이거나 다음수이면,
                if self.board[ny][nx] == '00' or self.board[ny][nx] == next_n:
                    self.board[ny][nx] = next_n
                    org_n = self.board[ny][nx]
                    # 계속해서 다음로...
                    self.next(ny, nx, next_n)

                    if self.solved:
                        return

                    # 롤백
                    self.board[ny][nx] = org_n

    # 다음 수 : 09 -> 10
    def next_num(self, n):
        if n[0] == '0':
            n = n[1]
        n = str(int(n) + 1)
        return n.zfill(2)

    def __str__(self):
        s = ''
        for i in self.board:
            s += ''.join(i) + '\n'
        return s


s = '''
------24--00--00--00------
----00--00--26--36--00----
--00--21--00--00--28--32--
18--00--15------00--00--00
--00--00--00--08--01--00--
----00--10--00--00--03----
------12--00--00--05------
'''
r = rikudo(s=s.strip())
print(r)
r.solve()
print(r)

2018/08/01 11:03

박범수

import copy

direc = ((2,0), (-2,0), (1,1), (1,-1), (-1,1), (-1,-1))

# steps = []
def search(numbers, step, n = 0):
    def display(ns):        
        for y in range(7):
            _str = ''
            for x in range(13):
                if ns[(x,y)] == -1: _str = _str + '--'
                elif 0 <= ns[(x,y)] < 10: _str = _str + '0' + str(ns[(x,y)])
                elif ns[(x,y)] >= 10: _str = _str + str(ns[(x,y)])
            print(_str)
        print('')

    if n == 36:
        display(numbers)
        raise NotImplementedError
        #for i, step in enumerate(steps):


    def find_start(numbers):  # 시작점 찾기
        for key, value in numbers.items():
            if value == 1:
                return key
        print('start point not found')
        raise NotImplementedError

    if n == 0:  # 처음이라면 시작점에서 스타트
        search(numbers, find_start(numbers), 1)
        return

    _x, _y = step
    for dx, dy in direc: # 주변에 다음번호가 있다면 바로 건너가기
        x = _x + dx
        y = _y + dy
        if 0 <= x <= 12 and 0 <= y <= 6: # 범위를 벗어나지 않을떄
            if numbers[(x,y)] == n+1:
                temp = copy.deepcopy(numbers)
                temp[(x,y)] = n+1
                search(temp, (x,y), n+1)
                return

    for dx, dy in direc: # 0인 부분으로 건너가서 탐색(가지치기)
        x = _x + dx
        y = _y + dy
        if 0 <= x <= 12 and 0 <= y <= 6: # 범위를 벗어나지 않을떄
            if numbers[(x,y)] == 0:
                temp = copy.deepcopy(numbers)
                temp[(x,y)] = n+1
                search(temp, (x,y), n+1)

    # if no way
    return

print('문제를 입력하세요')
inputs = []
for i in range(7):
    inputs.append(input())

numbers = {}
for k, s in enumerate(inputs):
    for i in range(0, len(s), 2):
        if s[i:i+2]!='--': numbers[(i//2, k)] = int(s[i:i+2])
        else: numbers[(i//2, k)] = -1

try:
    print('')
    search(numbers, (0,0), 0)
    print('정답을 찾지 못했습니다.')
except NotImplementedError:
    print('탐색을 종료합니다.')

문제를 입력하세요
------24--00--00--35------
----00--00--00--00--00----
--00--21--00--00--28--32--
00--00--15------00--00--00
--17--00--00--08--01--00--
----00--10--00--00--00----
------12--00--00--05------

------24--25--36--35------
----20--23--26--34--33----
--19--21--22--27--28--32--
18--16--15------29--30--31
--17--14--09--08--01--02--
----13--10--07--04--03----
------12--11--06--05------

탐색을 종료합니다.

2019/04/26 03:04

messi

inp="""------24--00--00--00------
----00--00--26--36--00----
--00--21--00--00--28--32--
18--00--15------00--00--00
--00--00--00--08--01--00--
----00--10--00--00--03----
------12--00--00--05------"""
numlst=["0"+str(num) if len(str(num))==1 else str(num) for num in range(1,37)]
lst=[]
for ln in inp.split("\n"):
    elst=[""]*13
    for n in range(13):
        elst[n]=ln[n*2]+ln[n*2+1]
    lst.append(elst)
for ln in lst:
    for cmp in ln:
        print("%1s"%cmp, end="")
    print()

def findone(): #맨처음 "01"을 찾을 때 쓴 함수
    for y in range(len(lst)):
        for x in range(len(lst[0])):
            if lst[y][x]=="01":
                return x,y
x,y=findone()

n=1
maxX,maxY=len(lst[0]),len(lst)
def solve(y,x):
    global n
    if n==36:
        for ln in lst:
            for cmp in ln:
                print("%1s"%cmp, end="")
            print()
    else:
        for dx, dy in [(-1,-1),(1,-1),(2,0),(1,1),(-1,1),(-2,0)]:
            nx,ny=x+dx,y+dy
            if 0<=nx<maxX and 0<=ny<maxY and lst[ny][nx]!="--":
                if lst[ny][nx]=="00" or int(lst[ny][nx])==int(lst[y][x])+1:
                    on=lst[ny][nx]
                    lst[ny][nx]=numlst[n]
                    n+=1
                    solve(ny,nx)
                    lst[ny][nx]=on
                    n-=1
solve(4,9)

결과

------24--25--35--34------
----20--23--26--36--33----
--19--21--22--27--28--32--
18--16--15------29--30--31
--17--14--09--08--01--02--
----13--10--07--04--03----
------12--11--06--05------

2020/09/05 23:37

박시원

using System;
using System.Collections.Generic;

namespace solution
{
    class Program
    {
        public static int[,] board;
        static void Main(string[] args)
        {
            string[] sample = { "------24--00--00--00------",
                                "----00--00--26--36--00----",
                                "--00--21--00--00--28--32--",
                                "18--00--15------00--00--00",
                                "--00--00--00--08--01--00--",
                                "----00--10--00--00--03----",
                                "------12--00--00--05------"};

            ricudo(sample);
            Console.WriteLine("");
        }

        private static void ricudo(string[] sample)
        {
            int row = sample.Length;
            int col = sample[0].Length / 2;
            board = new int[row, col];
            Dictionary<int, int> dic = new Dictionary<int, int>();
            for (int r = 0; r < row; r++)
            {
                string curr = "";
                for (int c = 0; c < col; c++)
                {
                    curr = sample[r][c * 2].ToString() + sample[r][c * 2 + 1];
                    if (curr == "--")
                        board[r, c] = -1;
                    else
                    {
                        board[r, c] = int.Parse(curr);
                        dic[board[r, c]] = r * col + c;
                    }
                }
            }
            printBoard(row, col, "input");

            List<int> nums = new List<int>() { 1 };
            List<int> points = new List<int>() { dic[1] };
            List<int> d = new List<int>() { 0 };
            int[] dR = { 0, 1, 1, 0, -1, -1 };
            int[] dC = { 2, 1, -1, -2, -1, 1 };

            while(nums.Count < 36)
            {
                int n = nums.Count - 1;
                if (d[n] == 6)
                {                    
                    nums.RemoveAt(n);
                    points.RemoveAt(n);
                    d.RemoveAt(n);
                }
                n = nums.Count - 1;
                int next = nums[n] + 1;
                if (dic.ContainsKey(next))
                {
                    bool ok = false;
                    int r = points[n] / col, c = points[n] % col;
                    for (int i = 0; i < 6; i++)
                    {
                        int R = r + dR[i], C = c + dC[i];
                        if(0 <= R && R < row && 0 <= C && C < col && board[R,C] == next)
                        {
                            nums.Add(next);
                            points.Add(R * col + C);
                            d[n]++;
                            d.Add(0);
                            ok = true;
                            break;
                        }
                    }
                    if (ok == false)
                    {
                        nums.RemoveAt(n);
                        points.RemoveAt(n);
                        d.RemoveAt(n);
                    }
                }
                else
                {
                    int R = points[n] / col + dR[d[n]];
                    int C = points[n] % col + dC[d[n]];
                    d[n]++;
                    if(0<=R && R < row && 0<=C && C<col && !points.Contains(R*col + C) && board[R,C] == 0)
                    {
                        nums.Add(next);
                        points.Add(R * col + C);
                        d.Add(0);
                    }
                }
            }

            fillNums(row, col, nums, points);
            printBoard(row, col, "output");
        }

        private static void fillNums(int row, int col, List<int> nums, List<int> points)
        {
            for (int i = 0; i < nums.Count; i++)
            {
                int r = points[i] / col, c = points[i] % col;
                board[r, c] = nums[i];
            }
        }

        private static void printBoard(int row, int col, string str)
        {
            Console.WriteLine("\n {0}", str);
            for (int r = 0; r < row; r++)
            {
                for (int c = 0; c < col; c++)
                {
                    if(board[r,c] == -1)
                        Console.Write("--");
                    else
                        Console.Write("{0:00}",board[r,c]);
                }
                Console.WriteLine();
            }
        }
    }
}

2023/09/16 20:24

insperChoi

목록으로