Fortress was a language being developed by the Sun Programming Language Research Group (R.I.P. Fortress) that had a unique property to it, it was possible to render ("Fortify") programs in different font-styles (i.e. blackboard bold, bold, italics, roman, etc. ). The goal is to represent a one-char Fortress variable in HTML markup.

Here's how the fortification of one-char variables worked (simplified/modified from documentation for code-golfing purposes):

  • If the variable is a repeated capital (i.e. ZZ), it becomes formatted in blackboard bold (π”Έπ”Ήβ„‚π”»π”Όπ”½π”Ύβ„π•€π•π•‚π•ƒπ•„β„•π•†β„™β„šβ„π•Šπ•‹π•Œπ•π•Žπ•π•β„€)
  • If the variable is preceded by an underscore, the variable is rendered in roman font (left alone)
  • If the variable is followed by an underscore, the variable is rendered in bold font (<b>v</b>)
  • If the variable is neither preceded nor followed by an underscore, the variable is rendered in italic font (<i>v</i>)
  • The codepoints of the blackboard bolds are: 𝔸:1D538, 𝔹:1D539, β„‚:2102, 𝔻:1D53B, 𝔼:1D53C, 𝔽:1D53D, 𝔾:1D53E, ℍ:210D, 𝕀:1D540, 𝕁:1D541, 𝕂:1D542, 𝕃:1D543, 𝕄:1D544, β„•:2115, 𝕆:1D546, β„™:2119, β„š:211A, ℝ:211D, π•Š:1D54A, 𝕋:1D54B, π•Œ:1D54C, 𝕍:1D54D, π•Ž:1D54E, 𝕏:1D54F, 𝕐:1D550, β„€:2124. These count as one byte each in your program (if your language of choice can handle these characters at all)

Input will be either a repeated ASCII capital, or a single ASCII letter with either no underscore, a leading underscore, or a trailing underscore (AKA _a_ will not be an input). This is code-golf so lowest byte count wins!

Test cases:

a => <i>a</i>
BB => 𝔹
c_ => <b>c</b>
_d => d
E => <i>E</i>
G_ => <b>G</b>
_H => H
ZZ => β„€

Links: Specification, Direct download of version 0.1 alpha.

Reference implementation (This would be in Fortress, but Fortress doesn't like most of the doublestruck characters, so this implementation is in D):

dstring fortify(string arg) {
    import std.string, std.conv;

    alias D = to!dstring; //Convert to a string that accepts the unicode needed
    dstring BB = "π”Έπ”Ήβ„‚π”»π”Όπ”½π”Ύβ„π•€π•π•‚π•ƒπ•„β„•π•†β„™β„šβ„π•Šπ•‹π•Œπ•π•Žπ•π•β„€"d; //blackboard bold capitals
    string UC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //normal ASCII capitals

    if(arg.length == 1)
        return D("<i>" ~ arg ~ "</i>");
    if(arg[0] == a[1])
        return D(BB[UC.indexOf(arg[0])]);
    if(arg[0] == '_')
        return D(arg[1]);
    return D("<b>" ~ arg[0] ~ "</b>");
  • \$\begingroup\$ I forgot to remove them, sandbox link: codegolf.meta.stackexchange.com/a/13383/55550 \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:00
  • \$\begingroup\$ Are the only uppercase variables the double repeated ones, and are the only lowercase ones the other three? \$\endgroup\$ Jul 25, 2017 at 18:10
  • \$\begingroup\$ Uppercase can be normal, italic, and bold. Lowercase can not be doublestruck. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:13
  • \$\begingroup\$ _____ won't be input. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:15
  • \$\begingroup\$ Oh... So it's not a string of characters we're converting, just a single one? \$\endgroup\$ Jul 25, 2017 at 18:17

4 Answers 4


Python 3.6, 159 131 128 bytes

1 byte saved thanks to @ZacharΓ½

3 bytes saved thanks to @VΠ°lueInk

28 bytes saved thanks to @Rod

lambda s:len(s)<2and f"<i>{s}</i>"or s[0]==s[1]and"π”Έπ”Ήβ„‚π”»π”Όπ”½π”Ύβ„π•€π•π•‚π•ƒπ•„β„•π•†β„™β„šβ„π•Šπ•‹π•Œπ•π•Žπ•π•β„€"[ord(s[0])-65]or[f"<b>{s[0]}</b>",s[1]][s[0]=='_']

Try it online!

  • \$\begingroup\$ len(s)<2 and=>len(s)<2and \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:27
  • \$\begingroup\$ Look at the new edit to the post, π”Έπ”Ήβ„‚π”»π”Όπ”½π”Ύβ„π•€π•π•‚π•ƒπ•„β„•π•†β„™β„šβ„π•Šπ•‹π•Œπ•π•Žπ•π•β„€ count as 1 byte each. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:35
  • \$\begingroup\$ 128 bytes by moving your first condition to the end. \$\endgroup\$
    – Value Ink
    Jul 25, 2017 at 20:34

Ruby, 104 106 105+1 = 105 107 106 "bytes"

Probably works even better in Retina. Uses -p flag.

-1 byte from ZacharΓ½.

gsub /^.$/,'<i>\0</i>'
gsub /(.)_/,'<b>\1</b>'
gsub ?_,''

Try it online!

  • \$\begingroup\$ You forgot JJ, KK, LL, TT, UU, VV and WW.!! (Which is probably why MM gives β„™) \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 18:55
  • \$\begingroup\$ @Zacharý fixed. \$\endgroup\$
    – Value Ink
    Jul 25, 2017 at 18:58
  • 2
    \$\begingroup\$ I think you can save a byte by making π•Š-𝕏𝕐 π•Š-𝕐. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 19:00
  • \$\begingroup\$ You didn't update your TIO link for the 1-byte saving. Also, this fails badly in Retina which uses UTF-16 and so can't translate a single A-Y to a two-char16_t blackbold character. \$\endgroup\$
    – Neil
    Aug 7, 2017 at 19:04
  • \$\begingroup\$ @Neil oops. Fixed link. \$\endgroup\$
    – Value Ink
    Aug 7, 2017 at 20:07

Jelly, 73 bytes

Turns out that not being able to use the BBB letters in the code is quite expensive.

;jβ€œ<>/”ṃ@β€œΒ’Κ f’

A full program taking one argument and printing the result.

Try it online! or see the test suite.


The main entry point is the last line of code ("Main link").

5ŀ”i - Link 1: list of characters, s (length 1 & no underscore)
  ”i - literal character 'i'
5Ε€   - call link 5 as a dyad with s on the left and 'i' on the right

β€œΓΓ±αΉ‘β€™DαΊ‹@β‚¬β€œΒ‘αΈžαΈ„β€™ΕΌβ€œΒΏΒΏΓ†β‚¬Β’Β¬Β΅β€˜+⁽ø³F⁸αΉͺOΒ€+α»‹Β₯Ọ - Link 2: list of characters, s (length 2 & no underscore)
β€œΓΓ±αΉ‘β€™                                 - base 250 literal              1007245
     D                                - to decimal list               [1,0,0,7,2,4,5]
         β€œΒ‘αΈžαΈ„β€™                        - base 250 literal              111673
      αΊ‹@€                             - repeat with reversed @rguments for €ach -> [[111673],[],[],[111673,111673,111673,111673,111673,111673,111673],[111673,111673],[111673,111673,111673,111673],[111673,111673,111673,111673,111673]]
               β€œΒΏΒΏΓ†β‚¬Β’Β¬Β΅β€˜              - code page index list          [11,11,13,12,1,7,9]
              ΕΌ                       - zip together                  [[111673,11],[11],[13],[[111673,111673,111673,111673,111673,111673,111673],12],[[111673,111673],1],[[111673,111673,111673,111673],7],[[111673,111673,111673,111673,111673],9]]
                         ⁽ø³          - base 250 literal              8382
                        +             - addition (vectorises)         [[120055,8393],[8393],[8395],[[120055,120055,120055,120055,120055,120055,120055],8394],[[120055,120055],8383],[[120055,120055,120055,120055],8389],[[120055,120055,120055,120055,120055],8391]]
                            F         - flatten                       [120055,8393,8393,8395,120055,120055,120055,120055,120055,120055,120055,8394,120055,120055,8383,120055,120055,120055,120055,8389,120055,120055,120055,120055,120055,8391]
                                Β€     - nilad followed by link(s) as a nilad:                                                                                    ^
                             ⁸        -   chain's left argument, s  e.g.    "CC"                                                                                 |
                              αΉͺ       -   tail (last character)             'C'                                                                                  |
                               O      -   cast to ordinal                   67                                                                                   |
                                   Β₯  - last two links as a dyad:                                                                                                |
                                  α»‹   -   index into (1-indexed & modular)  8383 (this is at index 67%26=15 -----------------------------------------------------+ )
                                 +    -   add the ordinal                   8450
                                    Ọ - convert from ordinal to character   'β„‚'

αΉͺ - Link 3: list of characters, s (length 2 & underscore at index 1)
αΉͺ - tail (get the first character

αΈ’5ŀ”b - Link 4: list of characters, s (length 2 & underscore at index 2)
αΈ’     - head s (the non-_ character)
   ”b - literal character 'b'
 5Ε€   - call link 5 as a dyad with the non-_ character on the left and 'b' on the right

;jβ€œ<>/”ṃ@β€œΒ’Κ f’ - Link 5, wrap in a tag: element, tagName      e.g. 'a', 'i'
;              - concatenate the element with the tagName          "ai"
  β€œ<>/”        - literal list of characters                        "<>/"
 j             - join                                              "a<>/i"
         β€œΒ’Κ f’ - base 250 literal                                  166603
       αΉƒ@      - base decompression with reversed @rguments
               -   "a<>/i" is 5 long, so 166603 is converted to
               -   base 5 [2,0,3,1,2,4,0,3] with digits "a<>/i"    "<i>a</i>"

i”_+LΒ΅ΔΏ - Main link: list of characters, s (as specified only):
 ”_     - literal '_'
i       - index of '_' in s (1-indexed; 0 if not found)
    L   - length of s
   +    - addition
     Β΅ΔΏ - call link with that number as a monad with argument s
        - implicit print
  • \$\begingroup\$ Fails on input ZZ. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 19:50
  • \$\begingroup\$ Oh, is that in a different place in Unicode? Bizarre choice they made. \$\endgroup\$ Jul 25, 2017 at 19:51
  • \$\begingroup\$ Yeah, doublestruck C H N P Q R and Z are at different places in unicode. \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 19:52
  • \$\begingroup\$ (Read the fifth bullet point) \$\endgroup\$
    – Adalynn
    Jul 25, 2017 at 19:53
  • \$\begingroup\$ LOL, it's fun to see Jelly flop like that! \$\endgroup\$
    – Adalynn
    Jul 26, 2017 at 0:02

JavaScript, 97 chars


Why a language have methods like String.prototype.italics and String.prototype.bold?

Thanks to Neil, save 9 bytes, use [...s] instead of s.match(/./u).

  • \$\begingroup\$ Is this ES6, or ES7? \$\endgroup\$
    – Adalynn
    Jul 26, 2017 at 11:58
  • \$\begingroup\$ u flag in RegExp is ES6 feature. String.prototype.italics and String.prototype.bold are just some legacy features. \$\endgroup\$
    – tsh
    Jul 27, 2017 at 1:37
  • \$\begingroup\$ I knew it was ES6 ... 'cause fat arrows. \$\endgroup\$
    – Adalynn
    Jul 27, 2017 at 1:38
  • \$\begingroup\$ change "ES6" to "ES6 or ES7" in the above comment. \$\endgroup\$
    – Adalynn
    Jul 27, 2017 at 1:54
  • \$\begingroup\$ [...'π”Έπ”Ήβ„‚π”»π”Όπ”½π”Ύβ„π•€π•π•‚π•ƒπ•„β„•π•†β„™β„šβ„π•Šπ•‹π•Œπ•π•Žπ•π•β„€'] should save you some bytes. \$\endgroup\$
    – Neil
    Aug 7, 2017 at 19:06

Your Answer

By clicking β€œPost Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.