update
This commit is contained in:
@ -7,6 +7,11 @@ http://cyxdown.free.fr/bs/
|
||||
http://cyxdown.free.fr/f2b/
|
||||
http://dead-code.org/home/
|
||||
https://github.com/restorer/gloomy-dungeons-2
|
||||
https://github.com/WohlSoft/PGE-Project
|
||||
https://en.wikipedia.org/wiki/List_of_free_and_open-source_Android_applications#Games
|
||||
https://notabug.org/Calinou/awesome-gamedev#games
|
||||
https://forum.freegamedev.net/viewtopic.php?f=20&t=11627
|
||||
https://www.old-games.ru/forum/threads/nekommercheskie-analogi-izvestnyx-igr.40868/page-9
|
||||
https://github.com/MyreMylar/pygame_gui
|
||||
http://e-adventure.e-ucm.es/login/index.php (games of eAdventure)
|
||||
http://ethernet.wasted.ch/
|
||||
|
@ -1,4 +1,4 @@
|
||||
start: title description property+ _E note _E? building
|
||||
start: title description property+ _E note? _E? building
|
||||
|
||||
title: "# " /(?! ).+(?<! )/ "\n" _E // not starting or ending with a space
|
||||
|
||||
@ -12,4 +12,4 @@ building: "## Building\n" _E property+ _E? note // the "building" section
|
||||
|
||||
note: /(?![\-#]).*\n/* // Unstructured text, not starting with - or #
|
||||
|
||||
_E: /^$\n/m // empty new line (filtered from tree)
|
||||
_E: /^$\n/m // empty new line
|
@ -1,8 +1,8 @@
|
||||
start: header entries*
|
||||
start: header entry*
|
||||
|
||||
header: "# " name " (" number ")\n" _E
|
||||
|
||||
entries: "## " name " (" number ")\n" _E property+ _E
|
||||
entry: "## " name " (" number ")\n" _E property+ _E
|
||||
|
||||
property: "- " _key ": " _value "\n"
|
||||
_key: /(?! ).+?(?=:)(?<! )/ // key: everything until next ":", not beginning or ending with a space
|
||||
|
@ -22,11 +22,14 @@ if __name__ == "__main__":
|
||||
|
||||
# read developer info
|
||||
developer_info = osg.read_developer_info()
|
||||
osg.write_developer_info(developer_info)
|
||||
osg.write_developer_info(developer_info) # write again just to make nice
|
||||
|
||||
# assemble info
|
||||
entries = osg.assemble_infos()
|
||||
|
||||
# cross-check
|
||||
osg.compare_entries_developers(entries, developer_info)
|
||||
|
||||
# loop over infos
|
||||
developers = ''
|
||||
try:
|
||||
|
9
code/maintenance_collect_inspiration_infos.py
Normal file
9
code/maintenance_collect_inspiration_infos.py
Normal file
@ -0,0 +1,9 @@
|
||||
from utils import constants as c, utils, osg
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
inspirations = osg.read_inspirations_info()
|
||||
osg.write_inspirations_info(inspirations) # write again just to check integrity
|
||||
|
||||
# assemble info
|
||||
entries = osg.assemble_infos()
|
@ -20,7 +20,7 @@ class ListingTransformer(lark.Transformer):
|
||||
def name(self, x):
|
||||
return ('name', x[0].value)
|
||||
|
||||
def entries(self, x):
|
||||
def entry(self, x):
|
||||
d = {}
|
||||
for key, value in x:
|
||||
d[key] = value
|
||||
@ -32,6 +32,34 @@ class ListingTransformer(lark.Transformer):
|
||||
def start(self, x):
|
||||
return x
|
||||
|
||||
# transformer
|
||||
|
||||
class EntryTransformer(lark.Transformer):
|
||||
|
||||
def start(self, x):
|
||||
d = {}
|
||||
for key, value in x:
|
||||
d[key] = value
|
||||
return d
|
||||
|
||||
def title(self, x):
|
||||
return ('title', x[0].value)
|
||||
|
||||
def description(self, x):
|
||||
return ('description', x[0].value)
|
||||
|
||||
def property(self, x):
|
||||
return (str.casefold(x[0].value), x[1].value)
|
||||
|
||||
def note(self, x):
|
||||
return ('note', x[0].value)
|
||||
|
||||
def building(self, x):
|
||||
d = {}
|
||||
for key, value in x:
|
||||
d[key] = value
|
||||
return ('building', d)
|
||||
|
||||
|
||||
essential_fields = ('Home', 'State', 'Keywords', 'Code repository', 'Code language', 'Code license')
|
||||
valid_fields = (
|
||||
@ -72,6 +100,7 @@ regex_sanitize_name = re.compile(r"[^A-Za-z 0-9-+]+")
|
||||
regex_sanitize_name_space_eater = re.compile(r" +")
|
||||
|
||||
valid_developer_fields = ('name', 'games', 'contact', 'organization', 'home')
|
||||
valid_inspiration_fields = ('name', 'inspired entries')
|
||||
|
||||
comment_string = '[comment]: # (partly autogenerated content, edit with care, read the manual before)'
|
||||
|
||||
@ -383,18 +412,27 @@ def read_developer_info():
|
||||
developers = read_and_parse(developer_file, grammar_file, transformer)
|
||||
# now transform a bit more
|
||||
for index, dev in enumerate(developers):
|
||||
# check for valid keys
|
||||
for field in dev.keys():
|
||||
if field not in valid_developer_fields:
|
||||
raise RuntimeError('Unknown developer field "{}" for developer: {}.'.format(field, dev['name']))
|
||||
# strip from name or organization (just in case)
|
||||
for field in ('name', 'organization'):
|
||||
if field in dev:
|
||||
dev[field] = dev[field].strip()
|
||||
# split games, contact (are lists)
|
||||
for field in ('games', 'contact'):
|
||||
if field in dev:
|
||||
content = dev[field]
|
||||
content = content.split(',')
|
||||
content = [x.strip() for x in content]
|
||||
dev[field] = content
|
||||
# check for duplicate names entries
|
||||
names = [dev['name'] for dev in developers]
|
||||
duplicate_names = (name for name in names if names.count(name) > 1)
|
||||
duplicate_names = set(duplicate_names) # to avoid duplicates in duplicate_names
|
||||
if duplicate_names:
|
||||
print('Warning: duplicate developer names: {}'.format(', '.join(duplicate_names)))
|
||||
return developers
|
||||
|
||||
|
||||
@ -445,7 +483,27 @@ def read_inspirations_info():
|
||||
inspirations_file = os.path.join(c.root_path, 'inspirations.md')
|
||||
grammar_file = os.path.join(c.code_path, 'grammar_listing.lark')
|
||||
transformer = ListingTransformer()
|
||||
return read_and_parse(inspirations_file, grammar_file, transformer)
|
||||
inspirations = read_and_parse(inspirations_file, grammar_file, transformer)
|
||||
# now transform a bit more
|
||||
for index, inspiration in enumerate(inspirations):
|
||||
# check for valid keys
|
||||
for field in inspiration.keys():
|
||||
if field not in valid_inspiration_fields:
|
||||
raise RuntimeError('Unknown field "{}" for inspiration: {}.'.format(field, inspiration['name']))
|
||||
# split lists
|
||||
for field in ('inspired entries', ):
|
||||
if field in inspiration:
|
||||
content = inspiration[field]
|
||||
content = content.split(',')
|
||||
content = [x.strip() for x in content]
|
||||
inspiration[field] = content
|
||||
# check for duplicate names entries
|
||||
names = [inspiration['name'] for inspiration in inspirations]
|
||||
duplicate_names = (name for name in names if names.count(name) > 1)
|
||||
duplicate_names = set(duplicate_names) # to avoid duplicates in duplicate_names
|
||||
if duplicate_names:
|
||||
print('Warning: duplicate inspiration names: {}'.format(', '.join(duplicate_names)))
|
||||
return inspirations
|
||||
|
||||
|
||||
def write_inspirations_info(inspirations):
|
||||
@ -454,4 +512,79 @@ def write_inspirations_info(inspirations):
|
||||
:param inspirations:
|
||||
:return:
|
||||
"""
|
||||
inspirations_file = os.path.join(c.root_path, 'inspirations.md')
|
||||
# comment
|
||||
content = '{}\n'.format(comment_string)
|
||||
|
||||
# number of developer
|
||||
content += '# Inspirations ({})\n\n'.format(len(inspirations))
|
||||
|
||||
# sort by name
|
||||
inspirations.sort(key=lambda x: str.casefold(x['name']))
|
||||
|
||||
# iterate over them
|
||||
for inspiration in inspirations:
|
||||
# inspiration name
|
||||
content += '## {} ({})\n\n'.format(inspiration['name'], len(inspiration['inspired entries']))
|
||||
|
||||
# games
|
||||
content += '- Inspired entries: {}\n'.format(', '.join(sorted(inspiration['inspired entries'], key=str.casefold)))
|
||||
|
||||
# all the remaining in alphabetical order
|
||||
for field in sorted(inspiration.keys()):
|
||||
if field not in ('name', 'inspired entries'):
|
||||
value = inspiration[field]
|
||||
field = field.capitalize()
|
||||
if isinstance(value, str):
|
||||
content += '- {}: {}\n'.format(field, value)
|
||||
else:
|
||||
content += '- {}: {}\n'.format(field, ', '.join(sorted(value, key=str.casefold)))
|
||||
content += '\n'
|
||||
|
||||
# write
|
||||
inspirations_file = os.path.join(c.root_path, 'inspirations2.md')
|
||||
utils.write_text(inspirations_file, content)
|
||||
|
||||
|
||||
|
||||
def compare_entries_developers(entries, developers):
|
||||
"""
|
||||
Cross checks the game entries lists and the developers lists.
|
||||
:param entries: List of game entries
|
||||
:param developers: List of developers
|
||||
"""
|
||||
|
||||
# from the entries create a dictionary with developer names
|
||||
devs1 = {}
|
||||
for entry in entries:
|
||||
name = entry['name']
|
||||
for dev in entry.get('developer', []):
|
||||
if dev in devs1:
|
||||
devs1[dev].append(name)
|
||||
else:
|
||||
devs1[dev] = [name]
|
||||
devs1_names = set(devs1.keys())
|
||||
|
||||
# from the developers create a dictionary with developer names
|
||||
devs2 = dict(zip((dev['name'] for dev in developers), (dev['games'] for dev in developers)))
|
||||
devs2_names = set(devs2.keys())
|
||||
|
||||
# devs only in entries
|
||||
for dev in devs1_names - devs2_names:
|
||||
print('Warning: dev "{}" only in entries ({}), not in developers'.format(dev, ','.join(devs1[dev])))
|
||||
# devs only in developers
|
||||
for dev in devs2_names - devs1_names:
|
||||
print('Warning: dev "{}" only in developers ({}), not in entries'.format(dev, ','.join(devs2[dev])))
|
||||
# for those in both, check that the games lists are equal
|
||||
for dev in devs1_names.intersection(devs2_names):
|
||||
games1 = set(devs1[dev])
|
||||
games2 = set(devs2[dev])
|
||||
delta = games1 - games2
|
||||
if delta:
|
||||
print('Warning: dev "{}" has games in entries ({}) that are not present in developers'.format(dev, ', '.join(delta)))
|
||||
delta = games2 - games1
|
||||
if delta:
|
||||
print('Warning: dev "{}" has games in developers ({}) that are not present in entries'.format(dev, ', '.join(delta)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user