adapted generation of statistics and json results of maintenance script to new layout

This commit is contained in:
Trilarion 2019-07-08 13:10:05 +02:00
parent 2915f52a19
commit 59b96e0878
5 changed files with 1240 additions and 1837 deletions

View File

@ -1,27 +1,27 @@
# Open Source Games
**[Dynamic HTML table](https://trilarion.github.io/opensourcegames/)** of the entries / Development **[Blog](https://trilarion.blogspot.com/search/label/osgames)** / **[Statistics](games/statistics.md)**
**[Dynamic HTML table](https://trilarion.github.io/opensourcegames/)** of the entries / Development **[Blog](https://trilarion.blogspot.com/search/label/osgames)** / **[Statistics](statistics.md#statistics)**
[comment]: # (start of autogenerated content, do not edit)
- **[All](games/_all.md)** (517)
- **[Action](games/_action.md)** (69)
- **[Arcade](games/_arcade.md)** (10)
- **[Adventure](games/_adventure.md)** (14)
- **[Visual novel](games/_visual novel.md)** (4)
- **[Sports](games/_sports.md)** (8)
- **[Platform](games/_platform.md)** (2)
- **[Puzzle](games/_puzzle.md)** (18)
- **[Role playing](games/_role playing.md)** (117)
- **[Simulation](games/_simulation.md)** (33)
- **[Strategy](games/_strategy.md)** (168)
- **[Card game](games/_card game.md)** (1)
- **[Board game](games/_board game.md)** (9)
- **[Music](games/_music.md)** (3)
- **[Educational](games/_educational.md)** (3)
- **[Tool](games/_tool.md)** (15)
- **[Game engine](games/_game engine.md)** (7)
- **[Framework](games/_framework.md)** (59)
- **[Library](games/_library.md)** (22)
- **[All](games/_all.md#All)** (517)
- **[Action](games/_action.md#Action)** (69)
- **[Arcade](games/_arcade.md#Arcade)** (10)
- **[Adventure](games/_adventure.md#Adventure)** (14)
- **[Visual novel](games/_visual novel.md#Visual novel)** (4)
- **[Sports](games/_sports.md#Sports)** (8)
- **[Platform](games/_platform.md#Platform)** (2)
- **[Puzzle](games/_puzzle.md#Puzzle)** (18)
- **[Role playing](games/_role playing.md#Role playing)** (117)
- **[Simulation](games/_simulation.md#Simulation)** (33)
- **[Strategy](games/_strategy.md#Strategy)** (168)
- **[Card game](games/_card game.md#Card game)** (1)
- **[Board game](games/_board game.md#Board game)** (9)
- **[Music](games/_music.md#Music)** (3)
- **[Educational](games/_educational.md#Educational)** (3)
- **[Tool](games/_tool.md#Tool)** (15)
- **[Game engine](games/_game engine.md#Game engine)** (7)
- **[Framework](games/_framework.md#Framework)** (59)
- **[Library](games/_library.md#Library)** (22)
[comment]: # (end of autogenerated content)
A list of open source games sorted by genre. The projects are at least in beta stage with a code basis that builds
@ -30,7 +30,7 @@ modification and sharing by others. For each entry, relevant information is coll
download possibilities and build instructions.
Similar collections include [Open Source Clones](https://github.com/opengaming/osgameclones) of popular games;
Popular games, add-ons, maps, etc. [hosted on GitHub](https://github.com/leereilly/games); [List of open-source video games](https://en.wikipedia.org/wiki/List_of_open-source_video_games) on Wikipedia.
Popular games, add-ons, maps, etc. [hosted on GitHub](https://github.com/leereilly/games); [List of open-source video games](https://en.wikipedia.org/wiki/List_of_open-source_video_games) on Wikipedia or the [LibreGameWiki](https://libregamewiki.org/Main_Page).
## Contribute

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,8 @@
<body>
<div class="container">
<h2>List of Open Source Games</h2>
<p>List of open source games in beta or mature state under a license that allows sharing and modification. The list is managed on <a href="https://github.com/Trilarion/opensourcegames">Github</a> (see also the <a href="https://trilarion.blogspot.com/search/label/osgames">Blog</a>). For feedback (additions, corrections, ..) use the <a href="https://github.com/Trilarion/opensourcegames/issues">Issue tracker</a>. Some <a href="https://github.com/Trilarion/opensourcegames/blob/master/games/statistics.md#statistics">statistics</a> about the games.</p>
<p> Other collections: <a href="https://osgameclones.com/">Open Source Game Clones</a>, <a href="https://github.com/leereilly/games/blob/master/README.md">Games on Github</a>, <a href="https://en.wikipedia.org/wiki/List_of_open-source_video_games">Open source games (Wikipedia)</a></p>
<p>List of open source games in beta or mature state under a license that allows sharing and modification. The list is managed on <a href="https://github.com/Trilarion/opensourcegames">Github</a> (see also the <a href="https://trilarion.blogspot.com/search/label/osgames">Blog</a>). For feedback (additions, corrections, ..) use the <a href="https://github.com/Trilarion/opensourcegames/issues">Issue tracker</a>. Some <a href="https://github.com/Trilarion/opensourcegames/blob/master/statistics.md#statistics">statistics</a> about the games.</p>
<p> Other collections: <a href="https://osgameclones.com/">Open Source Game Clones</a>, <a href="https://github.com/leereilly/games/blob/master/README.md">Games on Github</a>, <a href="https://en.wikipedia.org/wiki/List_of_open-source_video_games">Open source games (Wikipedia)</a>, <a href="https://libregamewiki.org/Main_Page">LibreGameWiki</a></p>
<p><h4>Features</h4></p>
<p>
<ul>

View File

@ -1,7 +1,7 @@
[comment]: # (autogenerated content, do not edit)
# Statistics
analyzed 517 entries on 2019-07-04 14:01:29
analyzed 517 entries on 2019-07-08 13:09:04
## State
@ -11,7 +11,7 @@ analyzed 517 entries on 2019-07-04 14:01:29
##### Inactive State
Blobby Volley 2 (2017), Eat The Whistle (2017), PokerTH (2017), Scrolling Game Development Kit 2 (2017), Tressette (2017), YSoccer (2017), Zone of Control (2017), 3d.city (2016), Atlantis (2016), Atomic Tanks (2016), Atrinik (2016), Birth of the Empires (2016), DNT (2016), Dark Destiny (2016), Dungeon Monkey Eternal (2016), FreeRCT (2016), GLtron (2016), Infiniminer (2016), JaNaG - Java Name Generator (2016), Mechanized Assault & eXploration Reloaded (2016), Open Yahtzee (2016), Polis (2016), TORCS, The Open Racing Car Simulator (2016), Tremulous (2016), ransack (2016), Aleph One: Marathon (2015), Battleround (2015), Blobwars: Metal Blob Solid (2015), Boulder Dash (2015), D-Fend Reloaded (2015), Dash Engine (2015), DeSmuME (2015), Delta Engine (2015), Egoboo (2015), Free heroes2 engine (2015), Liquid War (2015), M.E.W.L. (2015), Roguish (2015), Scrabble3D (2015), Tenes Empanadas Graciela (2015), The Endless Dungeons (2015), The Epic of Heroes (2015), TwinEngine (2015), Witch Blast (2015), pyORPG (2015), Argentum Online (2014), Battles of Antargis (2014), BlockOut II (2014), Cart Life (2014), Deity (2014), Dune Dynasty (2014), EternalWinterWars (2014), FAR Colony (2014), Fujo (2014), Grobots (2014), Hale (2014), Heroes of Wing Commander (2014), Kingdoms (2014), Lips of Suna (2014), Open RPG Maker (2014), Open Tibia (2014), Radakan (2014), SDL Game Engine 2D (2014), SDL Sopwith (2014), Scorched 3D (2014), Sintel The Game (2014), Summoning Wars (2014), Supremacy (2014), Turious (2014), VDrift (2014), X-Moto (2014), Xenowar (2014), rpge (2014), sandbox Game Maker (2014), Bos Wars (2013), C-evo (2013), Candy Box 2 (2013), Decker (2013), DemiGod (2013), Dungeon Mapper (2013), HoDoKu (2013), Holyspirit (2013), MechCommander 2 Omnitech (2013), Mpango (2013), Murder In The Public Domain (2013), OpenRPG (2013), Phantasy Star Rebirth (2013), Room for Change (2013), SoftPixel Engine (2013), Source of Tales (2013), SpaceZero (2013), The Bub's Brothers (2013), Trinity Reign (2013), Zero Ballistics (2013), Biniax (2012), BlackNova Traders (2012), Blitzkrieg (2012), Cataclysm (2012), Celestron (2012), CommandoJS (2012), Conquests (2012), Dark City (2012), Frozen Bubble (2012), Goblin Camp (2012), Hexwar (2012), Mega Mario (2012), OpenArena (2012), PARPG (2012), TROPHY (2012), Thousand Parsec (2012), Tux Football (2012), UFO2000 (2012), Wizards Magic (2012), OpenBlox (2011), Aeron (2011), Battlefield Java (2011), Brain Workshop (2011), Danger from the Deep (2011), Dawn (2011), Fish Fillets - Next Generation (2011), GalaxyMage Redux (2011), KQ Lives (2011), Kobold's Quest 2 (2011), OpenMOO2 (2011), PyKaraoke (2011), Skrupel - Tribute Compilation (2011), Smash Battle (2011), Song of Albion (2011), Star Control II: The Ur-Quan Masters (2011), Tux of Math Command (2011), UlDunAd (2011), World of Phaos (2011), X-Force: Fight For Destiny (2011), AI Wars (2010), Bombermaaan (2010), Crimson Fields (2010), Dragon History - Dračí Historie (2010), Heroes of Wesnoth (2010), Labyrinth of Worlds (2010), Linwarrior 3D (2010), Mercenary Commander (2010), OpenHoMM (2010), Slay (2010), SpaceTrader for Java (2010), UltraStar (2010), XPilot (2010), XSera (2010), nXtank (2010), Alien Assault Traders (2009), Annchienta (2009), Ardentryst (2009), Battle Tanks (2009), Crown and Cutlass (2009), Dark Oberon (2009), Duel Commander (2009), Fall of Imyrin (2009), Fallen Spire (2009), FreeTrain (2009), Glest (2009), Goblin Hack (2009), MicroWar 2.0 (2009), Netrek (2009), ORIENT (2009), OpenPop (2009), SDL Asylum (2009), Secret Mario Chronicles (2009), Space Trader for Windows (2009), World of Heroes (2009), Yo Frankie! (2009), A Planet's Revenge (2008), Attal: Lords of doom (2008), Avanor (2008), Freestars (2008), Mars, Land of No Mercy (2008), Meritous (2008), Open Game Engine (2008), S.C.O.U.R.G.E. (2008), Sengoku: Warring States of Japan (2008), Space Opera (2008), Armies (2007), Brutal Chess (2007), Eos, Dawn of Light: A Space Opera (2007), Pang Zero (2007), SharpKonquest (2007), Silvertree (2007), Slash'EM (2007), Underworld Adventures (2007), World Builder (2007), kiki the nano bot (2007), Betrayer's Moon Tactics (2006), Boson (2006), GPL Arcade Volleyball (2006), GUSANOS (2006), Grabble (2006), JQuest (2006), Linley's Dungeon Crawl (2006), Metal Mech (2006), RPDungeon - computer aided role playing (2006), Rogue Clone IV (2006), StarBlastrix (2006), GalaxyNG (2005), H-World (2005), LinCity (2005), Spice Trade (2005), Tumiki Fighters (2005), WAtomic (2005), Xconq (2005), ZAngband (2005), Colonization too (2004), GM Tools (2004), Gee Whiz (2004), Openglad (2004), PySol (2004), T-Bots (2004), AntiChess (2003), Cat Mother Dead Justice (2003), Civil (2003), Machinations (2003), Pizza Business (2003), Planetary Hoppers (2003), The Clans (2003), Wargamer (2003), XArchon (2003), Maelstrom (2002), Umbra (2002), Greenius' Civil War (2001), Tux Racer (2001), Operation Citadel (2000), xdigger (1999), Ballerburg (1987)
Blobby Volley 2 (2017), Eat The Whistle (2017), PokerTH (2017), Scrolling Game Development Kit 2 (2017), Tressette (2017), YSoccer (2017), Zone of Control (2017), 3d.city (2016), Atlantis (2016), Atomic Tanks (2016), Atrinik (2016), Birth of the Empires (2016), DNT (2016), Dark Destiny (2016), Dungeon Monkey Eternal (2016), FreeRCT (2016), GLtron (2016), Infiniminer (2016), JaNaG - Java Name Generator (2016), Mechanized Assault & eXploration Reloaded (2016), Open Yahtzee (2016), Polis (2016), TORCS, The Open Racing Car Simulator (2016), Tremulous (2016), ransack (2016), Aleph One: Marathon (2015), Battleround (2015), Blobwars: Metal Blob Solid (2015), Boulder Dash (2015), D-Fend Reloaded (2015), Dash Engine (2015), DeSmuME (2015), Delta Engine (2015), Egoboo (2015), Free heroes2 engine (2015), Liquid War (2015), M.E.W.L. (2015), Roguish (2015), Scrabble3D (2015), Tenes Empanadas Graciela (2015), The Endless Dungeons (2015), The Epic of Heroes (2015), TwinEngine (2015), Witch Blast (2015), pyORPG (2015), Argentum Online (2014), Battles of Antargis (2014), BlockOut II (2014), Cart Life (2014), Deity (2014), Dune Dynasty (2014), EternalWinterWars (2014), FAR Colony (2014), Fujo (2014), Grobots (2014), Hale (2014), Heroes of Wing Commander (2014), Kingdoms (2014), Lips of Suna (2014), Open RPG Maker (2014), Open Tibia (2014), Radakan (2014), SDL Game Engine 2D (2014), SDL Sopwith (2014), Scorched 3D (2014), Sintel The Game (2014), Summoning Wars (2014), Supremacy (2014), Turious (2014), VDrift (2014), X-Moto (2014), Xenowar (2014), rpge (2014), sandbox Game Maker (2014), Bos Wars (2013), C-evo (2013), Candy Box 2 (2013), Decker (2013), DemiGod (2013), Dungeon Mapper (2013), HoDoKu (2013), Holyspirit (2013), MechCommander 2 Omnitech (2013), Mpango (2013), Murder In The Public Domain (2013), OpenRPG (2013), Phantasy Star Rebirth (2013), Room for Change (2013), SoftPixel Engine (2013), Source of Tales (2013), SpaceZero (2013), The Bub's Brothers (2013), Trinity Reign (2013), Zero Ballistics (2013), Biniax (2012), BlackNova Traders (2012), Blitzkrieg (2012), Cataclysm (2012), Celestron (2012), CommandoJS (2012), Conquests (2012), Dark City (2012), Frozen Bubble (2012), Goblin Camp (2012), Hexwar (2012), Mega Mario (2012), OpenArena (2012), PARPG (2012), TROPHY (2012), Thousand Parsec (2012), Tux Football (2012), UFO2000 (2012), Wizards Magic (2012), Aeron (2011), Battlefield Java (2011), Brain Workshop (2011), Danger from the Deep (2011), Dawn (2011), Fish Fillets - Next Generation (2011), GalaxyMage Redux (2011), KQ Lives (2011), Kobold's Quest 2 (2011), OpenBlox (2011), OpenMOO2 (2011), PyKaraoke (2011), Skrupel - Tribute Compilation (2011), Smash Battle (2011), Song of Albion (2011), Star Control II: The Ur-Quan Masters (2011), Tux of Math Command (2011), UlDunAd (2011), World of Phaos (2011), X-Force: Fight For Destiny (2011), AI Wars (2010), Bombermaaan (2010), Crimson Fields (2010), Dragon History - Dračí Historie (2010), Heroes of Wesnoth (2010), Labyrinth of Worlds (2010), Linwarrior 3D (2010), Mercenary Commander (2010), OpenHoMM (2010), Slay (2010), SpaceTrader for Java (2010), UltraStar (2010), XPilot (2010), XSera (2010), nXtank (2010), Alien Assault Traders (2009), Annchienta (2009), Ardentryst (2009), Battle Tanks (2009), Crown and Cutlass (2009), Dark Oberon (2009), Duel Commander (2009), Fall of Imyrin (2009), Fallen Spire (2009), FreeTrain (2009), Glest (2009), Goblin Hack (2009), MicroWar 2.0 (2009), Netrek (2009), ORIENT (2009), OpenPop (2009), SDL Asylum (2009), Secret Mario Chronicles (2009), Space Trader for Windows (2009), World of Heroes (2009), Yo Frankie! (2009), A Planet's Revenge (2008), Attal: Lords of doom (2008), Avanor (2008), Freestars (2008), Mars, Land of No Mercy (2008), Meritous (2008), Open Game Engine (2008), S.C.O.U.R.G.E. (2008), Sengoku: Warring States of Japan (2008), Space Opera (2008), Armies (2007), Brutal Chess (2007), Eos, Dawn of Light: A Space Opera (2007), Pang Zero (2007), SharpKonquest (2007), Silvertree (2007), Slash'EM (2007), Underworld Adventures (2007), World Builder (2007), kiki the nano bot (2007), Betrayer's Moon Tactics (2006), Boson (2006), GPL Arcade Volleyball (2006), GUSANOS (2006), Grabble (2006), JQuest (2006), Linley's Dungeon Crawl (2006), Metal Mech (2006), RPDungeon - computer aided role playing (2006), Rogue Clone IV (2006), StarBlastrix (2006), GalaxyNG (2005), H-World (2005), LinCity (2005), Spice Trade (2005), Tumiki Fighters (2005), WAtomic (2005), Xconq (2005), ZAngband (2005), Colonization too (2004), GM Tools (2004), Gee Whiz (2004), Openglad (2004), PySol (2004), T-Bots (2004), AntiChess (2003), Cat Mother Dead Justice (2003), Civil (2003), Machinations (2003), Pizza Business (2003), Planetary Hoppers (2003), The Clans (2003), Wargamer (2003), XArchon (2003), Maelstrom (2002), Umbra (2002), Greenius' Civil War (2001), Tux Racer (2001), Operation Citadel (2000), xdigger (1999), Ballerburg (1987)
## Code Languages
@ -59,23 +59,19 @@ Blobby Volley 2 (2017), Eat The Whistle (2017), PokerTH (2017), Scrolling Game D
## Code licenses
Without license tag: 6 (1.2%)
Core War, GPL Arcade Volleyball, Imperium, Netrek, Nexiuz, kiki the nano bot
##### Licenses frequency
- GPL-2.0 (38.0%)
- GPL-3.0 (25.0%)
- MIT (11.0%)
- Custom (4.5%)
- GPL-2.0 (37.5%)
- GPL-3.0 (24.7%)
- MIT (10.9%)
- Custom (4.4%)
- ? (3.3%)
- Apache-2.0 (2.5%)
- 3-clause BSD (2.1%)
- ? (2.1%)
- GPL (2.1%)
- LGPL-2.1 (2.1%)
- zlib (2.1%)
- AGPL-3.0 (1.2%)
- AGPL-3.0 (1.1%)
- LGPL-3.0 (1.0%)
- LGPL-2.0 (0.8%)
- MPL (0.6%)
@ -104,107 +100,100 @@ Core War, GPL Arcade Volleyball, Imperium, Netrek, Nexiuz, kiki the nano bot
##### Keywords frequency
- TBS (7.3%)
- RTS (6.0%)
- roguelike (6.0%)
- remake (5.5%)
- requires original content (4.7%)
- MMO (4.5%)
- online (4.5%)
- shooter (4.5%)
- tool (3.7%)
- SP (3.1%)
- arcade (2.6%)
- 3D (2.4%)
- MP (2.1%)
- racing (2.1%)
- sports (2.1%)
- 2D (1.8%)
- board game (1.8%)
- browser (1.6%)
- puzzle (1.6%)
- engine (1.3%)
- cards (1.0%)
- popular (1.0%)
- visual novel (1.0%)
- TB (0.8%)
- artillery (0.8%)
- console (0.8%)
- educational (0.8%)
- karaoke (0.8%)
- music (0.8%)
- port (0.8%)
- space (0.8%)
- boardgame (0.5%)
- chess (0.5%)
- game engine (0.5%)
- kids (0.5%)
- multiplayer (0.5%)
- platform (0.5%)
- programming (0.5%)
- risklike (0.5%)
- sliding blocks (0.5%)
- snake-like (0.5%)
- voxel (0.5%)
- 2d (0.3%)
- JRPG (0.3%)
- MUD (0.3%)
- action-rpg (0.3%)
- action/adventure (0.3%)
- asciiart (0.3%)
- beatem-up (0.3%)
- blocks (0.3%)
- brain exercise (0.3%)
- car (0.3%)
- card game (0.3%)
- strategy (19.2%)
- role playing (13.4%)
- action (7.9%)
- framework (6.7%)
- simulation (3.8%)
- turn-based (3.5%)
- real time (2.6%)
- roguelike (2.6%)
- library (2.5%)
- remake (2.4%)
- puzzle (2.1%)
- requires original content (2.1%)
- shooter (2.1%)
- massive multiplayer online (1.9%)
- online (1.9%)
- tool (1.7%)
- adventure (1.6%)
- singleplayer (1.4%)
- arcade (1.1%)
- multiplayer (1.1%)
- 2D (1.0%)
- 3D (1.0%)
- board game (1.0%)
- racing (0.9%)
- sports (0.9%)
- game engine (0.8%)
- text-based (0.6%)
- cards (0.5%)
- popular (0.5%)
- visual novel (0.5%)
- artillery (0.3%)
- cars (0.3%)
- client (0.3%)
- continuation of commercial project (0.3%)
- demake (0.3%)
- dice game (0.3%)
- drive (0.3%)
- editor (0.3%)
- eingine (0.3%)
- emulator (0.3%)
- engine required (0.3%)
- fly (0.3%)
- football (0.3%)
- for adults (0.3%)
- fps (0.3%)
- frontend (0.3%)
- game editor (0.3%)
- game maker (0.3%)
- game of life (0.3%)
- gui toolkit (0.3%)
- inspired (0.3%)
- interface generator (0.3%)
- isometric (0.3%)
- isometric 2D (0.3%)
- kid-friendly (0.3%)
- language binding (0.3%)
- match 3 (0.3%)
- mmorpg (0.3%)
- physics (0.3%)
- plattformer (0.3%)
- point&click (0.3%)
- poker (0.3%)
- sandbox (0.3%)
- shoot'em up (0.3%)
- shootem up (0.3%)
- side-scrolling (0.3%)
- simulation (0.3%)
- soccer (0.3%)
- social (0.3%)
- source documentation generator (0.3%)
- tank (0.3%)
- tetris attack (0.3%)
- text (0.3%)
- text-based (0.3%)
- top down (0.3%)
- top-down (0.3%)
- tux (0.3%)
- worms-like (0.3%)
- console (0.3%)
- educational (0.3%)
- karaoke (0.3%)
- music (0.3%)
- port (0.3%)
- space (0.3%)
- wormslike (0.3%)
- chess (0.2%)
- isometric (0.2%)
- kids (0.2%)
- platform (0.2%)
- programming (0.2%)
- risklike (0.2%)
- shoot'em up (0.2%)
- sliding blocks (0.2%)
- snake-like (0.2%)
- top-down (0.2%)
- voxel (0.2%)
- JRPG (0.1%)
- MUD (0.1%)
- action-rpg (0.1%)
- action/adventure (0.1%)
- asciiart (0.1%)
- beat'em up (0.1%)
- blocks (0.1%)
- brain exercise (0.1%)
- card game (0.1%)
- client (0.1%)
- continuation of commercial project (0.1%)
- demake (0.1%)
- dice game (0.1%)
- editor (0.1%)
- eingine (0.1%)
- emulator (0.1%)
- engine required (0.1%)
- fly (0.1%)
- football (0.1%)
- for adults (0.1%)
- frontend (0.1%)
- game editor (0.1%)
- game maker (0.1%)
- game of life (0.1%)
- gui toolkit (0.1%)
- inspired (0.1%)
- interface generator (0.1%)
- kid-friendly (0.1%)
- language binding (0.1%)
- match 3 (0.1%)
- mmorpg (0.1%)
- physics (0.1%)
- plattformer (0.1%)
- point&click (0.1%)
- poker (0.1%)
- ruleset (0.1%)
- sandbox (0.1%)
- side-scrolling (0.1%)
- soccer (0.1%)
- social (0.1%)
- source documentation generator (0.1%)
- tank (0.1%)
- tetris attack (0.1%)
- tux (0.1%)
## Entries without download or play fields

View File

@ -22,29 +22,25 @@ valid_fields = ('Home', 'Media', 'State', 'Play', 'Download', 'Platform', 'Keywo
valid_platforms = ('Windows', 'Linux', 'macOS', 'Android', 'Browser')
recommended_keywords = ('action', 'arcade', 'adventure', 'visual novel', 'sports', 'platform', 'puzzle', 'role playing', 'simulation', 'strategy', 'card game', 'board game', 'music', 'educational', 'tool', 'game engine', 'framework', 'library')
def extract_overview_for_toc(file):
def entry_iterator():
"""
Parses a file for some interesting fields and concatenates the content.
To be displayed after the game name in the category TOCs.
"""
info = infos[file]
output = []
# get all entries (ignore everything starting with underscore)
entries = os.listdir(games_path)
entries = (x for x in entries if not x.startswith('_'))
if 'code language' in info:
output.extend(info['code language'])
# iterate over all entries
for entry in entries:
entry_path = os.path.join(games_path, entry)
if 'code license' in info:
output.extend(info['code license'])
# read entry
content = read_text(entry_path)
# state
if 'state' in info:
output.extend(info['state'])
output = ", ".join(output)
return output
# yield
yield entry, entry_path, content
def update_readme_and_tocs(infos):
@ -57,7 +53,7 @@ def update_readme_and_tocs(infos):
Needs to be performed regularly.
"""
print('update readme file')
print('update readme and toc files')
# delete all toc files
entries = os.listdir(games_path)
@ -66,6 +62,7 @@ def update_readme_and_tocs(infos):
os.remove(os.path.join(games_path, entry))
# read readme
readme_file = os.path.join(root_path, 'README.md')
readme_text = read_text(readme_file)
# compile regex for identifying the building blocks
@ -82,14 +79,14 @@ def update_readme_and_tocs(infos):
# create all toc and readme entry
title = 'All'
file = '_all.md'
update = ['- **[{}](games/{})** ({})\n'.format(title, file, len(infos))]
update = ['- **[{}](games/{}#{})** ({})\n'.format(title, file, title, len(infos))]
create_toc(title, file, infos)
for keyword in recommended_keywords:
infos_filtered = [x for x in infos if keyword in x['keywords']]
title = keyword.capitalize()
file = '_{}.md'.format(keyword)
update.append('- **[{}](games/{})** ({})\n'.format(title, file, len(infos_filtered)))
update.append('- **[{}](games/{}#{})** ({})\n'.format(title, file, title, len(infos_filtered)))
create_toc(title, file, infos_filtered)
update = ''.join(update)
@ -121,79 +118,26 @@ def create_toc(title, file, entries):
# add to text
text += '\n'.join(rows)
# write to toc file
write_text(toc_file, text)
def update_category_tocs():
"""
Lists all entries in all sub folders and generates the list in the toc file.
Needs to be performed regularly.
"""
# get category paths
category_paths = get_category_paths()
# for each category
for category_path in category_paths:
print('generate toc for {}'.format(os.path.basename(category_path)))
# read toc header line
toc_file = os.path.join(category_path, TOC)
toc_header = read_first_line(toc_file) # stays as is
# get paths of all entries in this category
entry_paths = get_entry_paths(category_path)
# get titles (discarding first two ("# ") and last ("\n") characters)
titles = [read_first_line(path)[2:-1] for path in entry_paths]
# get more interesting info
more = [extract_overview_for_toc(path) for path in entry_paths]
# combine name, file name and more info
info = zip(titles, [os.path.basename(path) for path in entry_paths], more)
# sort according to entry title (should be unique)
info = sorted(info, key=lambda x:x[0])
# assemble output
update = ['- **[{}]({})** ({})\n'.format(*entry) for entry in info]
update = "".join(update)
# combine with toc header
text = toc_header + '\n' + "[comment]: # (start of autogenerated content, do not edit)\n" + update + "\n[comment]: # (end of autogenerated content)"
# write to toc file
with open(toc_file, mode='w', encoding='utf-8') as f:
f.write(text)
def check_validity_external_links():
"""
Checks all external links it can find for validity. Prints those with non OK HTTP responses. Does only need to be run
from time to time.
"""
print("check external links (can take a while)")
# regex for finding urls (can be in <> or in () or a whitespace
regex = re.compile(r"[\s\n]<(http.+?)>|\]\((http.+?)\)|[\s\n](http[^\s\n,]+)")
# count
number_checked_links = 0
# get category paths
category_paths = get_category_paths()
# for each category
for category_path in category_paths:
print('check links for {}'.format(os.path.basename(category_path)))
# get entry paths
entry_paths = get_entry_paths(category_path)
# for each entry
for entry_path in entry_paths:
# read entry
content = read_text(entry_path)
# iterate over all entries
for _, entry_path, content in entry_iterator():
# apply regex
matches = regex.findall(content)
@ -232,43 +176,36 @@ def check_template_leftovers():
Should be run only occasionally.
"""
print('check for template leftovers')
# load template and get all lines
text = read_text(os.path.join(games_path, 'template.md'))
text = read_text(os.path.join(root_path, 'template.md'))
text = text.split('\n')
check_strings = [x for x in text if x and not x.startswith('##')]
# get category paths
category_paths = get_category_paths()
# iterate over all entries
for _, entry_path, content in entry_iterator():
# for each category
for category_path in category_paths:
# get paths of all entries in this category
entry_paths = get_entry_paths(category_path)
for check_string in check_strings:
if content.find(check_string) >= 0:
raise RuntimeError('{}: found {}'.format(os.path.basename(entry_path), check_string))
for entry_path in entry_paths:
# read it line by line
content = read_text(entry_path)
for check_string in check_strings:
if content.find(check_string) >= 0:
print('{}: found {}'.format(os.path.basename(entry_path), check_string))
def fix_keywords():
"""
Fixes the keywords.
"""
print('fix keywords')
regex = re.compile(r"(.*)(- Keywords:.*)(- Code repository: .*)", re.DOTALL)
# get all entries
# get all entries (ignore everything starting with underscore)
entries = os.listdir(games_path)
entries = (x for x in entries if not x.startswith('_'))
# iterate over all entries
for entry in entries:
entry_path = os.path.join(games_path, entry)
# read entry
content = read_text(entry_path)
for entry, entry_path, content in entry_iterator():
# match with regex
matches = regex.findall(content)
@ -308,6 +245,7 @@ def fix_keywords():
# write again
write_text(entry_path, new_content)
def parse_entry(content):
"""
Returns a dictionary of the features of the content
@ -442,19 +380,13 @@ def assemble_infos():
Parses all entries and assembles interesting infos about them.
"""
print('assemble game infos')
# a database of all important infos about the entries
infos = []
# get all entries (ignore everything starting with underscore)
entries = os.listdir(games_path)
entries = (x for x in entries if not x.startswith('_'))
# iterate over all entries
for entry in entries:
entry_path = os.path.join(games_path, entry)
# read entry
content = read_text(entry_path)
for entry, _, content in entry_iterator():
# parse entry
info = parse_entry(content)
@ -468,35 +400,35 @@ def assemble_infos():
return infos
def generate_statistics():
def update_statistics(infos):
"""
Generates the statistics page.
Should be done every time the entries change.
"""
# for this function replace infos with infos.values
infois = infos.values()
print('update statistics')
# start the page
statistics_path = os.path.join(games_path, 'statistics.md')
statistics_file = os.path.join(root_path, 'statistics.md')
statistics = '[comment]: # (autogenerated content, do not edit)\n# Statistics\n\n'
# total number
number_entries = len(infois)
number_entries = len(infos)
rel = lambda x: x / number_entries * 100 # conversion to percent
statistics += 'analyzed {} entries on {}\n\n'.format(number_entries, datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
# State (beta, mature, inactive)
statistics += '## State\n\n'
number_state_beta = sum(1 for x in infois if 'beta' in x['state'])
number_state_mature = sum(1 for x in infois if 'mature' in x['state'])
number_inactive = sum(1 for x in infois if 'inactive' in x)
number_state_beta = sum(1 for x in infos if 'beta' in x['state'])
number_state_mature = sum(1 for x in infos if 'mature' in x['state'])
number_inactive = sum(1 for x in infos if 'inactive' in x)
statistics += '- mature: {} ({:.1f}%)\n- beta: {} ({:.1f}%)\n- inactive: {} ({:.1f}%)\n\n'.format(number_state_mature, rel(number_state_mature), number_state_beta, rel(number_state_beta), number_inactive, rel(number_inactive))
if number_inactive > 0:
entries_inactive = [(x['title'], x['inactive']) for x in infois if 'inactive' in x]
entries_inactive = [(x['title'], x['inactive']) for x in infos if 'inactive' in x]
entries_inactive.sort(key=lambda x: x[0]) # first sort by name
entries_inactive.sort(key=lambda x: x[1], reverse=True) # then sort by inactive year (more recently first)
entries_inactive = ['{} ({})'.format(*x) for x in entries_inactive]
@ -517,7 +449,7 @@ def generate_statistics():
# get all languages together
languages = []
for info in infois:
for info in infos:
if field in info:
languages.extend(info[field])
@ -533,16 +465,16 @@ def generate_statistics():
field = 'code license'
# those without license
number_no_license = sum(1 for x in infois if field not in x)
number_no_license = sum(1 for x in infos if field not in x)
if number_no_license > 0:
statistics += 'Without license tag: {} ({:.1f}%)\n\n'.format(number_no_license, rel(number_no_license))
entries_no_license = [x['title'] for x in infois if field not in x]
entries_no_license = [x['title'] for x in infos if field not in x]
entries_no_license.sort()
statistics += ', '.join(entries_no_license) + '\n\n'
# get all licenses together
licenses = []
for info in infois:
for info in infos:
if field in info:
licenses.extend(info[field])
@ -559,7 +491,7 @@ def generate_statistics():
# get all keywords together
keywords = []
for info in infois:
for info in infos:
if field in info:
keywords.extend(info[field])
@ -574,7 +506,7 @@ def generate_statistics():
statistics += '## Entries without download or play fields\n\n'
entries = []
for info in infois:
for info in infos:
if 'download' not in info and 'play' not in info:
entries.append(info['title'])
entries.sort()
@ -586,7 +518,7 @@ def generate_statistics():
entries = []
field = 'code repository'
for info in infois:
for info in infos:
if field in info:
popular = False
for repo in info[field]:
@ -607,11 +539,11 @@ def generate_statistics():
# get all build systems together
build_systems = []
for info in infois:
for info in infos:
if field in info:
build_systems.extend(info[field])
statistics += 'Build systems information available for {:.1f}% of all projects.\n\n'.format(len(build_systems) / len(infois) * 100)
statistics += 'Build systems information available for {:.1f}% of all projects.\n\n'.format(rel(len(build_systems)))
unique_build_systems = set(build_systems)
unique_build_systems = [(l, build_systems.count(l) / len(build_systems)) for l in unique_build_systems]
@ -622,7 +554,7 @@ def generate_statistics():
# C, C++ projects without build system information
c_cpp_project_without_build_system = []
for info in infois:
for info in infos:
if field not in info and ('C' in info['code language'] or 'C++' in info['code language']):
c_cpp_project_without_build_system.append(info['title'])
c_cpp_project_without_build_system.sort()
@ -630,7 +562,7 @@ def generate_statistics():
# C, C++ projects with build system information but without CMake as build system
c_cpp_project_not_cmake = []
for info in infois:
for info in infos:
if field in info and 'CMake' in info[field] and ('C' in info['code language'] or 'C++' in info['code language']):
c_cpp_project_not_cmake.append(info['title'])
c_cpp_project_not_cmake.sort()
@ -642,11 +574,11 @@ def generate_statistics():
# get all platforms together
platforms = []
for info in infois:
for info in infos:
if field in info:
platforms.extend(info[field])
statistics += 'Platform information available for {:.1f}% of all projects.\n\n'.format(len(platforms) / len(infois) * 100)
statistics += 'Platform information available for {:.1f}% of all projects.\n\n'.format(rel(len(platforms)))
unique_platforms = set(platforms)
unique_platforms = [(l, platforms.count(l) / len(platforms)) for l in unique_platforms]
@ -655,25 +587,27 @@ def generate_statistics():
unique_platforms = ['- {} ({:.1f}%)'.format(x[0], x[1]*100) for x in unique_platforms]
statistics += '##### Platforms frequency\n\n' + '\n'.join(unique_platforms) + '\n\n'
with open(statistics_path, mode='w', encoding='utf-8') as f:
f.write(statistics)
# write to statistics file
write_text(statistics_file, statistics)
def export_json():
def export_json(infos):
"""
Parses all entries, collects interesting info and stores it in a json file suitable for displaying
with a dynamic table in a browser.
"""
print('export to json for web display')
# make database out of it
db = {'headings': ['Game', 'Description', 'Download', 'Category', 'State', 'Keywords', 'Source']}
db = {'headings': ['Game', 'Description', 'Download', 'State', 'Keywords', 'Source']}
entries = []
for info in infos.values():
for info in infos:
# game & description
entry = ['{} (<a href="{}">home</a>, <a href="{}">entry</a>)'.format(info['title'], info['home'][0],
r'https://github.com/Trilarion/opensourcegames/blob/master/games/' + info['path']),
r'https://github.com/Trilarion/opensourcegames/blob/master/games/' + info['file']),
textwrap.shorten(info['description'], width=60, placeholder='..')]
# download
@ -683,9 +617,6 @@ def export_json():
else:
entry.append('')
# category
entry.append(info['category'])
# state (field state is essential)
entry.append('{} / {}'.format(info['state'][0], 'inactive since {}'.format(info['inactive']) if 'inactive' in info else 'active'))
@ -780,13 +711,13 @@ def bzr_repo(repo):
return None
def update_primary_code_repositories():
def export_primary_code_repositories_json():
primary_repos = {'git':[],'svn':[],'hg':[],'bzr':[]}
unconsumed_entries = []
# for every entry filter those that are known git repositories (add additional repositories)
for info in infos.values():
for info in infos:
field = 'code repository-raw'
# if field 'Code repository' is available
if field in info:
@ -837,36 +768,37 @@ def update_primary_code_repositories():
primary_repos[k] = sorted(set(v))
# write them to tools/git
json_path = os.path.join(games_path, os.path.pardir, 'tools', 'archives.json')
json_path = os.path.join(root_path, 'tools', 'archives.json')
text = json.dumps(primary_repos, indent=1)
write_text(json_path, text)
if __name__ == "__main__":
# paths
games_path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'games'))
readme_file = os.path.realpath(os.path.join(games_path, os.pardir, 'README.md'))
root_path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.pardir))
games_path = os.path.join(root_path, 'games')
# check for unfilled template lines
check_template_leftovers()
# fix keywords
fix_keywords()
# assemble info
infos = assemble_infos()
# recount and wriite to readme and to tocs
# recount and write to readme and to tocs
update_readme_and_tocs(infos)
# generate report
#generate_statistics()
update_statistics(infos)
# update database for html table
#export_json()
export_json(infos)
# check for unfilled template lines
#check_template_leftovers()
# fix keywords
# fix_keywords()
# collect list of primary code repositories
export_primary_code_repositories_json()
# check external links (only rarely)
# check_validity_external_links()
# collect list of primary code repositories
#update_primary_code_repositories()