• Welcome to the new COTI server. We've moved the Citizens to a new server. Please let us know in the COTI Website issue forum if you find any problems.

ACS Compact Format

robject

SOC-14 10K
Admin Award
Marquis
INTRODUCTION

I use a Traveller-aware, machine-friendly but human-readable format for Adventure-Class Ships.

Data typically takes up around 2K bytes, but there are some free text fields that can make the file larger. However, even with explanatory text, these files don't seem to get above 20 KB.

Anyway.

This format has a dual nature.

First, it is not difficult to write a simple parser for it: you need to be able to read line by line, and you need to be able to split on the colon or the space character. If you can do that, then it should be easy to know where you are and what do to.

Second, it's also a strict subset of YAML, so a YAML parser should be able to parse it in one operation.


STRUCTURE

It has three sections.

Header
This comes first. It is a set of key-value pairs that identify the format version, creation date, and general ship information.

Generally, this section begins with a line containing only three dashes. This can be omitted; if it's present, then everything in front of it should be considered free text and skipped.

Component Array
This section begins with a line containing only "Components:". It is followed by a list of components with the following format:

Each component line begins with a space, then a dash, then another space.
Each component then follows with a set of six space-delimited configuration strings, then a descriptive text label of arbitrary length.
The configuration strings are required, even if they're just a dash, because that makes them easy to split up.
The six configuration strings are interpreted as follows:
  1. A 3-character operational identifier indicating what class of component this is. More on this later.
  2. The code (or value) of the component itself.
  3. The quantity of this component.
  4. QREBS for the component. All zeros is default.
  5. The tonnage of the component.
  6. The decimal cost, in MCr, of the component.
#1 + #2 don't always form a unique identifier. For example, sensors, weapons, and defenses have a formulaic label that encodes not only the type of component, but also its range, stage, and emplacement type.


Footer
This optional section has a single line, starting with "ref: " and ending with a reference label. It may be a URL.


EXAMPLE

Here's a worked example using the Judges Guild subsidized liner.

Code:
---
ACS1.0: Wed Apr 13 17:18:53 2022
Mission: Subsidized Liner
QSP: MK-FB13
TL: 12
Name: Glimmerdrift
Tons: 600
Actual Tons: 600

MCr: 144.9
Builder: Ling Standard
Owner: Judges Guild
Disposition: In Service
Allegiance: ImJG

Crew comfort: 0
Passenger demand: 0
Cargo: 124
FuelPercentage: 12
Components:
#  CODE R  # QREBS TONS  MCR   LABEL
 - HH0  B  1 00000 600   18    Braced Hull
 - HL1 n/  1 00000 -3    0     No Landers
 - AA1 12  1 00000 0     0     AV=12. 1 Kinetic Plate
 - DF0  -  1 00000 180   0     Jump Fuel (3  parsecs)
 - DF0  -  1 00000 24.3  0     Plant Fuel (1.5 months)
 - DJ2  J  1 00000 50    50    Jump Drive-3 (J)
 - DM1  C  1 00000 5     10    Maneuver Drive-1 (C)
 - DP1  1  1 93CC2 28    28    Imp PowerPlant J (R3)
 - OC1  3  1 00000 3     10.5  Computer Model/3 std
 - OL0  L  1 00000 2     2     Life Support Long Term
 - OL0  X  1 00000 1     1     Life Support Luxury
 - OB0  -  1 00000 6     0.6   Standard Bridge
 - SS1  1  1 00000 2     2.5   LR Ant Communicator
 - SS1  4  1 00000 6     4     LR Ext Radar
 - SS1  1  1 00000 2     2.5   LR Ant Scope
 - WW1 -2  3 00000 1     0.2   AR T1 Empty
 - CS0  1  9 00000 2     0.1   Crew Stateroom
 - CC0  -  1 00000 18    0     Crew Lounge
 - CF0  2  1 00000 1     1     Crew Common Fresher
 - PL0  - 80 00000 0.5   0.1   Low Berth
 - PC0  -  1 00000 124   0     Cargo Hold Basic
 - PO1  -  1 00000 2     0     Cargo Lock
 - PO1  -  2 00000 0.5   0.1   Air Lock
 - PS0  1 21 00000 2     0.1   Standard Stateroom
 - PC0  -  1 00000 42    0     Passenger Lounge
 - PF0  2  3 00000 1     1     Common Fresher

ref: [<a href='http://www.farfuture.net/'>Far Future Enterprises</a>]
 

Attachments

  • ImJG MK-FB13 Glimmerdrift.acs.txt
    1.6 KB · Views: 0
Last edited:
A less compact form of this file is currently output by my Shipyard program. Since the format is still in flux, I didn't write a reader for it yet: the Shipyard round-trips with YAML, JSON, and XML, all of which are significantly larger than the ACS format.

I was using a very, very compressed form of this in a BASIC program I was writing earlier this year. It's not enough: I want more customizability but still in a small file size that's still not difficult for BASIC to parse.

So mainly it's for portability between my applications: Shipyard can build any ACS and write it to D64 images; I'd like those images to be easy to parse in BASIC.
 
Why not standardise on XML? Given compute and storage power available today I'm not sure I see the utility of a schema optimised for space. The ZX-81 has been retired :) and the WWW HTML is based on XML.

A standard XML format, given most (dare I say all) apps should be able to export an xml doc, might lead to better ship builder apps with designs able to be easily cross checked for accuracy and devs making the next app which might be related to trading or combat, knowing that ship design is largely sorted for some editions and will be compatible if say a T4 or T5 ship builder is developed.

Just a thought.
Cheers
 
The ACS format is much easier on the eyes. If one were to go XML, they might as well just go binary and be done with it, since only the computer needs to read the files anyway.
 
XML is useful for human editable machine readable data structures. Almost all currently available OS's have a free text editor which can edit XML files. (On android, it often cannot access them, but if you can access them, you can edit them.)

XML is thus useful for setting options, or creating human-edited templates. For example, an XML structure is a great extensible method of creating a human modifiable equipment list.

As a human readable format, however, it's long, single column, so space inefficient, or a group of paragraphs, which are hard to find tags in. (I say this as someone who still hand-codes their websites. XML is an outgrowth of HTML.)

The compact textual output, however, is easily human readable, and, thanks to monospace formatting, also machine readable by string slicing.

So, XML isn't quite always "better to use binary," but as an output format, its not a great choice.
 
One advantage of XML is the extendible part. A spec can also be written so that you know your XML is a valid model with an XSD file that defines what is allowed and required.

And personally I find XML readable - with the appropriate names for the fields you know what that field is rather than having to know something from outside the document.

That being said, JSON is a bit more lean and still easy to read and is used more for public facing APIs probably (although most web frameworks, or at least the ones I have worked with, can return either one depending on the request without actually writing any code).

Side note: the ACA spec for the CCDA (continuous care document architecture - how different medical systems can transfer medical documents) has a large XSD file. I generated a class from that (there are tools) and it created a 225,000 line C# model. But there are a LOT of rules built in). Sadly there are two big parts for the spec: computer readable one and human, so that there is basically a duplicate of the pure XML in XHTML - they stick an HTML doc inside an XML doc....
 
"Easy on the eyes" always scores in my book, although I always tend to also compress data when it's a custom structure. I like the UWP.

For those few codgers who still believe in XML: note that yes, my app round-trips XML, and also round-trips JSON and YAML. Mainly because these formats, having been around for more than a decade, have LIBRARIES that will dump and parse for me already. It doesn't make sense NOT to support these sorts of things anymore.

ACS, on the other hand, is a compact format because it knows what Traveller needs, and doesn't have to encompass what any other structure might need. It's convention over configuration. It doesn't have to be a dictionary, so it's not.

Add to that the extra little kick that, yes, I want it to be so dang easy to parse that yacc or any of its children aren't necessary to write a parser for it (and yet it's still flexible enough to have one arbitrary-length line-oriented list in it).

There. There's my requirements, hence the format above.

Actually, I adjusted the writer last nite to nearly match the above output. The difference is that I left the hull and armor elements as part of the component list, and bumped out the fixed column widths for volume and quantity. I suspect there is still some tweaking to do, but I'm pretty happy with what's there. Now I have to write the reader.
 
I'll make another comment. This ACS format descended from the Plain Old Ship Component List that we've all used at one time or another in one form or another. In one incarnation it looks like this:

Trader A-HS63 Broadsword MCr519.9

Disposition: In Service
Crew comfort: +0
Passenger demand: -5

Mercenary Cruiser (type F): Using an 800-ton hull, the mercenary cruiser is built to carry a company of lift infantry for corporate or government operations.


Code:
   Tons	 Component                          	  MCr	Notes
-------	 -----------------------------------	-----	--------------------
    800	 Streamlined Hull, lifters          	   50	S, lifters
      8	 Landing legs with pads             	    8	
      0	 Stealth Coating                    	    0	
     16	 Mod AV=64. 2 Kinetic Charged       	    0	R0
     16	 Mod AV=64. 2 Blast Charged         	    0	R0
      0	 Mod AV=32. 1 EMP Charged           	    0	R0
     80	 Plant Fuel (2 months)              	    0	2 months
    199	 Jump Fuel (3  parsecs)             	    0	3 parsec jump, at 66t per parsec
  20.13	 Adv PowerPlant V                   	   61	R6
  12.87	 Adv Maneuver Drive V               	   78	R6
  21.45	 Adv Jump Drive M                   	   65	R3
      9	 Complete Fuel Collection           	  6.5	50 t/hr
      0	 Adv AR Surf Stealth Mask           	  1.5	R0
      0	 2x LR Surf CommPlus                	    5	#2 
      0	 Adv DS Surf Communicator           	  3.5	R0
      0	 2x Mod DS Surf EMS                 	  3.4	#2 R0
      0	 Adv DS Surf Jammer                 	  3.5	R0
      0	 Adv DS Surf Neutrino Detector      	  3.5	R0
      0	 Adv Or Surf Field Sensor           	  1.6	R0
      0	 Adv DS Surf Scope                  	  3.5	R0
     50	 4x Ult AR Bay Missile              	 41.6	#4 R0
      8	 8x Magazine ( Bay Missiles )       	    0	#8 50 x Size-5
    1.2	 10x Ult D T4 Beam Laser ( Firmpoint	   24	#10 R0
   0.24	 2x Ult D T4 Sandcaster ( Firmpoint 	  3.2	#2 R0
      1	 2x Magazine ( Sandcaster )         	    0	#2 50 x Size-5
   0.75	 Ult B Nuclear Damper               	    4	R0
    0.5	 Ult B Meson Screen                 	    4	R0
   4.62	 Adv Computer Model/7 fib           	   78	R0
     60	 Lift Infantry Company              	    3	(70) 3 pl + O3 O2 R5 R3
      2	 2x Damage Control Lockers          	    2	#2 
      2	 2x Medical Low Berth               	    1	#2 
      2	 2x Emergency Low Berth             	    1	#2 10 individuals
      3	 3x Life Support Standard           	    3	#3 10 person-months
      6	 3x Life Support Long Term          	    6	#3 40 person-months
      2	 Counsellor                         	  0.2	
      4	 Surgery                            	    3	
     48	 Spacious Bridge                    	  2.7	6cc 12op 6ws
      4	 Captain's Quarters                 	  0.4	fresher + safe
      4	 XO's Quarters                      	  0.4	fresher + safe
     30	 15x Crew Stateroom ( Double )      	  1.5	#15 1 crew
      4	 4x Crew Common Freshers            	    4	#4 10 crew
     24	 Crew Lounge + Commons              	    0	
      4	 Briefing Room                      	  0.4	inc. 50 Kg safe
    0.5	 Air Lock                           	  0.1	
     12	 Fuel Storage - Lift Infantry       	    0	
     20	 Cargo Hold                         	    0	
      4	 Cargo Lock                         	  0.4	
     84	 14x Adv Grav Troop Carrier-16 ( 4dt	   42	#14 
     32	 4x Vehicle Lock                    	    0	#4
 
So in the above variant of the Plain Old Listing, you've got everything you need to understand a ship, and there are a few useful sections:

There's a header with a title or a QSP or something. Maybe some other various meta-data.

There's a short text description. A comment, if you will.

And there's the component list, mainly for the sake of (1) capability, and (2) volume and price calculations.


The next thing you may notice is, gosh darn it, there's a lot of white space there. If you're like me, you're already thinking you can tighten that baby up a bit. And before you know it, you're including stuff you think would be useful for tasks, and then lining up things into a fixed-column-width format for, you know, machine friendliness. And some of that meta-data is ALWAYS going to be there, so squeeze it onto one line in a compact way... Jack's a donut, you've got something tight, less readable, but rather structured. Downright fascist structure, if I may misuse the term... which is the sort of structure computers like.
 
I'll sometimes use CVS to tighten up white space. A comma can do wonders. But it depends on how many MB the file might reach. I'll always use JSON over XML because of smaller file size.
 
When I was a mainframe programmer, each byte mattered. We didn't store anything in a human readable format. Now that storage is relatively cheap, user's want more and more information.

Cheers,

Baron Ovka
 
It's less about users wanting to see more, that is a presentation issue. Take an XML, JSON or YAML schema and generate a pretty print output.

Programmers however want easy ways to process and manipulate data, ideally using well established libraries and schemas they can visually verify. It is also easier to develop a new app that uses an existing well established schema. You need the key to decipher a custom made schema, while XML, JSON or YAML, are all self explanatory.

With being self explanatory, comes a lot of verbage, but today a coders time is more valuable than compute hardware.
 
Last edited:
Just for laughs, here's a sample of the JSON data I use in my iOS app-in-progress for saving and restoring ship designs. Lots of complexity that can't be condensed into a compressed format. The app supports multiple hulls that may be detachable so every component has a "location". I also create control panels for most systems which can be assigned to consoles. I also have crew divisions and departments with details on individual crew members. Whew!

Code:
[
    
    {
        "ship":
        {
            "accesses":
            [
                
                {
                    "attached":"yes",
                    "controlpanelid":264166,
                    "location":159569,
                    "type":"Personnel Air Lock"
                }
            ],
            "attributes":
            {
                "class":"Vigor",
                "description":"Launch",
                "hullnumber":0,
                "mission":"T - Transport",
                "missionactivity":"Merchant",
                "missionmod1":"P -  Patrol, Plus, Passenger, Mercenary",
                "missionmod2":"None",
                "missionqualifier":"Freight",
                "missionservice":"Commerce",
                "missiontype":"Unscheduled",
                "name":"",
                "techlevel":12
            },
            "barracks":
            [
                
            ],
            "compartments":
            [
                
                {
                    "attached":"yes",
                    "compartmentid":964469,
                    "description":"Bridge",
                    "location":159569,
                    "tons":2.0,
                    "type":"Specialized"
                },
                
                {
                    "attached":"yes",
                    "compartmentid":785182,
                    "description":"Cargo Hold",
                    "location":159569,
                    "tons":5.5,
                    "type":"Storage"
                }
            ],
            "computers":
            [
                
                {
                    "attached":"yes",
                    "brainc4":0,
                    "braines":"no",
                    "braintype":"None",
                    "brainwj":"no",
                    "description":"Main Computer",
                    "location":159569,
                    "model":"1",
                    "powersource":"Power Plant",
                    "stage":"Ultimate",
                    "type":"Electronic"
                }
            ],
            "connectorsets":
            [
                
            ],
            "consoles":
            [
                
                {
                    "attached":"yes",
                    "brainc4":0,
                    "braines":"no",
                    "braintype":"None",
                    "brainwj":"no",
                    "compartment":964469,
                    "description":"Helm",
                    "location":159569,
                    "panels":
                    [
                        
                        {
                            "panel":40
                        },
                        
                        {
                            "panel":940872
                        },
                        
                        {
                            "panel":317132
                        }
                    ],
                    "powersource":"Power Plant",
                    "size":"Standard",
                    "stage":"Ultimate",
                    "type":"Control"
                },
                
                {
                    "attached":"yes",
                    "brainc4":0,
                    "braines":"no",
                    "braintype":"None",
                    "brainwj":"no",
                    "compartment":964469,
                    "description":"Sensors",
                    "location":159569,
                    "panels":
                    [
                        
                        {
                            "panel":773304
                        },
                        
                        {
                            "panel":264166
                        },
                        
                        {
                            "panel":41519
                        },
                        
                        {
                            "panel":520540
                        },
                        
                        {
                            "panel":922606
                        }
                    ],
                    "powersource":"Power Plant",
                    "size":"Standard",
                    "stage":"Ultimate",
                    "type":"Operating"
                }
            ],
            "controlpanels":
            [
                
                {
                    "controlpanelid":40,
                    "description":"Lifters",
                    "location":159569,
                    "number":1,
                    "type":"Fitting"
                },
                
                {
                    "controlpanelid":940872,
                    "description":"Maneuver A TL12 Advanced",
                    "location":159569,
                    "number":0,
                    "type":"IP Drive"
                },
                
                {
                    "controlpanelid":317132,
                    "description":"Fusion A TL12 Ultimate",
                    "location":159569,
                    "number":1,
                    "type":"Power Plant"
                },
                
                {
                    "controlpanelid":41519,
                    "description":"Ult AR Surf Communicator-12",
                    "location":159569,
                    "number":1,
                    "type":"Sensor"
                },
                
                {
                    "controlpanelid":520540,
                    "description":"Adv AR Surf Radar-12",
                    "location":159569,
                    "number":1,
                    "type":"Sensor"
                },
                
                {
                    "controlpanelid":922606,
                    "description":"Adv AR Surf Scope-12",
                    "location":159569,
                    "number":1,
                    "type":"Sensor"
                },
                
                {
                    "controlpanelid":773304,
                    "description":"Standard",
                    "location":159569,
                    "number":1,
                    "type":"Life Support"
                },
                
                {
                    "controlpanelid":264166,
                    "description":"Personnel Air Lock",
                    "location":159569,
                    "number":1,
                    "type":"Access"
                }
            ],
 
Continued:

Code:
            "crewaccommodations":
            [
                
                {
                    "attached":"yes",
                    "location":159569,
                    "quantity":1,
                    "type":"Double Stateroom"
                },
                
                {
                    "attached":"yes",
                    "location":159569,
                    "quantity":1,
                    "type":"Shared Fresher"
                }
            ],
            "crewdepartments":
            [
                
                {
                    "crew":
                    [
                        
                        {
                            "description":"Pilot",
                            "duties":
                            [
                                
                                {
                                    "duty":"Captain"
                                },
                                
                                {
                                    "duty":"Pilot"
                                },
                                
                                {
                                    "duty":"Astrogator"
                                }
                            ],
                            "rank":"Fourth Officer",
                            "service":"Merchant"
                        },
                        
                        {
                            "description":"SysOp",
                            "duties":
                            [
                                
                                {
                                    "duty":"Drive Tech"
                                },
                                
                                {
                                    "duty":"Rad Tech"
                                },
                                
                                {
                                    "duty":"Sensop"
                                },
                                
                                {
                                    "duty":"IT Tech"
                                },
                                
                                {
                                    "duty":"Steward"
                                },
                                
                                {
                                    "duty":"Cargo Handler"
                                }
                            ],
                            "rank":"Steward Apprentice",
                            "service":"Merchant"
                        }
                    ],
                    "divisions":
                    [
                        
                    ],
                    "name":"Crew"
                }
            ],

            "defenses":
            [
                
            ],
            "fuelfittings":
            [
                
            ],
            "fuelstores":
            [
                
                {
                    "attached":"yes",
                    "location":159569,
                    "tons":1.8000000000000000444,
                    "type":"Hydrogen Tank"
                }
            ],
            "grapplesets":
            [
                
            ],
            "hulls":
            [
                
                {
                    "armorcoating":"None",
                    "armorlayers":
                    [
                        
                        {
                            "antilayer":"None",
                            "stage":"Standard"
                        }
                    ],
                    "attached":"yes",
                    "configuration":"Streamlined",
                    "detachable":"no",
                    "fins":"no",
                    "finsfolding":"no",
                    "firmpoints":1,
                    "flotation":"no",
                    "hardpoints":0,
                    "hullindex":0,
                    "hullstructure":"Plate",
                    "hulltype":"Main Hull",
                    "jumpfield":"None",
                    "landinglegs":"no",
                    "landingskids":"yes",
                    "landingwheels":"no",
                    "lifters":"yes",
                    "locationid":159569,
                    "parenthull":-1,
                    "submergence":"no",
                    "tons":20.0,
                    "wings":"no",
                    "wingscollapsing":"no"
                }
            ],
            "ipdrives":
            [
                
                {
                    "attached":"yes",
                    "controlpanelid":940872,
                    "groups":1,
                    "location":159569,
                    "number":1,
                    "size":0,
                    "stage":"Advanced",
                    "type":"Maneuver"
                }
            ],
            "isdrives":
            [
                
            ],
            "lifesupports":
            [
                
                {
                    "attached":"yes",
                    "controlpanelid":773304,
                    "location":159569,
                    "quantity":1,
                    "type":"Standard"
                }
            ],
            "passaccommodations":
            [
                
                {
                    "attached":"yes",
                    "location":159569,
                    "quantity":2,
                    "type":"Double Stateroom"
                },
                
                {
                    "attached":"yes",
                    "location":159569,
                    "quantity":1,
                    "type":"Shared Fresher"
                }
            ],
            "plants":
            [
                
                {
                    "attached":"yes",
                    "controlpanelid":317132,
                    "groups":1,
                    "location":159569,
                    "number":1,
                    "size":0,
                    "stage":"Ultimate",
                    "type":"Fusion"
                }
            ],
            "sensors":
            [
                
                {
                    "attached":"yes",
                    "controlpanelid":41519,
                    "deployable":"no",
                    "extendable":"no",
                    "location":159569,
                    "mount":"Surface",
                    "mountlocation":"Surface",
                    "powersource":"Power Plant",
                    "range":"Attack",
                    "stage":"Ultimate",
                    "type":"Communicator"
                },
                
                {
                    "attached":"yes",
                    "controlpanelid":520540,
                    "deployable":"no",
                    "extendable":"no",
                    "location":159569,
                    "mount":"Surface",
                    "mountlocation":"Surface",
                    "powersource":"Power Plant",
                    "range":"Attack",
                    "stage":"Advanced",
                    "type":"Radar"
                },
                
                {
                    "attached":"yes",
                    "controlpanelid":922606,
                    "deployable":"no",
                    "extendable":"no",
                    "location":159569,
                    "mount":"Surface",
                    "mountlocation":"Surface",
                    "powersource":"Power Plant",
                    "range":"Attack",
                    "stage":"Advanced",
                    "type":"Scope"
                }
            ],
            "vehicles":
            [
                
            ],
            "vessels":
            [
                
            ],
            "weapons":
            [
                
            ]
        }
    }
]
 
You might be able to attach one of them files to a post, Agorski.

For example, one of my ship designs in YAML.
 

Attachments

  • ACS-A2-FS22-Far Trader.yml.txt
    16.5 KB · Views: 3
And the same design in JSON.
 

Attachments

  • ACS-A2-FS22-Far Trader.json.txt
    17.2 KB · Views: 3
And the same design in XML.
 

Attachments

  • ACS-A2-FS22-Far Trader.xml.txt
    12.5 KB · Views: 4
Back
Top