#!/usr/bin/env python # -*- coding: utf-8 -*- import argparse import heapq import numpy as np import random import parse import itertools class MAP: def __init__(self, afile): #解答ファイルから読み込み x_index = 0 y_index = 0 z_index = -1 with open(afile) as f: for str_line in f: if str_line[0]=='G': pass elif str_line[0]=='S': size = parse.parse("SIZE {X:d}X{Y:d}X{Z:d}", str_line) self.X=size["X"] self.Y=size["Y"] self.Z=size["Z"] self.name="%dX%dX%d" % (self.X, self.Y, self.Z) self.map=np.zeros((self.X+1, self.Y+1, self.Z+1)) self.mapdic=0 elif str_line[0]=='L': z_index += 1 y_index = 0 elif str_line[0] >= '0' and str_line[0] <= '9': array = str_line.split(",") x_index = 0 for num in array: self.map[x_index][y_index][z_index] = int(num) x_index += 1 y_index += 1 self.n_line = int(np.amax(self.map)) self.line = np.zeros((self.n_line,2,3)) for x,y,z in itertools.product(\ range(self.X), range(self.Y), range(self.Z)): neighbours = self.neighbour([x,y,z]) index = int(self.map[x][y][z]-1) num = self.countV(index+1, neighbours) if num == 1: if list(self.line[index][0]) == [0,0,0]: self.line[index][0][0] = x self.line[index][0][1] = y self.line[index][0][2] = z else: self.line[index][1][0] = x self.line[index][1][1] = y self.line[index][1][2] = z def countV(self, value, point_list): """座標リストpoint_list内の座標(x,y,z)のself.mapの値(ラインのインデックス)がvalueと等しいものの個数を数えます""" c = 0 for p in point_list: if self.map[tuple(p)] == value: c += 1 return c def delLine(self, index): """self.map上のラインindexを消す. 端点は消さない""" for x,y,z in itertools.product(\ range(self.X), range(self.Y), range(self.Z)): if self.map[x][y][z] == index+1 \ and [x,y,z] != list(self.line[index][0]) \ and [x,y,z] != list(self.line[index][1]): self.map[x][y][z] = 0 def sortline(self, start, end, x, y, z): """ 不明 使えるかもしれないので残しておく""" length=len(x) lines=np.append(np.append(x,y),z).reshape((3,length)) lines=lines.T for i in range(1,length): if np.equal(start,lines[i]).all(): lines[0],lines[i]=np.copy(lines[i]),np.copy(lines[0]) break for i in range(0,len(x)-1): if np.linalg.norm(lines[i]-lines[i+1])==1:continue for j in range(i+2,len(x)): if np.linalg.norm(lines[i]-lines[j])==1: lines[j],lines[i+1]=np.copy(lines[i+1]),np.copy(lines[j]) break lines=lines.T x,y,z=lines[0],lines[1],lines[2] return x,y,z def print(self): """問題・解答をプリント """ self.printQ() self.printA() def printQ(self): """問題をプリント """ print(self.strQ()) def printA(self): """解答をプリント """ print(self.strA()) def strQ(self): """問題文字列を作成する""" str=[] str.append("SIZE %dX%dX%d\n" % (self.X, self.Y, self.Z)) str.append("LINE_NUM %d\n\n" % (self.n_line)) for i,line in enumerate(self.line): str.append("LINE#%d (%d,%d,%d)%s(%d,%d,%d)\n" % (i+1, line[0][0], line[0][1], line[0][2]+1, random.choice([' ', '-']), line[1][0], line[1][1], line[1][2]+1)) return "".join(str) def strA(self): """解答文字列を作成する""" str=[] str.append("SIZE %dX%dX%d\n" % (self.X, self.Y, self.Z)) for zm in range(self.Z): z=zm+1 str.append("LAYER %d\n" % (z)) for y in range(self.Y): for x in range(self.X-1): str.append("%02d," % self.map[x][y][zm]) str.append("%d\n" % self.map[self.X-1][y][zm]) return "".join(str) def save(self): """問題・解答をファイルとして保存する""" self.saveQ() self.saveA() def saveQ(self): """問題をファイルとして保存する""" filename="Q-"+self.name+".txt" f=open(filename, 'w') f.write(self.strQ()) f.close() def saveA(self): """解答をファイルとして保存する""" filename="A-"+self.name+".txt" f=open(filename, 'w') f.write(self.strA()) f.close() def isregular(self, points): """self.mapの範囲内の座標だけを返す""" a=np.all(points>=0,axis=1) b=points[:,0]=2: l=np.append(l,True) else: l=np.append(l,False) return points[l==False] def neighbour(self, point): """ 与えられた座標をX,Y,Z方向に1移動させ, それら座標のリストを返す """ dlist=np.array([[0,0,-1], [0,0,1], [0,-1,0], [0,1,0], [-1,0,0], [1,0,0]]) nlist=point+dlist return nlist def addLine(self, maxlength): MAXLOOP=1000 for i in range(MAXLOOP): start=np.array([[random.randrange(self.X), random.randrange(self.Y), random.randrange(self.Z)]]) if len(self.isblank(start))!=0:break else: return False self.n_line=self.n_line+1 point = start[0] self.map[tuple(point)]=self.n_line for i in range(maxlength): points = self.neighbour(point) points = self.isregular(points) points = self.isblank(points) points = self.istip(points) if len(points)==0: break point=random.choice(points) self.map[tuple(point)]=self.n_line end=point if np.array_equal(start[0],end): self.map[tuple(end)]=0 self.n_line=self.n_line-1 return False self.line=np.append(self.line, [[start[0], end]], axis=0) return True def optLine(self, n_line): MAX=72*72*8 dlist=np.array([[0,0,-1], [0,0,1], [0,-1,0], [0,1,0], [-1,0,0], [1,0,0]]) self.map[self.map==n_line]=0 q=[] #コスト, 座標, ラインが引かれた方向 heapq.heappush(q, (0, self.line[i][0], [0,0,0])) while True: if q == []: break (priority, point, direction) = heapq.heappop(q) if point == self.line[i][1]: break next_points=point+dlist boollist=isregular(next_points) for n, d in zip(next_points[boollist],dlist[boollist]): if self.map[tuple(n)]!=0:continue if len(isregular(next_point))==0:continue if np.array_equal(direction, d): heapq.heappush((priority+1)) def generate(self, linenum, maxlength): self.name="".join([self.name,"_%d_%d" % (linenum, maxlength)]) for i in range(linenum): self.addLine(maxlength) #for i in range(self.n_line): # self.optLine(i) if __name__ == '__main__': parser = argparse.ArgumentParser(description='NLGenerator') parser.add_argument('--input', '-i', default=None, type=str, help='Input file') args = parser.parse_args() m=MAP(args.input) m.delLine(10-1) m.print() #m.save() #m.saveQ() #m.saveA() #m.show()