shingoushori's dialy

音信号処理を専ら研究していた元博士後期課程の学生によるメモ

PythonでSimutransのマップに天空の市道の碁盤の目を追加してみた

Simutrans(http://japanese.simutrans.com)は, 素晴らしい.

それでもって私は人工地盤っぽいことをやっています。
Simutransで人工地盤してみる - shingoushori's dialy

これまで、Pythonでセーブデータをあれこれし
地形をいじったり、交差部分の接続方向をいじったりして来ました
今回は、いよいよ道路を敷いてみました

... city_road でもいけました ... 高架の道路じゃなくても宙に浮くんですね

<経緯>
地形の坂とか、各街の標高や山の標高を考慮しながら敷設していくのは、
楽しいけれども、一向に眺めて楽しいところまでたどり着けなかったのです ...

さらに、気になったのがデータ容量と景観
地平から全山頂より超えるところまで足場を組み上げると..
その階層の分だけ、おそらくデータ容量がほぼ線形で増えます
街も足場で埋め尽くされて見えないし ...
... 足場は後から消せるのですね Simutrans アプリ上でも
だから、消せばいいわけですけれども さらに手間ですね
ミスも多いだろうし

... そういった事情を一気にクリアすべく、
もういっそ高い階層にセーブデータ上で流し込んでやろうということです<メモ>
しかし、上空に 市道を敷いても、その近辺に民家が経つことはなかったと思います 残念


↓サンプルコードです。
↓※絶対に元のデータを上書きしないでください。
↓※データや設定が破壊されても、責任は一切負えません。
↓version=0.120.4, 自作改造パック pak.japan_custom 用になっていますが ... 適宜正しい値になっていないと、面白いくらい開けないデータになります、多分
↓私はそれで苦戦しました
↓さらに、文字コードとかあれこれ読み込みが繊細です。

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

import xml.etree.ElementTree as ET

filename_in = 'test_in.sve'
filename_out = 'test_out.sve'

f = open(filename_in)
data1 = f.read()  # ファイル終端まで全て読んだデータを返す
f.close()

data2 = data1.replace("<![CDATA[","<CDATA>")
data2 = data2.replace("]]>","</CDATA>")

root = ET.fromstring(unicode(data2.encode('utf-8')))

# マップのサイズを取得
N_x = int(root[0][0].text)
N_y = int(root[0][13].text)

count_p = 0
count_x = 0
count_y = 0

pitch_x = 4
pitch_y = 4
for planquadrat in root.iter('planquadrat_t'):
  count_x = count_p % N_x
  count_y = count_p / N_x
  if (count_x % pitch_x == 0) or (count_y % pitch_y == 0):
    count_ch = len(planquadrat.getchildren())
    
    # 接続方向
    # 1:toN, 2:toE, 4:toS, 8:toW
    connect_arg = 0
    if (count_x % pitch_x == 0):
      connect_arg = connect_arg + 1 + 4
    if (count_y % pitch_y == 0):
      connect_arg = connect_arg + 2 + 8
    if (count_x == 0):
      connect_arg = connect_arg & (15 - 8)
    if (count_x == N_x-1):
      connect_arg = connect_arg & (15 - 2)
    if (count_y == 0):
      connect_arg = connect_arg & (15 - 1)
    if (count_y == N_x-1):
      connect_arg = connect_arg & (15 - 4)
    
    elem_1 = ET.Element('id')
    elem_1.text = '6'
    elem_2 = ET.Element('grund_t')
    subelem_1 = ET.SubElement(elem_2, 'i8')
    subelem_1.text = '10' # 高度
    subelem_1 = ET.SubElement(elem_2, 'i8')
    subelem_1.text = '-6' # 
    subelem_1 = ET.SubElement(elem_2, 'i8')
    subelem_1.text = '4' # 
    subelem_1 = ET.SubElement(elem_2, 'CDATA')
    subelem_1.text = '' # 
    subelem_1 = ET.SubElement(elem_2, 'i8')
    subelem_1.text = '0' # 
    subelem_1 = ET.SubElement(elem_2, 'id')
    subelem_1.text = '1' # 
    subelem_1 = ET.SubElement(elem_2, 'strasse_t')
    subelem_2 = ET.SubElement(subelem_1, 'weg_t')
    subelem_3 = ET.SubElement(subelem_2, 'i8')
    subelem_3.text = '15' # owner?
    subelem_3 = ET.SubElement(subelem_2, 'i8')
    subelem_3.text = str(connect_arg) # 接続方向
    subelem_3 = ET.SubElement(subelem_2, 'i16')
    subelem_3.text = '0' # 速度 (ロード時 pakの情報に上書き)
    subelem_3 = ET.SubElement(subelem_2, 'i8')
    subelem_3.text = '0' # 
    subelem_3 = ET.SubElement(subelem_2, 'i32')
    subelem_3.text = '0' # 
    subelem_3 = ET.SubElement(subelem_2, 'i32')
    subelem_3.text = '0' # 
    subelem_3 = ET.SubElement(subelem_2, 'i32')
    subelem_3.text = '0' # 
    subelem_3 = ET.SubElement(subelem_2, 'i32')
    subelem_3.text = '0' # 
    subelem_2 = ET.SubElement(subelem_1, 'CDATA')
    subelem_2.text = 'city_road'
    subelem_1 = ET.SubElement(elem_2, 'id')
    subelem_1.text = '-1' # 
    subelem_1 = ET.SubElement(elem_2, 'i8')
    subelem_1.text = '0' # 
    planquadrat.insert(count_ch-1, elem_1)
    planquadrat.insert(count_ch, elem_2)
  count_p = count_p + 1

data3 = ET.tostring(root, encoding="utf-8")

data4 = "<?xml version=\"1.0\"?>\n" + data3
data4 = data4.replace("<CDATA>","<![CDATA[")
data4 = data4.replace("</CDATA>","]]>")
data4 = data4.replace("<CDATA />","<![CDATA[]]>")
data4 = data4.replace("<Simutrans pak=\"pak.japan_custom\" version=\"0.120.4\">","<Simutrans version=\"0.120.4\" pak=\"pak.japan_custom\">")

f = open(filename_out,'w') # 書き込みモードで開く
f.write(data4)  # 引数の文字列をファイルに書き込む
f.close()