Create the shortest possible obfuscated program that displays the text "Hello World".

In order to be considered an obfuscated program, it must meet at least two of the following requirements:

  • Does not contain the characters: h, l, w and d in any case
  • Does not contain the characters: e, o, r, 0, and 1 in any case
  • Does not contain the characters: 2 or 7


Hello World


Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

/* Configuration */

var QUESTION_ID = 307; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 48934; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;

function getAnswers() {
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answers_hash[id] = a;
      if (!data.has_more) more_answers = false;
      comment_page = 1;

function getComments() {
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();


var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;

function process() {
  var valid = [];
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    var match = body.match(SCORE_REG);
    if (match)
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);

    var lang = a.language;
    if (/<a/.test(lang)) lang = jQuery(lang).text();
    languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link};

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))

  langs.sort(function (a, b) {
    if (a.lang > b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;

  for (var i = 0; i < langs.length; ++i)
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);

body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;

#language-list {
  padding: 10px;
  width: 290px;
  float: left;

table thead {
  font-weight: bold;

table td {
  padding: 5px;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
  <table class="answer-list">
    <tbody id="answers">

<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <tbody id="languages">

<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>

  • 9
    \$\begingroup\$ I guess import in python is not permitted. \$\endgroup\$
    – Alexandru
    Feb 1, 2011 at 0:07
  • 29
    \$\begingroup\$ Does these rules apply to language keywords as well? \$\endgroup\$
    – hallvabo
    Feb 1, 2011 at 13:04
  • 10
    \$\begingroup\$ are those case insensitive restrictions? \$\endgroup\$
    – Rommudoh
    Aug 4, 2011 at 14:22
  • 24
    \$\begingroup\$ Could someone explain why 2 and 7 are not allowed? I'm just curious as I don't see why those were chosen in particular. \$\endgroup\$ Aug 5, 2011 at 23:01
  • 6
    \$\begingroup\$ @trinithis, and others, ASCII character 72 is "H" which is why I chose those two \$\endgroup\$ Sep 18, 2011 at 23:18

145 Answers 145

1 2 3 4


This is a very cheap trick (30 bytes):


Not much to see here.

Rules broken: none (the O.P. said o, not O)

Going really cheap on this one (25 bytes):

Create a file called cONSTAnTINO_ and run:


There's nothing saying about file names being forbidden.

But if we want to go REALLY dirty, just do (10 bytes):


And run a file from a directory called Hello World.

Enough of being cheap!

Here is another attempt (97 bytes):

<?foreach([144,405,650,867,1114,389,1224,1783,2060,2169,2210]as$k=>$v)echo chr($v/(($k+1*2)+$k));

Yeah, pretty huge, right?

Sadly, it breaks 2 rules.

  • 1
    \$\begingroup\$ You were successful in breaking the second restriction in your first one because the OP mentioned "in any case" (but it's only one restriction, so it's fine). But your second and third ones use a standard (forbidden) loophole and break restrictions 1 and 2. \$\endgroup\$ Jul 6, 2015 at 1:19
  • \$\begingroup\$ @KevinBrown Those aren't serious answers. The purpose of those is to show how much I can cut If I go really cheap (a.k.a.: cheat). \$\endgroup\$ Jul 6, 2015 at 1:28

Cardinal, 73 71 68 chars

- xx  Nj kr rx  u  &],
\-%xx,*u,*u,*u,*u ,*u<

My previous, less obfuscated version (73 chars) for better understanding:

>--- ~n*,n*,n*,,n*,n*,n*,n*,n*,n*,n*,
\---%xN  k  r   u  &  ]  u  x  r  j

Start at %, first move to the left, decrement the active value by 3 (---). () reflects the IP upwards, (>) changes the direction to the right. Then decrement by 3 more (---), swap active and inactive value (~). Then read in the char below (n), store it as active value, add the inactive value to it (*) and output the result (,)... rinse and repeat.

‘n’ places the active value of the ip above the arc of the character n, u puts it below the arc of the character u, then picks up the value of the character above (u) or below (n) the “open” side of the letter and stores the value as new active value. The corresponding instructions in horizontal direction are ‘(’ and ‘)’.

Cardinal is an esolang invented in 2010 http://esolangs.org/wiki/Cardinal

The original interpreter has some bugs, but this example works without problems. I recompiled the source to get rid of the worst bugs so far, in case someone is interested.


Ruby, 66

puts ""<<(61+11)<<101<<108<<108<<111<<' '<<(31+56)<<111<<114<<108<<100

It breaks rule 2

Ruby, 43

Also based upon @Nemo157 answer:

puts "Gdkkn~Vnqkc".split("").map(&:succ)*''

It breaks rule 1


CBM BASIC v2.0 (66 characters)

I think Mark's answer, while very clever, verges on cheating as it exploits the lack of lowercase letters in the machine's default non-ASCII character set. Here's a somewhat longer program that doesn't rely on the PETSCII quirk. It breaks only Rule 2.


Swift 2.0, 243 bytes

Works for Swift 2.0 on Xcode 7 and above.

var s = " ".join(["Gdkkn", "Vnqkc"].map({
    var usv = String.UnicodeScalarView()
    for a in $0.unicodeScalars.map({ 
        UnicodeScalar(($0.value + 4 - 3)) }) { usv.append(a) }
    return String(usv)

print(s, appendNewline: false)
  • \$\begingroup\$ Welcome to PPCG, this challenge type is called code-golf, and for that we include the length of our program in bytes/characters in the title. Also, as a side challenge, you should try and get your program as short as possible by removing unnecessary whitespace, newlines etc. \$\endgroup\$
    – Beta Decay
    Jul 6, 2015 at 13:13

C#, 143 bytes

First i put in an array the decimal values for each letter in text

Hello World.

Then in each world i call (char)decimalValue



returns o in C#.

namespace N{class P{static void Main(){int[] i={13*8,69,36*3,36*3,111,119,111,114,19*4,68};foreach(int v in i)System.Console.Write((char)v);}}}
  • \$\begingroup\$ You should say a little something about how this works in your answer. \$\endgroup\$
    – Justin
    Feb 20, 2014 at 19:55
  • \$\begingroup\$ Breaks the rules. Have a look at TimWi's solution. That's how it's done. \$\endgroup\$
    – RobIII
    Feb 21, 2014 at 1:15

Detour, 18 bytes


Basically the same as @gnibbler's answer, only breaks rule 2.

Try it online!

The 19-byte version breaks none of the rules:

Detour, 19 bytes


Try it online!


JavaScript, 77 70 69 characters

This satisfies conditions number 2 and 3.

"H"+([]+![])[4]+"ll"+([]+{})[+!![]]+" W"+([]+{})[+!![]]+([]+!![])[+!![]]+"ld"

a=!![];b=([]+{});c=b[+a];"H"+([]+![])[4]+"ll"+c+" W"+c+([]+a)[+a]+"ld"

a=!![];b=([]+{});c=b[+a];`H${([]+![])[4]}ll${c} W${c}${([]+a)[+a]}ld`

Please help me shorten this up.


Molecule, 7 chars (18 bytes)


Molecule uses Chocolate Compressor to compress strings.
So I just decompress it.


tcl, 104

\u6cmap x {G d k k n \U1F V n q k c} {scan $x %c n;incr n;puts -n\u6Fn\u65w\u6cin\u65 [f\U6Frmat %c $n]}

Almost meets 3 requirements. Unfortunately I am not successful when I try to use directly the char by key pressing Alt+Num 31, representable as:

Dec U-Hex  Oct
\31 \U1F   \037

which happens to have forbidden chars in all number bases!

Available to run on: http://rextester.com/live/GQBHU26987


Ruby, 51 bytes

Chars not used: hlwd27

puts "Ifmmp!Xpsme".chars.map{|i|(i.ord-1).chr}.join

Perl, 33 bytes

print 'Ifmmp Xpsme'=~y/G-t/F-s/r

Breaks rule 2.


perl -E "say 'Ifmmp Xpsme'=~y/G-t/F-s/r"

I think this counts as one byte shorter...


Mathematica 144 Bytes

StringJoin@Insert[ToUpperCase@StringPart[#,1]<>StringPart[#,5-3;;]&/@IntegerString[{349644888483444,656639565449499}/(498331*8*3+3),36]," ",5-3]

This is a pain in Mathematica because so few functions adhere to rules 2 & 3. This answer adheres to rules 1 & 2 and also takes care to do the Capitalization. I couldn't even use the built in Capitalize function. The basic idea is to find the base 10 representation of the string assuming it's in base 36.

as can be seen by running


which yields a handful of built in symbols, only some of which are functions, and none of which are helpful with string manipulation.


A single function solution that came to mind was:

Transliterate["הֶללֳ וֳרלד"]

which translates from Hebrew characters, but as you can see it it violates rules 2 and 3.


PHP, 41 bytes

<?for(;$a='Gdkkn vnqkc'[$p++];print++$a);

Complies with rules 1 and 3.


Ly, 30 bytes


Try it online!

This rotates the codepoints in the string by a decending number and prints them. Meaning, the character in Hello World are pushed onto the stack, then the first one is shifted by 17 and printed. Then the second one is shifted by 16 and printed, etc...

There are shorter ways to do this in Ly, but this is more confusing/obsfuscated so I like it better.

Also, it doesn't meet the second rule, since AFAIK there's no way to output a character without using o.

  1. We need 17 and a 0 on the stack to separate the shift value from the string
4:*`    - pushes "4", duplicates it, multiplies, then increments
    4~  - searches for "4" on the stack, fails and pushes a "0"
  1. Load the shifted "Hello World" string
  1. For each input char, decrement the shift, then decrement the char and print
                   [        ]   - loop while top of stack isn't "0"
                    r,r         - reverse stack, decrement, reverse again
                       4~       - push a "0" on the stack (failed search for "4")
                         I      - copy bottom of the stack to the top
                          -o    - decrement the codepoint and print
                             ;  - halt code (otherwise junk on stack would print)

KonamiCode, 250 bytes

KonamiCode in and of itself is pretty obfuscated, but I modified the normal Hello World code to make it as confusing as possible.



MUMPS, 85 bytes

 x $c(86+33,35-3,34,69+3,98+3,99+9,99+9,99+9+3,35-3,93-6,68+43,69+45,99+9,96+4,33,34)

Try it online!

Meets every rule. The x command (short for xecute (not a typo)) executes its string argument as code. The $c expression builds the string "w ""Hello World!""" out of a list of each character's ASCII code which have been written to avoid including 0, 1, 2, or 7. The w command (short for write) prints its argument "Hello World!" when executed.

The leading space is there so that x is interpreted as a command and not a tag.


Jelly, 7 bytes


Try it online!


Julia 1.0, 27 bytes


Try it online! (\x1e and \2 are special characters, here for legibility)

simply subtract 2 to each character. Rule 2 is not followed


Rattle, 25 bytes


Try it Online!

This meets requirements 1 and 3


Ifmmp!Xpsme                this is a caesar-shifted string of Hello World (H->I, etc.)
           |               take the above string as a variable
            !              disable implicit output
             I             split the string and store its characters in consecutive memory slots   while moving the pointer to the right
              I^           get the length of the string
                P          reset the pointer
                [     ]`   loop n times where n is the length of the string
                 g         get the value in memory at the pointer
                  n        convert the character to its ASCII integer value
                   -       subtract one
                    ,      explicitly output the shifted character
                     >     move the pointer right

..? (291 bytes)

I made interpreter which randomizes instructions and made this.


link to interpreter

This code is single use unless someone gets the same intstructions.


Itr, 15 bytes


the first character in the string is the byte value 0x90

(base 64 u5DK2NjeQK7e5NjIqzI6)

online interpreter


»90ÊØØÞ@®ÞäØÈ« is a "code-literal" containing the doubled byte values of that characters in Hello World (encoded as single bytes)

2: divides all bytes in the code-literal by two.

The result is then implicitly printed to stdout

Itr, 15 bytes

Uses only Ascii characters


Works the same way as the other solution (byte values increased by 6 instead of multiplied by 2)


Morsecco 85 80 bytes

Obfuscated not for every nerd:

.   .... ---- . .-.. .-.. --- -..... -.-.--- --- .-. .-.. -..  -.- .-- -.- - ---

In morsecco, strings are typically Entered as morse code. Because morse code is not case sensitive, it uses the ---- (CH) as Case Hack to toggle the case. This would cost 10 additional bytes for the capital W of World, but here comes a trick: non-existent morse codes get interpreted as Unicode, so we can save some bytes by using -.-.---. Also, the space is coded as Unicode -......

-.- .-- Konverts from .Morse code, -.- - Konverts to Text for Output.


YASEPL, 39 bytes

=n$99++#"H"›#"ll"++9›#" W"›+3›#"ld"

Excel 138

(Not actually a language and not really obfuscated, but why not)


Violates rule #2 tho, as it contains 'o' and 'r'

  • 4
    \$\begingroup\$ it also contains H (rule #1). \$\endgroup\$
    – Andrey
    Jan 18, 2017 at 9:27
  • \$\begingroup\$ 1. CHAR automatically violates 1 and 2. 2. Older Excel versions use CONCATENATE, but besides that, you can use the & operator. I've posted another answer that doesn't break Rule 1. \$\endgroup\$ Jun 15, 2020 at 15:39
1 2 3 4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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