Strazin fights Gary from Accounting (who looks like a humanoid
dragon), his boss, on his first day at work! {This was just a
training exercise.} He defeats him in one blow! But Gary says “You
may have beaten me, but Cheryl from HR is the real challenge…” (Dun
dun dun!)
Gary sends us out after four criminal bosses: the Turtle does
protection, the Tiger does gambling, the Bird does illegal information
gathering and trading, and the Dragon does drugs.
We decide to go after the Bird later. We'd have go off planet to the
satellite controlling space station around the planet of the bird
people. On paper it is a telecommunication booster, but he uses it to
steal data. Anyway, he's the hardest to approach, and we need
somebody smart, which is not playing to either of our strengths.
We need to gather hard evidence of crimes, so they can be put away
for ever.
We decide to go after the Tiger. We are going to a casino with
associated brothel, Alpha Blue, under cover. We are offered a hit of
a mild (and legal) drug at registration.
{Drugs are not illegal unless really special: moon sugar, super
cocaine, etc. Crimes: illegal pit fighting where people die, contests
where people are expected to die, etc.}
Yin goes straight to the tables, and breaks even, then gets the
feeling there is a disturbance in the force.
Strazin gets a mental image of a guy going back and to the left
through a secret passage to one of the arenas. Strazin tells Yin
telepathically and they follow the guy to a death match. They've got
five guys going over beams over a death drop, and they're betting on
who survives. We end up in a lower box with the betters. We've got a
martial arts guy, Fister, and Loud Strike, a wanted gun runner, who is
also wanted. {We are wired with audio and video.} Fister and Loud
Strike are talking about going to the private suite of the Tiger to
get the winnings after the match.
The Contestants are: Red & Blue tied for first, then Green & Black
tied, and trailing Yellow. Yin and then Strazin bets on Yellow; none
of the betters can believe it. Then Strazin uses Psychic to assist
Yellow, pushing twice then Green pushed black off in frustration and
lost his balance and fell.
We win the jackpot, and Fister and the other guy take us up to the
Tigers office, where we see a tiger (not The Tiger), who is
very rotund, not at all fit, Fat Tony, who asks if we want blue bucks
(the casino money) or to cash it out now. We keep the blue bucks, for
later, and when he goes to pays recognizes Yin as infamous across the
Galaxy, and a fight breaks out. It turns against us and we flee, Yin
uses Shape-Shifter to go down through the vents in the
floor and Strazin uses Psychic to read their weapon
patterns and to jump out the window and time it to catch the elevator
on the way down. Yin says “We will never talk about this!”
We got 2 XP each, and each get a bonus 1 XP, for meta
reasons.
I added a brutally simple character sheet for OVA: The Anime
Role-Playing Game to my RPG Downloads page. It is for
LibreOffice Calc. There is also a brutally simple PDF generated from
it as well.
I've made some stuff that I've used for some RPGs available for
download. Right now it has reference sheets for several editions of
Big Eyes, Small Mouth (Second Edition Revised, Third Edition, and
Fourth edition) and for OVA: The Anime Role-playing Game.
Unfortunately, pandoc’s (and probably the orginal python docutils’),
formatting of tables from reST is limited and doesn’t let me do
what I need to do.[1]
Here’s an image of the BESM 4E character, Xeksil [2], I played
Wednesday night:
As you can see, it doesn’t fully fill the width of the page, and the
first two columns are too wide for the information they contain.
I’m contemplating changing the program so that the actual tables are
in grofftbl format directly, and insert them into the
generated reST file in .. raw:: ms directives. That locks
me into using pandoc’s groffms macros output, but I
could just write a new version that outputs ConTeXt (C1, C2) if I
ever need one…
As a test, I converted a character and his mecha into raw groffms with tbl output. Here’s an image of that:
As you can see, the tables fill the width of the text entirely and the
first two columns are narrower and the third column expands to fill
the width of the text. I was also able to put double lines before and
after each entity, and put single lines after the headers and before
the total lines.
I think this looks much better.
Note that the first example is on 5.5” by 8.5” page (which I use for
things I’m going to look at on the screen a lot, because it takes up
less space) and the second example is on 8.5” by 11” paper and in two
columns. It was essentially impossible to have pandoc (and I’m
sure docutils) produce 2 column output and have the reST
versions of the tables adapt to the width of the columns. With the
narrower widths of the first two table columns the third table column
is wide enough that I can use pages with two columns.
CPB (who I talked about this with earlier) commented: The data is in
YAML now right? Why not just generate troff?
Because when I write the actual text of things, I prefer reST.
So, for instance, the description of the character or entity I write
in reST. And I like reST for the main documents into
which I include these generated files because then I can output to
HTML too. (Or to ConTexT; I’ve got some documents where I needed
features that ConTexT has and pandoc’s groff -ms output doesn’t
have.)
I’ve already written the character formatting program (named
besm-rst, originally enough) so that it can output the
table version or a terse version where the different sections are in
normal paragraphs, which is useful because it is much more compact.
Adding a version that outputs reST with tables expressed as an
reST.. raw:: ms block that contains the table sections as
groff -mstbl source would just be writing another
version of the output routine, selectable with a command line option.
The original output routine to produce reST grid tables and its
support procedures were 315 lines. The second output routine to
paragraphs and its new support procedures (it uses some of the first
output routine’s support procedures) was 158 lines.
It will be interesting to see how long the troff output will be.
Oh, here is Lieutenant Enyon Boase again, this time in paragraph format:
That’s also a 8.5” by 11” page, and as you can see, it’s much more
compact, but harder for folks to find each individual item. This is
basically the format that was used in the original BESM 1E and 2E
books, and the table based version appeared in BESM 3E and was
continued in 4E.
I think the table format is much easier to read.
Now, when I use the reST table output and generate HTML from it
it looks kinda crude:
However, I think I may be able to fix that with CSS.
The HTML is relatively clean. (It probably doesn't really need the
width specifications in the colgroup element, but pandoc puts
those in.)
That’s actually six tables. If I wrap them in one div with a
particular class I think I can get them formatted right.
CPB commented: CSS supports printing.
Yes, there is actually at least one commercial document formatting
system that uses CSS for sophisticated print output, much more
elaborate than what the browsers support, I think. And there is at
least one open source solution, weasyprint, that uses CSS to produce
PDF.
But I know tbl better than CSS. 😉
I do have a need for good looking output html for the output of the
program: so I can put it on my blog! It would be better than images
in cases where I’m not actually comparing the PDF output of various
things.
Well, it took me longer than I expected to write the new version of
the output routines for embedded tbl in rst: 4¼ hours. After
the first 2 hours I was fried (it had already been a long day): if I
had stopped then I probably could have finished it the next day in an
hour. Oh well. The new output routine and its new supporting
routines were 208 lines long.
Here's an image of the page produced (probably from the same YAML
file; I have a couple, since one of them was an early test file for
besm-rst) using the new output routine, with reST
output with tbl output in .. raw:: ms, pulled from the
document with all the pregenerated characters:
And for reference, here is the YAML version of Enyon Boase:
And here is the YAML version of his FV2021 Coleopteran:
----name:FV2021 Coleopteranpage:BRCS, p. 94=95description:|A three-metre talk British-built humanoid combat walker used bythe Canadians on Mars. They use a new “mind-interface”neuro-helmet that makes the mecha very agile. However, if adifferent pilot wants to use the mecha, the neuro-helmet must be“retuned” to their brain waves — this takes a full day; untilthen, halve the Defence Mastery and Combat Technique: LightningReflexes Attribute bonuses. The mecha are painted standardcolours: UN white, with sky-blue helmets.derived:-name:Health Pointsvalue:80attributes:-name:Featureslevel:1points:1details:"Radio,InertialNaviagion"-name:Ground Speedlevel:3points:3details:Up to 50 kph-name:Armourlevel:3effective:4points:6limiters:-"UniqueLimiter:Partial:Thin"details:|Hit thin area with called shot for half Armour Rating; 20 AR;20 Health Points-name:Combat Techniquelevel:2points:2details:"LightningReflexes:majoredgeonInitiativerolls"-name:Defence Masterylevel:2points:2details:+2 to Defense Combat Value-name:Resilientlevel:6points:12details:|Space: low pressure, high pressure, intense cold, intenseheat, radiation, lack of air-name:Supersenselevel:4points:4details:Sensors, range 10 km-name:Superstrengthlevel:2points:8details:|Lift 500 kg (a horse); +10 Unarmed Combat Damage;+2 Muscle Weapons Damage-name:Toughlevel:6points:6details:+60 Health Points-name:"Weapon:Railgun"level:12effective:9points:24details:|Damage Modifier ×9; Range 10 km; fails and cannot be usedagain on natural 2 or 3enhancements:-[Range,5]limiters:-[Unreliable,2]-name:"Weapon:RocketPod"level:14effective:9points:14details:|Damage Modifier ×9; Autofire: 1 hit if attack exceeds defenceby 0–3, 2 hits if it exceeds by 4–6, 3 hits if it exceeds by>7–9, etc.; Area 3m radius; Range 1 km; 3 shots; Can bedeflected or destroyed for 1 round; Alternate attack: costhalvedenhancements:-[Autofire,3]-Area-[Range,4]limiters:-[Charges,2]-Stoppable-name:"Weapon:PlasmaFist"level:11effective:12points:11details:|Damage Modifier ×12; Muscle Weapon; 6 shots; Alternate attack:cost halvedlimiters:-Chargesdefects:-name:Awkward Sizerank:2points:-4details:|Size 2: Medium: +2 to be hit for every size attacker issmaller, −2 to be hit for every size attack is larger, 1.5–8tonnes, big horse to bigger than an elephant-name:Conditional Ownershiprank:1points:-1details:UN Army ownership-name:"SpecialRequirement:Frequentmaintenance"rank:1points:-3
The git repo with this program and some test data is on github.
Enyon Boase is a pregenerated character that I came up for my
BESM 2ER rewrite of the BESM 1E adventure “Red
Planet, Blue Helmets”, from Big Robots, Cool Starships, which
I'm now converting to BESM 4E. The FV2021 Coleopteran is
also from that adventure.
I got an interesting game yesterday, and finished reading it today:
the 1991 Lord of the Rings Adventure Game from Iron Crown
Enterprises, which was the first holder of the Tolkien franchise
for RPGs.
ICE got its start with Rolemaster, which started as a detailed
add-on combat system for D&D and developed into a very detailed RPG of
its own, based on open-ended d100 rolls: high is good and on very
high or low rolls you roll again and add the new roll for high or
subtracted for low, continuing infinitely in either direction.
ICE then got the Tolkien franchise and developed Middle-Earth Role
Playing (MERP) as a slightly simplified RPG for those who wanted to
play in Middle Earth, but did not want all the complexities of the
full Rolemaster system. The adventures were written in such a way that
you could play them either with Rolemaster or MERP, and had some short
guidelines to help the GM adapt them for other games. They had a lot
of success and their Middle Earth products were extensive and highly
regarded.
Lots of folk used them with other RPG systems. (I bought several for
the ideas.)
Later in their run, ICE wanted to tap the larger Tolkien readership and
so wrote the Lord of the Ring Adventure Game as a much simpler
game that they hoped would draw interested readers and the viewers of
the animated Hobbit and Lord of the Rings.
(I have fond memories of the animated Hobbit, though I knew it only
through reading the graphic novel adaptation that used art from the
movie when I was at my uncle and aunt's place in New York one summer.
I finally saw it, probably on TV some years later.)
Anyway, the Lord of the Rings Adventure Game (LOR hereafter, as seems
to be customary) comes in a box with a 32 page rulebook, a 64 page
adventure with 6 pre-generated characters, a 32 pamphlet of 4 pages of
backstory for the 6 pregens and area maps for the adventure, several
poster sized maps, including a nice color one of Middle Earth, and
(missing in my copy, as the seller had noted in the description) 2
six-sided dice and a sheet of standup cardboard figures of people and
creatures and the pregens.
Characters have 12 stats: 6 capabilities (Strength, Agility,
Intelligence, Movement, and Endurance) and 6 skills (Defense, Melee
Offensive Bonus, Ranged Offensive Bonus, General, Subterfuge,
Perception, and Magical). The value of each of these is called a
bonus, and can be less than zero.
You pick one of 9 character types (Hobbit Scout, Elf Scout, Human
Warrior, Dwarf Warrior, Elf Warrior, Human Ranger, Half-elf Ranger,
Human Bard, and Elf Bard), which sets your equipment and capability
values and starting skill values, and then you have six +1 bonuses to
add to your skills as you choose, no more than +3 to any one skill.
If you have +1 or more in magic you get two spells per +1 bonus. Some
of your equipment gives bonuses to your stats. I'll note that your
character type doesn't restrict what you can do: if you want your
Warrior to be able to use magic, put some of your starting skill
bonuses into Magical! And they don't really have much to do with what
your characters occupation is: someone who takes one of the Warrior
character types can be a merchant, someone who takes one of the Scout
character types can be a healer. It is all in how you assign your
starting skill bonuses.
Your character type sets your Endurance (basically your hit points),
with the dwarf warrior having the most at 60 points and the elf bard
the least at 30 points.
There are 15 spells, all with a fairly reasonable balance between
keeping with the magic seen in the novels, which is to say not
tremendously powerful, and what one would expect from a fantasy RPG.
The spells are Strength, Shield, Speed, Balance, Camouflage,
Concentration, Item Analysis, Clairvoyance, Healing, Luck, Protection
from Magic, Sustenance, Calm, Charm Animal, and Fire Bolt. Magic
items typically add a plus to a stat, or let you do something you
couldn’t before.
Maneuvers are how you use your stats. Some, like climbing a tree have
a set difficulty. Others the GM sets the difficulty, from Routine (4)
to Absurd (18).
You roll 2d6 plus a stat bonus versus a target number or an opponent’s
roll. Meet or exceed an unopposed roll to succeed, while you can tie
on opposed rolls. In combat you take the attacker’s Offensive Bonus
minus the defenders Defensive Bonus and roll 2d6 and look the result
up in a chart to see how much damage is done and whether the defender
is knocked unconscious or killed outright.
Activities are things that are normally automatically successful if
you have the equipment and time (tying up a captive, setting up camp,
digging a ditch), but turn into GM moderated maneuvers if you don’t
have the time or equipment (digging a ditch to hide in before the
opponents you want to ambush show up).
There are 14 action sequences. These things like combat (one of the
action sequences) where there is a general sequence you follow to do
something, from sneaking through a town at night to tracking through a
wilderness or ambushing an enemy. I like how these are written up as
a standard sequence of things to do and consider, just like how combat
is done in most system.
These action sequences can be adjusted by the GM for circumstances and
they encourage you to make up your own. You might make one up for
when someone is wanting to convince a crowd of something. They are
multi-step procedures for doing something. I think they would be
quite useful.
You get Experience Points (EP) for successful maneuvers depending on
how hard the target number was, for every point of damage inflicted,
with unconsciousness and killed results worth more, and for every
point of damage the caster of a spell takes to cast the spell. (Every
spell costs the caster Damage to cast!). You also get EP for good
ideas and for the group accomplishing significant goals.
The included adventure is a mix of programmed sequences to help the
new GM and players learn the system, where the choices the players
make determines what section you turn to next, and the sections are
broken up into action sequences and the results determine which
section the players go to next, GM notes on how to run or adjust
things, and descriptions of what happens.
I do notice that each of the pregens has a special ability: finding
lost items or people, eidetic memory, knowing if any creature within a
20 foot radius is aligned with forces of darkness, healing wounds
faster, being unusually skilled at bargaining and negotiation, and
always knowing which way is north and can follow known routes
perfectly. But there is no rule for assigning these to characters. I
imagine that if the GM wanted to have special abilities for other
characters the GM and the players should come up with them.
The rules encourage you to use figures or counters to represent
characters in combat, and movement is given in inches, to be measured
on the map, if you draw one, or on the table if you just set out the
figures at the right distances. You could easily use a battle map
with a grid, if you have one. Movement at a walk is 50 feet plus 10
feet multiplied by the characters Movement bonus.
Anyway, I like it. I hope to run it this year for Christmas, if all
goes well.
There is, of course, a Wikipedia page about it, but it is even
briefer than this post.
There is a compatible game, The Middle-Earth Adventure Game
(MEAG), that was designed by Brian Gross and J.R. Gracen. I knew of
it before I got the LotRAG, it seems to be a generalization and
expansion, and thus a little more complicated, but it doesn't look
too complicated. I'll read it and report what I think of it.
I wrote a post about using the old ada-mode.el that used to be
distributed with Emacs because I couldn't get the newer,
separate package version to work for me.
Well, this morning when I pulled up an Ada file in Emacs version
28 there were two problems:
The information to invoke ada-mode on Ada files was not in the
auto-mode-alist variable in Emacs. That was easy
enough to fix: add .ada, .ads, and .adb to
auto-mode-alist (and .gpr, too, since Ada mode works
for gprbuild files as well):
When I tried to do any indentation emacs reported an error,
with the error message “End position is smaller than start
position”. Eventually I tracked this down to a call to
parse-partial-sexp in ada-in-open-paren-p. It turns out
that somewhere after Emacs version 27.2 was released the
Emacs developers added a check to parse-partial-sexp to
ensure that the FROM argument (which indicates where in the
buffer to start parsing) was less than the TO argument (which
indicates where in the buffer to stop parsing).
Drat. Drat. Drat. Well, looking at the code it was clear that
since ada-in-open-paren-p is explicitly searching backwards
that TO would always be smaller than FROM. So I could
just transpose the s-expressions that found those two values. I
tried it, and it worked!
At that point I realized that I had committed to maintain the old
version of ada-mode, at least for myself, and that I'd already talked
about it on my blog and it was small step from there to setting up a
GitHub repository with the old code, adding an issue describing the
problem, adding a commit with the fix, and then writing this blog
post.
Somewhere, someone is laughing and enjoying the schadenfreude. Maybe
this will help someone else.
And since I already have a GitHub repository, I ought to document the
first problem and since it is a documentation problem, put a mention
in the README.
I finished reading Dyskami Publishing’s Demonicity tonight (PDF). I liked the document design and found it easy to read, except the “Demon City” two page spread which I found a pain to read because of the body font. I liked the artwork; it was not particularly anime or manga like, unlike BESM Fourth Edition. There were a few typos, missing words, and other minor mistakes, but there was only one that hindered comprehension, and that one I figured out eventually from the context. The rules are easy to understand.
The setting of Demonicity is the titular “Demon City”, a city that is the location of an attack by demons from an different world/dimension. It is obviously inspired by their earlier licensed RPG, Demon City Shinjuku, which I quite liked.
Demonicity has a very interesting stripped down version of the Tri-Stat system that makes character generation and play much simpler. In some ways it reminds me of BESM First Edition, though it is even simpler. The three Stats are Body, Mind, and Soul, of course, so that’s the same. There are also Attributes, which are the special things a character can do. Stats can be determined randomly or assigned by the player, and they and Attributes always cost points. And there are some Derived Values: Combat, Health, Sanity.
You roll 2d6 and add a stat or a derived value (like Combat), plus optionally an Attribue’s level, and compare the result to a target number or an opposed roll. Things that make something easier are Edges: you get an extra die or two on your dice roll, and you keep the highest two. Things that make something harder, like trying to use two weapons at once without training, gives you Obstacles: an extra die or two on your dice roll, but you keep the two lowest rolls. Edges cancel out Obstacles and vice versa. Combat is theater of the mind.
Demoicity’s version of BESM’s Attributes are quite stripped down. There are only nine: Adaptability, Damage, Demonicity, Fighting, Knacks, Movement, Resistance, Resources, and Skills. These are bought in levels as usual, but associated with each are a number of Foci (as many as one has levels in the Attribute), which gives the character a special ability. Demonicity is the Attribute that allows a character to do most of the more impressive supernatural things, for instance. A few of its Foci are Healing, Meld (mere with inanimate objects), and Shadow Form. The Fighting Attribute makes a character more proficient at combat than their Stats would suggest, and it’s Foci specify which kinds of Fighting you are better at (Melee or Ranged), or makes it easier to do certain things in combat (Blind Fighting, Two Weapons). Generally, an Attribute’s level adds to dice rolls for things associated with it, while having an appropriate Foci means that you get an Edge. After every session characters get a few points to increase their Stats and Attributes.
The rulebook is only 32 pages long and has a thicker card stock cover. It is accompanied by six one page adventures with related art on the back and by six pre-generated characters with an image of the character on the back, all on card stock. There are also four six-sided dice. The box everything comes in seems sturdy. In general the production values are quite good.
People who are confident with their improvisation skills can probably run the adventures easily, but those who like more details will probably want to do a bit more preparation. The adventures appear designed to be easily linked into a six episode mini-campaign, or can form the backbone of a longer campaign if the GM writes their own adventures.
I like the inclusion of the pre-generated characters and the one page adventures. They allow a gaming group to pick the game and start playing with little or no preparation. And the simplified rules make it easy to learn the game, and to create characters if the gaming group doesn't want to use the pre-generated characters. I think this makes it an excellent pick-up-and-play game.
I would like to have seen something like the adventure generators from various Savage Worlds setting books or Toon and its supplements. They allow the GM who is stuck for ideas to come up with something quickly when inspiration is lacking. But it would have been difficult to fit in the constraints of the product. Perhaps on another sheet of card stock, since I can’t see deleting anything from the rulebook? BESM and Tri-Stat generally have very little procedural support for coming up with NPCs, scenes, adventures, etc., and I think an adventure generator would be a useful addition. Of course, having the example adventures to give an idea of what Demonicity adventures would be like is very useful.
All in all, I quite like Demonicity and hope to play it soon. My only reservations are about the price of this game and the other two Tri-Stat boxed games, Pixies and Wyrms. Forty-five retail dollars Canadian for the physical product seems like a lot. The PDF seems more reasonable at 15 dollars.
When I did a search for “splitting strings on a delimiter in the Ada
programming language” recently I did not get many useful results.
Eventually I stumbled over GNAT.String_Split which is an
instantiation of the generic package GNAT.Array_Split. I also
finally foundGNATCOLL.Strings_Impl and GNATCOLL.Strings, its
default instantiation, which looks especially interesting, contains
a split implementation, and which seems to be designed to be a more
efficient string implementation than than Ada.Strings.Unbounded.
However, those are all a little complicated, so it might be
appropriate to show a simpler implementation.
The String type in Ada is a array of characters. Once
declared, a String variable always has the same length. That
means that all the strings in an array of strings have to be the same
length. However, an access (Ada's version of a
pointer) to a String can point to a string of any length, so for
this version we'll return an array of pointers to String.
withAda.Strings;useAda.Strings;withAda.Strings.Fixed;useAda.Strings.Fixed;withAda.Text_IO;withAda.Integer_Text_IO;useAda.Integer_Text_IO;proceduresplit_fixedis-- Ada.Text_IO contains a type, Count, that would conflict with-- the function Ada.Strings.Fixed.Count, so don't "use Ada.Text_IO;"-- instead, make a package the gives it a shorter name, and use all its-- procedures with that as the prefix.packageATIOrenamesAda.Text_IO;typeString_PtrisaccessString;typeVectorisarray(Naturalrange<>)ofString_Ptr;-- Allocate a new String in a storage pool, initializing it to S, and-- returning an access to it (a pointer).function"+"(Source: inString)returnString_PtrisSP:String_Ptr:=newString'(Source);beginreturnSP;end"+";functionSplit(S: String;Pattern: String)returnVectorisStart:Positive:=1;Position:Natural;Num_Parts:Natural:=Count(S,Pattern)+1;V:Vector(1..Num_Parts);I:Natural:=0;beginwhileStart<=S'LengthloopPosition:=Index(S,Pattern,Start);exitwhenPosition=0;I:=I+1;V(I):=+S(Start..Position-1);-- The pattern can be longer than one character.Start:=Position+Pattern'Length;endloop;I:=I+1;V(I):=+S(Start..S'Last);returnV;endSplit;procedurePrint_Vector(Label: String;S: String;V: Vector)isN:Natural:=0;beginATIO.Put_Line(Label&": """&S&"""");forIinV'First..V'LastloopN:=N+1;ATIO.Put(" Part ");Put(N,0);ATIO.Put(": """);ATIO.Put(V(I).all);ATIO.Put_Line("""");endloop;endPrint_Vector;S1:String:="Hello, World!|I am fine!|How are you?";V1:Vector:=Split(S1,"|");S2:String:="";-- Empty string.V2:Vector:=Split(S2,"|");S3:String:="|";-- Just one of pattern.V3:Vector:=Split(S3,"|");S4:String:="||";-- Just two of pattern.V4:Vector:=Split(S4,"|");S5:String:="one";-- Just one part.V5:Vector:=Split(S5,"|");-- The delimiter doesn't have to be one character.S6:String:="foo<=>bar";V6:Vector:=Split(S6,"<=>");beginPrint_Vector("S1",S1,V1);Print_Vector("S2",S2,V2);Print_Vector("S3",S3,V3);Print_Vector("S4",S4,V4);Print_Vector("S5",S5,V5);Print_Vector("S6",S6,V6);endsplit_fixed;
Here's the output:
S1: "Hello, World!|I am fine!|How are you?"
Part 1: "Hello, World!"
Part 2: "I am fine!"
Part 3: "How are you?"
S2: ""
Part 1: ""
S3: "|"
Part 1: ""
Part 2: ""
S4: "||"
Part 1: ""
Part 2: ""
Part 3: ""
S5: "one"
Part 1: "one"
S6: "foo<=>bar"
Part 1: "foo"
Part 2: "bar"
The Bounded_String type in Ada has a maximum capacity and a
current length. You instantiate a new package for each different
maximum capacity that you want, producing a different type for each.
You can assign any string smaller than or equal to the maximum length,
and the current length is recorded.
withAda.Strings;useAda.Strings;withAda.Strings.Bounded;useAda.Strings.Bounded;withAda.Text_IO.Bounded_IO;withAda.Text_IO;useAda.Text_IO;withAda.Integer_Text_IO;useAda.Integer_Text_IO;proceduresplit_boundedispackageB_Stringis newAda.Strings.Bounded.Generic_Bounded_Length(Max=> 128);useB_String;packageB_String_IOis newBounded_IO(B_String);useB_String_IO;typeVectorisarray(Naturalrange<>)ofBounded_String;functionSplit(S: Bounded_String;Pattern: String)returnVectorisStart:Positive:=1;Position:Natural;Num_Parts:Natural:=B_String.Count(S,Pattern)+1;V:Vector(1..Num_Parts);I:Natural:=0;beginwhileStart<=Length(S)loopPosition:=Index(S,Pattern,Start);exitwhenPosition=0;I:=I+1;V(I):=Bounded_Slice(S,Start,Position-1);-- The pattern can be longer than one character.Start:=Position+Pattern'Length;endloop;I:=I+1;V(I):=Bounded_Slice(S,Start,Length(S));returnV;endSplit;procedurePrint_Vector(Label: String;S: Bounded_String;V: Vector)isN:Natural:=0;beginPut_Line(label&": """&S&"""");forIinV'First..V'LastloopN:=N+1;Put(" Part ");Put(N,0);Put(": """);Put(V(I));Put_Line("""");endloop;endPrint_Vector;S1:Bounded_String:=To_Bounded_String("Hello, World!|I am fine!|How are you?");V1:Vector:=Split(S1,"|");S2:Bounded_String:=To_Bounded_String("");-- Empty string.V2:Vector:=Split(S2,"|");S3:Bounded_String:=To_Bounded_String("|");-- Just one of pattern.V3:Vector:=Split(S3,"|");S4:Bounded_String:=To_Bounded_String("||");-- Just two of pattern.V4:Vector:=Split(S4,"|");S5:Bounded_String:=To_Bounded_String("one");-- Just one part.V5:Vector:=Split(S5,"|");-- The delimiter doesn't have to be one character.S6:Bounded_String:=To_Bounded_String("foo<=>bar");V6:Vector:=Split(S6,"<=>");beginPrint_Vector("S1",S1,V1);Print_Vector("S2",S2,V2);Print_Vector("S3",S3,V3);Print_Vector("S4",S4,V4);Print_Vector("S5",S5,V5);Print_Vector("S6",S6,V6);endsplit_bounded;
Here's the output:
S1: "Hello, World!|I am fine!|How are you?"
Part 1: "Hello, World!"
Part 2: "I am fine!"
Part 3: "How are you?"
S2: ""
Part 1: ""
S3: "|"
Part 1: ""
Part 2: ""
S4: "||"
Part 1: ""
Part 2: ""
Part 3: ""
S5: "one"
Part 1: "one"
S6: "foo<=>bar"
Part 1: "foo"
Part 2: "bar"
The Unbounded_String type in Ada grows dynamically as needed,
but is not as time efficient as fixed strings or bounded strings.
For this version, we'll use Ada.Containers.Vectors for a
dynamically expending vector, rather than a fixed size vector.
withAda.Strings.Unbounded;useAda.Strings.Unbounded;withAda.Text_IO;useAda.Text_IO;withAda.Integer_Text_IO;useAda.Integer_Text_Io;withAda.Text_IO.Unbounded_IO;useAda.Text_IO.Unbounded_IO;withAda.Containers.Vectors;proceduresplit_unboundedispackageUnbounded_String_Vectorsis newAda.Containers.Vectors(Natural, Unbounded_String);useUnbounded_String_Vectors;function"+"(Source: inString)returnUnbounded_StringrenamesTo_Unbounded_String;subtypeUBS_VectorisUnbounded_String_Vectors.Vector;functionSplit(S: Unbounded_String;Pattern: String)returnUBS_VectorisStart:Positive:=1;Position:Natural;Num_Parts:Natural:=0;V:UBS_Vector;beginwhileStart<=Length(S)loopPosition:=Index(S,Pattern,Start);exitwhenPosition=0;Append(V,Unbounded_Slice(S,Start,Position-1));-- The pattern can be longer than one character.Start:=Position+Pattern'Length;endloop;Num_Parts:=Num_Parts+1;Append(V,Unbounded_Slice(S,Start,Length(S)));returnV;endSplit;procedurePrint_UBS_Vector(Label: String;S: Unbounded_String;V: UBS_Vector)isN:Natural:=0;beginPut_Line(Label&": """&to_string(s)&"""");forIinV.First_Index..V.Last_IndexloopN:=N+1;Put(" Part ");Put(N,0);Put(": """);Put(V(I));Put_Line("""");endloop;endPrint_UBS_Vector;S1:Unbounded_String:=+"Hello, World!|I am fine!|How are you?";V1:UBS_Vector:=Split(S1,"|");S2:Unbounded_String:=+"";-- Empty string.V2:UBS_Vector:=Split(S2,"|");S3:Unbounded_String:=+"|";-- Just one of pattern.V3:UBS_Vector:=Split(S3,"|");S4:Unbounded_String:=+"||";-- Just two of pattern.V4:UBS_Vector:=Split(S4,"|");S5:Unbounded_String:=+"one";-- Just one part.V5:UBS_Vector:=Split(S5,"|");-- The delimiter doesn't have to be one character.S6:Unbounded_String:=+"foo<=>bar";V6:UBS_Vector:=Split(S6,"<=>");beginPrint_UBS_Vector("S1",S1,V1);Print_UBS_Vector("S2",S2,V2);Print_UBS_Vector("S3",S3,V3);Print_UBS_Vector("S4",S4,V4);Print_UBS_Vector("S5",S5,V5);Print_UBS_Vector("S6",S6,V6);endsplit_unbounded;
Here's the output:
S1: "Hello, World!|I am fine!|How are you?"
Part 1: "Hello, World!"
Part 2: "I am fine!"
Part 3: "How are you?"
S2: ""
Part 1: ""
S3: "|"
Part 1: ""
Part 2: ""
S4: "||"
Part 1: ""
Part 2: ""
Part 3: ""
S5: "one"
Part 1: "one"
S6: "foo<=>bar"
Part 1: "foo"
Part 2: "bar"
About
Lacking Natural Simplicity is one, not particularly flattering,
definition of sophisticated.
This blog chronicles my journey through our at times too complicated
and sophisticated world.
This site uses no cookies directly, but I expect the Disqus comments use cookies at disqus.com.