Skip to main content

FACEHARD — native Python port, verbatim clone + CLI

A faithful Python reimplementation of FACEHARD 8.0, Nathan Okun's face-hardened naval armour penetration program (QuickBASIC, 2018). It reproduces both the program's numbers and its exact text output, validated against the generated BASIC working oracle (fh_oracle) by differential fuzzing. Intentional oracle corrections are documented separately.

Two ways to use it: a modern CLI (facehard run/pen/list) and a byte-faithful clone of the original interactive program (facehard emulate). Stdlib-only, pipx-installable.

Versions. The package is versioned independently of the model: this is package 1.0.0, reproducing Okun's FACEHARD 8.0 (8 August 2018). facehard.MODEL_VERSION and facehard --version both report the model version alongside the package version.

Source. Okun's original programs, papers and armour data are published at NavWeaps — The Nathan Okun Collection.

Install

pipx install facehard
facehard --version

CLI

facehard                     interactive wizard (modern menus)
facehard emulate             the ORIGINAL FACEHARD interactive session, verbatim
facehard run   [options]     one impact; --output narrative|limits|plug|metrics|json|all
facehard pen   [options]     penetration thickness at a striking velocity
facehard list  armors|nations|projectiles [--nation N]

run/pen scenario flags: --armor 1-25 --nation 1-8 --proj N -d/--diameter -w/--weight -b/--body-weight -v/--velocity -o/--obliquity; --curved for a strongly curved plate (dome/cylinder/ellipse — enables Okun's curved-plate body-damage rule above 45° obliquity); --soft-cap works|fails answers the original's "do you wish the SOFT AP cap or HOOD to work?" question (only consulted inside the 15–20° shatter zone of mixed results; the header says when it applies); --set NAME=VALUE (repeatable) is the "modify armor plate's parameters" screen (UB, Q, QDAM, CARTWL, CMPND, THNCHL, SOFTSHAT, THKTHN); backing --wood --cement --metal --metal-type --metal-plates; nose loss --remove {none,cap,windscreen,caphead} --windscreen-wt --caphead-wt. run also takes -t/--thickness (the plate to shoot); pen omits it because it computes the thickness defeated.

Library API

from facehard import calc, results, render_results, penetration, names

calc(armor=14, nation=1, proj=18, TA=16, D=16, WT=2700, WB=2048, OB=30).vltru
results(armor=14, nation=1, proj=18, TA=12, D=16, WT=2700, WB=2048, OB=30, VS=2200)
render_results(armor=14, nation=1, proj=18, TA=12, D=16, WT=2700, WB=2048,
               OB=30, VS=2200, show_limits=True)          # verbatim BASIC text
penetration(armor=14, nation=1, proj=18, D=16, WT=2700, WB=2048, V=2500, OB=0)  # 29.5 in

Every numeric menu choice also has a named IntEnum — drop-in for the plain numbers, which stay valid everywhere:

from facehard import penetration, Armor, Nation, USProjectile, projectiles

Nation.UK == 2                                            # original menu numbers, unchanged
penetration(armor=Armor.BRITISH_CA, nation=Nation.USA,
            proj=USProjectile.APC_6IN_MK35_16IN_MK8,      # 16-in Mk 8 (IOWA)
            D=16, WT=2700, WB=2048, V=2500, OB=0)

projectiles(Nation.JAPAN).APC_TYPE91                      # per-nation projectile menus
Armor.JAPANESE_VH.menu_text                               # the original menu line

Nation, Armor, BackingMetal (the metal_type parameter), and one projectile enum per nation (USProjectile, BritishProjectile, GermanProjectile, FrenchProjectile, ItalianProjectile, JapaneseProjectile, AustroHungarianProjectile, RussianProjectile). The short names summarise menu lines that often cover several marks — member.menu_text is authoritative.

All of calc/results/render_results/penetration accept curved=True (strongly curved plate), soft_cap_works=False (the 15–20° soft-cap/hood answer; zomr_applies(...) says whether the original would ask it), and manual armour overrides. results() also carries Okun's trailing rule notes (Results.notes: curved-plate / soft-cap nose-only-shatter / below-NBL notes) that the effective-limit text's "(SEE BELOW)" refers to. calc/results/render_results also accept backing, nose-covering loss (remove, windscreen_wt, caphead_wt), and manual armour overrides (armor_overrides={"Q": 0.8, "UB": 60, ...} for UB/Q/QDAM/CARTWL/CMPND/THNCHL/SOFTSHAT/THKTHN).

Coverage — the whole program

Layer Status
Ballistic limits (N1–N4, H1–H4) ported, 100% vs BASIC
Post-impact results (outcome, exit angle, plug weights, remaining velocity, effective BL) ported, 100%
Verbatim results narrative (RESULTSPRINT + damage flags) ported, word-for-word
Backing (wood/cement/metal) & nose-covering loss (decapping) ported, 100%
Manual armour-parameter overrides ("modify parameters" screen) ported, applies + verbatim
Interactive shell (menus, info pages, prompts, re-run state) ported, verbatim (facehard emulate)

Not reproduced: nothing functional — only the DOS graphics-mode screen clears (cosmetic) differ.

Fidelity — how close to the BASIC?

precision_audit.py (1500 fuzzed examples, deterministic):

  • Zero velocity deviations across 6,818 ballistic-limit and post-impact velocity comparisons.
  • Exit angles agree exactly in the retained 10,000-case differential campaign.
  • The remaining differences are BASIC display rounding of plug weights to one decimal place (maximum 0.05 lb).

The generated working oracle uses double precision and contains the documented post-impact-limit correction in ORACLE_PATCHES.md.

Verbatim-text fuzzers confirm the same at the string level: fuzz_narrative.py 99.97% of result lines, fuzz_emulate.py 99.98% of full-session lines, fuzz_override.py 100% of override sessions — residual diffs are those same sub-unit display roundings.

Layout

Path Role
facehard/ installable package: model.py, emulate.py, cli.py, names.py
fh_oracle compiled BASIC oracle; rebuild via build_qb64.py + QB64-PE
facehard.bas / build_qb64.py the merged BASIC and its generator
ORACLE_PATCHES.md intentional model corrections applied to the generated oracle
facehard_run.py drives fh_oracle, parses its output
facehard_native.py back-compat shim → facehard.model
validate_native.py / validate_results.py limit & post-impact sweeps vs BASIC
precision_audit.py exact deviation audit (identical / off-by-1 / ≥2)
fuzz_native/narrative/emulate/override.py differential fuzzers
reproduce_table4_native.py reproduces the published comparison table, pure Python

Licence

Not open-source. The penetration mechanics and associated IP — including the formulas, decision logic, data tables, and original FACEHARD program flow and text — belong to the estate of Nathan Okun and, per NavWeaps' terms, may not be used commercially without prior written permission. The Python implementation and its original additions are Copyright © 2026 Adrian Beale and are released under the PolyForm Noncommercial License 1.0.0. The combined distribution is for noncommercial use only; commercial use may require permission from both rights holders. See LICENSE and NOTICE.

Release files for facehard 1.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for facehard 1.1.2
File Size Uploaded
facehard-1.1.2.tar.gz 112.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for facehard 1.1.2
File Interpreter ABI Platform
facehard-1.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 225.3 kB

Release files / facehard-1.1.2.tar.gz

Download URL facehard-1.1.2.tar.gz
Size 112.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a8920812bca0bd943b31bf6f69781978d26413916dd3445a3c980b3c1157eb4e
BLAKE2b-256 checksum
How to use checksums
2ad3a6c319221e7ee3e7ff60a2674b207da0ec7b97497c5f73ee793a231b4030
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Release files / facehard-1.1.2-py3-none-any.whl

Download URL facehard-1.1.2-py3-none-any.whl
Size 112.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
90ea04417e95b88ed6d925c62ca7453b88f59443eec814728ef870f4caec7975
BLAKE2b-256 checksum
How to use checksums
9389d6da11e49b9995f00c789704a513c1c762cf0a0ea8d3e8d7b69050af9041
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Release history Release notifications | RSS feed

This release

1.1.2 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page