Page 1 of 1

Utility to Generate a Graphical Tech Tree from techs.ruleset

Posted: Fri Jul 13, 2018 9:56 pm
by vodot
There used to be a utility would generate a tech tree from a techs.ruleset file. Anyone know where I could find that?

EDIT: found this page, but the tech tree util seems dead: http://freeciv.wikia.com/wiki/Utilities

Re: Utility to Generate a Graphical Tech Tree from techs.ruleset

Posted: Sat Jul 14, 2018 8:43 am
by JTN
The TechTree utility linked there is the only one I know of. No idea if it still works; it might well need tweaking.

I've fixed the links on that page to point to files.freeciv.org (where most stuff from download.gna.org ended up), and most of the links now work, including the TechTree one.

Re: Utility to Generate a Graphical Tech Tree from techs.ruleset

Posted: Sat Jul 14, 2018 7:58 pm
by madmax
From the help, it seems it uses as input the output of a server command that is no more.

If you just need a tech tree, without all the options and info that utility had, below is a dirty python script that translates a techs.ruleset into graphviz format. Example usage:

Code: Select all

./techtree.py ~/src/freeciv-2.6/data/classic/techs.ruleset | dot -Tpng > classic.png
Doesn't tell you the effects of the techs, what units, buildings, etc they make available or obsolete, doesn't translate, doesn't support include... You just get the tech requirements graph.

Code: Select all

#!/usr/bin/python3

import sys
import configparser
import re


def freeciv_to_ini(filename):
  with open(filename, 'r') as file:
    clean_line = ''
    for line in file:
      if line == '\n':
        continue
      if line[-2] == '\\':
        clean_line = clean_line + line[:-2]
      else:
        if line[-2] == ';':
          line = line[:-2]
        yield clean_line + line
        clean_line = ''


config = configparser.ConfigParser(interpolation=None)
config.read_file(freeciv_to_ini(sys.argv[1]))
advances = dict()
name_re = re.compile('(_\()?("(\?[^:]*:)?([^"]*"))')

for section in config.sections():
  if section[:8] == 'advance_':
    name = ''
    rule_name = ''
    reqs = list()
    for key, value in config.items(section):
      if key == 'rule_name':
        rule_name = value
      elif key == 'name':
        name = '"' + re.match(name_re, value).group(4)
        if rule_name == '':
          rule_name = name
      elif key[:3] == 'req' and value != '"None"':
        reqs.append(value)

    advances[rule_name] = (name, reqs)

print('digraph tree {')
print('label=', config.get('datafile', 'description'), ';')
for key, value in advances.items():
  print(key, '[label=', value[0], '];')
for key, value in advances.items():
  for req in value[1]:
    print(req, '->', key, ';')
print('}')
Edit: corrected so that translation contexts don't duplicate nodes.

Re: Utility to Generate a Graphical Tech Tree from techs.ruleset

Posted: Sat Jul 14, 2018 10:13 pm
by JTN
madmax wrote:From the help, it seems it uses as input the output of a server command that is no more.
Looks like the "rulesout" command it relied on was removed from 1.14.

However, the next script on the Utilities page, "Rulesout perl script", looks like it was intended to replace the missing command. Looks like it reads ruleset files. It is likely to need tweaking for ruleset format changes since 2004.

Re: Utility to Generate a Graphical Tech Tree from techs.ruleset

Posted: Mon Jul 16, 2018 4:07 am
by vodot
JTN wrote:The TechTree utility linked there is the only one I know of. No idea if it still works; it might well need tweaking.

I've fixed the links on that page to point to files.freeciv.org (where most stuff from download.gna.org ended up), and most of the links now work, including the TechTree one.
Thanks!!
madmax wrote:From the help, it seems it uses as input the output of a server command that is no more.

If you just need a tech tree, without all the options and info that utility had, below is a dirty python script that translates a techs.ruleset into graphviz format. Example usage:

Code: Select all

./techtree.py ~/src/freeciv-2.6/data/classic/techs.ruleset | dot -Tpng > classic.png
Doesn't tell you the effects of the techs, what units, buildings, etc they make available or obsolete, doesn't translate, doesn't support include... You just get the tech requirements graph.

Code: Select all

#!/usr/bin/python3

import sys
import configparser
import re


def freeciv_to_ini(filename):
  with open(filename, 'r') as file:
    clean_line = ''
    for line in file:
      if line == '\n':
        continue
      if line[-2] == '\\':
        clean_line = clean_line + line[:-2]
      else:
        if line[-2] == ';':
          line = line[:-2]
        yield clean_line + line
        clean_line = ''


config = configparser.ConfigParser(interpolation=None)
config.read_file(freeciv_to_ini(sys.argv[1]))
advances = dict()
name_re = re.compile('(_\()?("(\?[^:]*:)?([^"]*"))')

for section in config.sections():
  if section[:8] == 'advance_':
    name = ''
    rule_name = ''
    reqs = list()
    for key, value in config.items(section):
      if key == 'rule_name':
        rule_name = value
      elif key == 'name':
        name = '"' + re.match(name_re, value).group(4)
        if rule_name == '':
          rule_name = name
      elif key[:3] == 'req' and value != '"None"':
        reqs.append(value)

    advances[rule_name] = (name, reqs)

print('digraph tree {')
print('label=', config.get('datafile', 'description'), ';')
for key, value in advances.items():
  print(key, '[label=', value[0], '];')
for key, value in advances.items():
  for req in value[1]:
    print(req, '->', key, ';')
print('}')
Edit: corrected so that translation contexts don't duplicate nodes.
...dude, did you just write this??