21
\$\begingroup\$

Given a word, decide if it is an ambigram.

When rotated:

b > q
d > p
l > l
n > u
o > o
p > d
q > b
s > s
u > n
x > x
z > z

Assume only lowercase letters as input.


Test input:

this,
another,
lll,
lol,
dad,
dab,
dap,
wow,
ooi,
lollpopdodllol,

Ones That Should Return Truthy Values:

lll,
lol,
lollpopdodllol,

Note that input and output can be taken in any format (except for Standard Loopholes).

\$\endgroup\$
12
  • 7
    \$\begingroup\$ This makes absolutely no sense to me. Can you work through an example perhaps? \$\endgroup\$
    – chunes
    Jun 2 at 0:39
  • 8
    \$\begingroup\$ I suggest a test case where the characters are rotationally symmetric but the word isn't, like pppd. This prevents simple subset solutions from passing all test cases. \$\endgroup\$
    – chunes
    Jun 2 at 1:24
  • 2
    \$\begingroup\$ pod is another truthy example. \$\endgroup\$
    – stanri
    Jun 2 at 10:16
  • 2
    \$\begingroup\$ a/e is a close match \$\endgroup\$
    – user253751
    Jun 2 at 11:28
  • 34
    \$\begingroup\$ These are not palindromes, they are ambigrams \$\endgroup\$ Jun 2 at 14:04

22 Answers 22

17
\$\begingroup\$

Factor + flip-text, 34 bytes

[ dup flip-text "ʃ""l"replace = ]

Attempt This Online!

Factor has a vocabulary for ʇxǝʇ ᵷuᴉddᴉʃɟ, but for some reason it turns l into ʃ, so I have to change it back.

\$\endgroup\$
12
\$\begingroup\$

Python, 70 69 bytes

-1 byte thanks to Kyle G

lambda s:[i*(i in b'losxz')or b'dbq0pnu0'[i%8]for i in s][::-1]==[*s]

Attempt This Online!

Accepts a bytes object as input.

Explanation

[... for i in s] Build an array mapping each letter i of s to...

i*(i in b'losxz') ... i, if i is one of the letters that should remain unchanged, or...

b'dbq0pnu0'[i%8] ... its rotation. Since the rotatable letters have unique code points mod 8, we can use that to index into a string of possible rotations. Note that multiple letters may map to a given letter (e.g. u and e both map to n), but that's fine since only the rotatable letters will form a reversible map (e.g. b->q->b)

[...][::-1]==[*s] Reverse the new array and compare to the original string, unpacked into an array.

\$\endgroup\$
2
  • \$\begingroup\$ @solid.py I added an explanation. The most interesting golfing tricks are probably the ord(i)%8 and the string unpacking ([*s]) \$\endgroup\$ Jun 2 at 14:37
  • \$\begingroup\$ you can save a byte by requiring the input to be a bytes or bytearray object instead of a string \$\endgroup\$
    – Kyle G
    Jun 2 at 18:55
10
\$\begingroup\$

Charcoal, 28 bytes

θ⟲T⁴≔⪫KAωη⎚⁼θΦη№bdlnopqsuxzι

Try it online! Link is to verbose version of code. Explanation:

θ

Print the input string to the canvas.

⟲T⁴

Rotate the canvas by 180°, transforming the characters as required.

≔⪫KAωη

Read the transformed rotated string back from the canvas.

Clear the canvas.

⁼θΦη№bdlnopqsuxzι

Compare the two strings, and check that all of the letters in the string were valid. (This check costs half of the byte-count, ugh.)

\$\endgroup\$
1
  • 5
    \$\begingroup\$ right tool for the job ;) \$\endgroup\$
    – att
    Jun 2 at 1:22
8
\$\begingroup\$

Vyxal, 23 bytes

ka«ƛG₈₀2ǔvȯF±ɾF)ǍrT«ĿṘ⁼

Try it online or verify all test cases.

How?

ka«×¢₇}Ẇ₇]↲βjEβ&ɾṗµ«ĿṘ⁼
ka                      # Push the lowercase alphabet
  «×¢₇}Ẇ₇]↲βjEβ&ɾṗµ«    # Push compressed string "bqapaaaaaaalauodbasanaaxaz"
                    Ŀ   # Transliterate the (implicit) input from the lowercase alphabet to that
                     Ṙ  # Reverse
                      ⁼ # Is it equal to the (implicit) input?

A port of Kevin's 05AB1E answer is 23 bytes as well:

Vyxal, 23 bytes

Ḃ«ƛ≠ȧ‹«:£ḂĿka¥«g₴Ṡ«JFF=

Try it Online!

\$\endgroup\$
1
  • \$\begingroup\$ You forgot z in your compressed string. \$\endgroup\$ Jun 2 at 8:21
7
\$\begingroup\$

JavaScript (ES6), 68 bytes

Saved 1 byte thanks to @Shaggy

Returns \$0\$ or \$1\$.

s=>[...s].map(c=>o=S[S.search(c)^1]+o,S=o='bqdpnulloossxxzz')|o==s+S

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 68 bytes \$\endgroup\$
    – Shaggy
    Jun 2 at 10:21
  • 2
    \$\begingroup\$ @Shaggy Ah, nice one! \$\endgroup\$
    – Arnauld
    Jun 2 at 12:30
5
\$\begingroup\$

J-uby, 153 148 56 55 53 bytes

:=~&(:~|~:tr&"pq#{?p*9}lpuodbpspnppxpp"&[*?a..?z]*'')

Try it online!

Just learning J-uby so this definitely is terrible.

Edit: I knew it. -95 bytes thanks to Steffan

\$\endgroup\$
6
  • 2
    \$\begingroup\$ sorry, 53 \$\endgroup\$
    – Steffan
    Jun 2 at 3:42
  • \$\begingroup\$ @Steffan why sorry? I can't thank you enough for shaving 95 bytes \$\endgroup\$
    – badatgolf
    Jun 2 at 3:44
  • 1
    \$\begingroup\$ bcs i have to say my golfs in 3 different comments lol \$\endgroup\$
    – Steffan
    Jun 2 at 3:45
  • 2
    \$\begingroup\$ please do add your answer to the LoTM thread \$\endgroup\$
    – Razetime
    Jun 2 at 3:46
  • \$\begingroup\$ @Razetime I try to add, but it says suggested edits are not allowed (I don't have enough reputation yet). Could you add my answer in? \$\endgroup\$
    – badatgolf
    Jun 2 at 3:48
5
\$\begingroup\$

R, 56 bytes

\(s)all(chartr("a-y","AqCpE-KlMuodbRsTnVWxY",s)==rev(s))

Attempt This Online!

Takes input as a vector of characters.

Translates all characters from the dictionary in the question to their counterparts and all others to uppercase equivalents (comparison is case sensitive in R, so those will break the equality).

\$\endgroup\$
5
\$\begingroup\$

C (gcc): 172 171 bytes

Edit: Thanks to ceilingcat for shortening the code to 172 171 bytes by using some nifty tricks!

Hello, first time posting code golf here! Criticism is welcome. :)

d[]={[98]=81,0,80,[108]=76,0,85,79,68,68,0,83,0,78,0,0,88,0,90};main(c,v)int**v;{for(char*s,*e;--c;s>e&&puts(v[c]))for(e=index(s=v[c],0);s<e--&d[*e]-*s+d[*s]+64==*e;)s++;}

Try it online (with explanation)

Explanation:


/**
 * Thanks to ceilingcat for shortening the code to 171 bytes by using some nifty tricks!
 */

/**
 * Stores the flipped equvilent of a character in upper case ASCII
 * (sorry to anyone using EBCDIC) where the index is the character (lower case)
 * and the value is the flipped equivalent of the character.
 * The reason I used upper case is because writing many ['b'] = 'q' is more
 * expensive (space-wise) than writing [66] = 81 and converting them each time
 * (by adding or subtracting 32).
 */
d[]={[98]=81,0,80,[108]=76,0,85,79,68,68,0,83,0,78,0,0,88,0,90};
main(c,v)int**v;{
        // Prints string if the 2 pointers crossed the middle which would
        // mean the second loop never exited (is a palindrome) at the end.
        for(char*s,*e;--c;s>e&&puts(v[c]))
                // 'e=index(s=v[c],0)' gets the pointers for the first and last
                // character of the string.
                // Exits the loop when character '*s' is not equal to flipped character '*e' and
                // vice versa or the 2 pointers cross at the middle of the string.
                for(e=index(s=v[c],0);s<e--&d[*e]-*s+d[*s]+64==*e;)
                        s++;
}

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Golf, and nice first answer! In our site, we allowed that input can be a function argument and output can be what the function returns, so that can cut you some bytes (see my answer for example). Also, take a look at Tips for golfing in C. \$\endgroup\$
    – badatgolf
    Jun 3 at 14:59
  • \$\begingroup\$ @ceilingcat Wow, great find! I was sure that I squeezed out every byte. :P \$\endgroup\$ Jun 7 at 9:24
3
\$\begingroup\$

APL+WIN, 44 37 bytes

-7 bytes thanks to OVS

Prompts for text

t≡⌽'qpluodbsnxz '['bdlnopqsuxz'⍳t←,⎕]

Try it online! Thanks to Dyalog Classic APL

\$\endgroup\$
1
  • \$\begingroup\$ I'm guessing APL+WIN doesn't have , but ∧/t=⌽ ... should work? \$\endgroup\$
    – ovs
    Jun 2 at 7:56
3
\$\begingroup\$

PARI/GP, 70 bytes

s->Vecrev(s)==[Vec("`q`p```````l`uodb`s`n``x`z")[i-96]|i<-Vecsmall(s)]

Attempt This Online!

\$\endgroup\$
3
\$\begingroup\$

C (gcc), 835 bytes

I never was very good at golf...

#include "string.h"
#include "stdio.h"
char z[8][2] = {{'b','q'},{'d','p'},{'n','u'},{'l','l'},{'o','o'},{'s','s'},{'x','x'},{'z','z'},};
void main(int argc, char *argv[])
{
    int n = argc-1;
    for (int x = 1; x <= n; x++){
        int p = 0;
        int l = strlen(argv[x]);
        char r[l+1];
        for (int i = l; i > 0; i--){
            char c = argv[x][i-1];
            int v = 0;
            for (int a = 0; a < 8; a++){
                if (c == z[a][0]){
                    c = z[a][1];
                    v = 1;
                } else if (c == z[a][1]){
                    c = z[a][0];
                    v = 1;
                }
            }
            if (!v) {p = 1;}
            r[l-i] = c;
        }
        r[strlen(argv[x])+1] = '\0';
        printf("%d\n", memcmp(r, argv[x], l) == 0 && p == 0);
    }
}

Try it online!

Original, much more readable version:

C (gcc), 1238 bytes

#include "string.h"
#include "stdio.h"

char letters_to_rotate[8][2] = {
{'b', 'q'},
{'d', 'p'},
{'n', 'u'},
{'l', 'l'},
{'o', 'o'},
{'s', 's'},
{'x', 'x'},
{'z', 'z'},
};

void main(int argc, char *argv[])
{
    int num_inputs = argc-1;
    for (int x = 1; x <= num_inputs; x++){
        int invalid_char_present = 0;
        int inputlength = strlen(argv[x]);
        char rotated[inputlength+1];
        for (int i = inputlength; i > 0; i--){
            char c = argv[x][i-1];
            int valid_char = 0;
            for (int a = 0; a < 8; a++){
                if (c == letters_to_rotate[a][0]){
                    c = letters_to_rotate[a][1];
                    valid_char = 1;
                }
                else if (c == letters_to_rotate[a][1]){
                    c = letters_to_rotate[a][0];
                    valid_char = 1;
                }
            }
            if (!valid_char) {invalid_char_present = 1;}
            rotated[inputlength-i] = c;
        }
        rotated[strlen(argv[x])+1] = '\0';
        if (memcmp(rotated, argv[x], inputlength) == 0 && invalid_char_present == 0){
            printf("%s: True\n", argv[x]);
        } else {
            printf("%s: False\n", argv[x]);
        }
    }
}

Try it online!

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Welcome to Code Golf! You've golfed things pretty well so far, but there's a few more easy things you can do to lower your byte count. You have a lot of whitespace, which is almost all unnecessary. Indentation, line breaks, spaces before and after operators and keywords, etc. After that, you might want to check out Tips for golfing in C to see if there's any more tricks you can use, like clever for loop stuff. \$\endgroup\$ Jun 3 at 0:01
  • \$\begingroup\$ 206 bytes \$\endgroup\$
    – ceilingcat
    Jun 9 at 15:18
3
\$\begingroup\$

Rust, 135 130 bytes

let m="bqdpnulloossxxzz";let f=|s:&str|!s.chars().zip(s.chars().rev()).any(|(a,b)|m.find(a).or(Some(99))!=m.rfind(b).map(|x|x^1));

I'm pretty new to golfing so I hope I did it alright.

I'm still pretty unhappy with how verbose the code to fix the options is.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Try it online! - link where others can run your program. Feel free to edit it into your answer if you want \$\endgroup\$ Jun 2 at 20:09
3
\$\begingroup\$

T-SQL, 84 bytes

Returns 1 when palindrome, otherwise 0

PRINT IIF(translate(@,'bqdpnu','qbpdun')<>reverse(@)or 
@ like'%[^qbpdunolsxz]%',0,1)

Try it online

\$\endgroup\$
3
\$\begingroup\$

Oracle SQL, 68 bytes

o=reverse(translate(o,'bdlnopqsuxzacefghijkmnrstuvwy','qpluodbsnxz'))

Tested with

with w as (
   select column_value o
   from
   ku$_vcnt(
   'this',
   'another',
   'lll',
   'lol',
   'dad',
   'dab',
   'dap',
   'wow',
   'ooi',
   'lollpopdodllol'
))
select o from w
where
   o=reverse(translate(o,'bdlnopqsuxzacefghijkmnrstuvwy','qpluodbsnxz'));
\$\endgroup\$
1
  • \$\begingroup\$ your solution will not return an answer. You have just included the "WHERE" clause as answer. \$\endgroup\$ Jun 3 at 12:45
3
\$\begingroup\$

Bash, 71 bytes

f()(a=bdlnopqsuxz;[ "`echo $1|tr $a qpluodbsnxz|tr -dc $a|rev`" = $1 ])

Try it online!


Using a more compact tr command as inspired by pajonk's answer:

Bash, 58 bytes

f()([ "`echo $1|tr a-y AqCpE-KlMuodbRsTnVWxY|rev`" = $1 ])

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$ Jun 3 at 20:49
  • \$\begingroup\$ Wouldn't this be shorter as a full program (script) rather than a function? Also, I think returning via success code is an allowed output format for a boolean function, in case that helps. \$\endgroup\$
    – Neil
    Jun 6 at 16:17
3
\$\begingroup\$

PowerShell, 72 68 51 bytes

!(($s=$args)|?{'dbqspn  x z l uo'[$_%16]-$s[--$i]})

Try it online!

The script assumes an input does not contains space chars. I guess It is good constraint for a word.

The script takes a splatted string and performs double check for each symbol from the string.

The algorithm for the hash string dbqspn x z l uo is: Place an ambigram char at the position (ASCII % 16).

Source char ASCII % 16 Ambigram char
p 112 0 d
q 113 1 b
b 98 2 q
s 115 3 s
d 100 4 p
u 117 5 n
x 120 8 x
z 122 10 z
l 108 12 l
n 110 14 u
o 111 15 o
\$\endgroup\$
2
\$\begingroup\$

05AB1E, 23 bytes

Â.•1⋃•©Â‡A®.•(ÖÆ•«ммQ

Try it online or verify all test cases.

A port of @Steffan's Vyxal answer is 23 bytes as well:

ÂA.•1ηλ¥nô[˜ζÕPζeí=Ω•‡Q

Try it online or verify all test cases.

Explanation:

          # Bifurcate the (implicit) input-string, short for Duplicate & Reverse
 .•1⋃•   # Push the compressed string "bdunpq"
  ©        # Store it in variable `®` (without popping)
   Â       # Bifurcate it
    ‡      # Transliterate all "bdunpq" to "qpnudb"
 A         # Push the lowercase alphabet
  ®        # Push string `®`
   .•(ÖÆ•« # Append compressed string "losxz"
    м      # Remove all those characters from the alphabet: "acefghijkmrtvwy"
     м     # Remove all those characters from the modified input
      Q    # Check if it's equal to the input-string
           # (after which the result is output implicitly)

          # Bifurcate the (implicit) input-string, short for Duplicate & Reverse
 A         # Push the lowercase alphabet "abcdefghijklmnopqrstuvwxyz"
  .•1ηλ¥nô[˜ζÕPζeí=Ω•
           # Push the compressed string  "bqapaaaaaaalauodbasanaaxaz"
   ‡       # Transliterate the alphabet to these characters
    Q      # Check if it's equal to the input-string
           # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?) to understand why .•1⋃• is "bdunpq"; .•(ÖÆ• is "losxz"; and .•1ηλ¥nô[˜ζÕPζeí=Ω• is "bqapaaaaaaalauodbasanaaxaz".

\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 56 bytes

$
¶$`
T`b\dl-qsuxzl`q\p\l_u\o\dbsnxz_`^.+
+`(.)¶\1
¶
^¶$

Try it online! Link includes test cases. Explanation:

$
¶$`

Duplicate the input.

T`b\dl-qsuxzl`q\p\l_u\o\dbsnxz_`^.+

Individually rotate the characters of the first copy, but delete characters that aren't rotatable. (d, l, o and p need to be quoted when not used as part of a range.)

+`(.)¶\1
¶

Compare the last character of the first copy with the first character of the second, removing both if they are equal. Repeat until either they don't match or there aren't any left.

^¶$

If there aren't any left then the original input was a rotational palindrome.

\$\endgroup\$
0
2
\$\begingroup\$

K (ngn/k), 30 bytes

{x~|v(|v:"lnopqsxzxsbdoul")?x}

Try it online!

I took the shortest ambigram which contained all the possible characters and made it into a lookup string: locate where each character of the input is in the string, and then take one character from the reversed version to construct the rotated character. Finally, reverse it and compare against the original input.

\$\endgroup\$
1
\$\begingroup\$

JavaScript, 88 bytes

s=>s==[...s].map(x=>'losxz'.includes(x)?x:(r='budpnq')[5-r.indexOf(x)]).reverse().join``

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Stax, 23 bytes

Ç╥Vⁿ2n♣¿æ∞╙♥>5H╜ÜN¡¼}╝î

Run and debug it

\$\endgroup\$
0
\$\begingroup\$

Regex (Perl / PCRE2 / Boost), 65 bytes

^(([losxz])((?1)\2|)|b(?1)q|q(?1)b|d(?1)p|p(?1)d|n(?1)u|u(?1)n|)$

Try it online! - Perl
Try it online! - PCRE2
Try it online! - Boost

This is a straight port of my Perl/PCRE2/Boost answer to Numbers with Rotational Symmetry.

^              # Assert this is the start of the string
(              # Define (?1) recursive subroutine call
    ([losxz])  # \2 = match a char that is its own rotation
    ((?1)\2|)  # Optionally match (?1) followed by \2
|
    b(?1)q
|
    q(?1)b
|
    d(?1)p
|
    p(?1)d
|
    n(?1)u
|
    u(?1)n
|
               # Match an empty string at the center of an even-length string
)
$              # Assert this is the end of the string

If there just one more matched pair of distinct characters, e.g. ae, another method would win by 3 bytes:

^(([losxz])((?1)\2|)|a(?1)e|e(?1)a|b(?1)q|q(?1)b|d(?1)p|p(?1)d|n(?1)u|u(?1)n|)$
^((?=([losxz]|a.*e|e.*a|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).((?1)\3|)|)$

But instead it loses by 1 byte:

^(([losxz])((?1)\2|)|b(?1)q|q(?1)b|d(?1)p|p(?1)d|n(?1)u|u(?1)n|)$
^((?=([losxz]|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).((?1)\3|)|)$

Regex (Ruby), 72 bytes

^((?=([losxz]|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).(\g<1>\k<3+0>|)|)$

Try it online!

In this port, unlike the Perl/PCRE2/Boost version, the alternative method wins by 5 bytes:

^(([losxz])(\g<1>\k<2+0>|)|b\g<1>q|q\g<1>b|d\g<1>p|p\g<1>d|n\g<1>u|u\g<1>n|)$
^((?=([losxz]|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).(\g<1>\k<3+0>|)|)$

Regex (.NET), 75 bytes

^((?=([losxz]|b.*q|d.*p|n.*u|p.*d|q.*b|u.*n)(?<=(.))).?)+(?<-3>\3)*(?(3)^)$

Try it online!

This is a straight port of my .NET answer to Numbers with Rotational Symmetry.

Regex (Perl / PCRE / .NET), 79 bytes

^((?=([losxz]|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).?(?=.*(\3(?(4)\4))))*\4?$

Try it online! - Perl
Try it online! - PCRE1
Try it online! - PCRE2
Try it online! - .NET

Regex (Perl / PCRE / Java / .NET), 86 bytes

^((?=([losxz]|b.*q|q.*b|d.*p|p.*d|n.*u|u.*n)(?<=(.))).?(?=.*(\3(\6\4|(?!\6))())))*\4?$

Try it online! - Perl
Try it online! - PCRE1
Try it online! - PCRE2
Try it online! - Java
Try it online! - .NET

Regex (Perl / PCRE2 / Pythonregex), 90 bytes

^(l(?1)l|o(?1)o|s(?1)s|x(?1)x|z(?1)z||b(?1)q|q(?1)b|d(?1)p|p(?1)d|n(?1)u|u(?1)n|[losxz]?)$

Try it online! - Perl
Try it online! - PCRE2
Try it online! - Python import regex

Unlike in Numbers with Rotational Symmetry, this comes in last place here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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