# Visible Dice Faces

A traditional Western die is a cube, on which the integers 1 to 6 are marked on the faces. Pairs that add to 7 are placed on opposite faces.

As it is cube, we can only see between 1 and 3 faces (inclusive)1 at any given time. Opposite faces can never be seen at the same time.

Your task is to write a program or function which, given a list of integers representing sides on a die, determines if it is possible to see these faces at the same time.

1Okay, maybe you can see 4 or 5 faces with a pair of eyes, but for the purpose of this challenge we observing the die from a single point.

# Rules:

• Your submission may assume the input list:
• Is non-empty.
• Only contains values which satisfy 1 ≤ n ≤ 6.
• Contains no duplicate elements.
• You may not assume that the input is sorted.
• Your submission should output a truthy / falsy value: truthy is the faces can be seen at the same time, falsy otherwise.
• This is , so the shortest answer (in bytes) wins!
• Standard loopholes are forbidden by default.

## Test Cases

Truthy:

[6]                 (One face)
[6, 2]              (Share a side)
[1, 3]              (Share a side)
[2, 1, 3]           (Share a vertex)
[3, 2, 6]           (Share a vertex)

Falsy:

[1, 6]              (1 and 6 are opposite)
[5, 4, 2]           (2 and 5 are opposite)
[3, 1, 4]           (3 and 4 are opposite)
[5, 4, 6, 2]        (Cannot see 4 faces)
[1, 2, 3, 4, 5, 6]  (Cannot see 6 faces)
• Dec 4, 2017 at 20:30
• It seems that the last two falsey cases are superfluous as any list longer than 3 will contain opposing values, no? Dec 6, 2017 at 12:22
• @WeckarE yes, obviously - if you have a look at the answers they all exploit this. It was just an easier explanation to write. Dec 6, 2017 at 15:09
• You can still see up to 5 faces from a single point if you bent the light waves with something heavy like a black hole Dec 14, 2017 at 6:46
• @Ferrybig So a mirror would be cheating, but a black hole is fair game? :-) Mar 19 at 3:14

# JavaScript (ES6),  38 34 30 29  28 bytes

Takes input as any number of separate parameters. Returns 0 or 1.

(a,b,c,d)=>!(d|(a^b^c)%7)^!c

### Test cases

let f =

(a,b,c,d)=>!(d|(a^b^c)%7)^!c

console.log('[Truthy]')
console.log(f(6      ))
console.log(f(6, 2   ))
console.log(f(1, 3   ))
console.log(f(2, 1, 3))
console.log(f(3, 2, 6))

console.log('[Falsy]')
console.log(f(1, 6            ))
console.log(f(5, 4, 2         ))
console.log(f(3, 1, 4         ))
console.log(f(5, 4, 6, 2      ))
console.log(f(1, 2, 3, 4, 5, 6))

### How?

Below are simplified versions of the main expression according to the number of parameters provided, undefined variables being coerced to either 0 or false:

# of param. | simplified expression        | comment
------------+------------------------------+---------------------------------------------
1      | !(a % 7) ^ 1                 | always true
2      | !((a ^ b) % 7) ^ 1           | false for (1,6), (2,5) and (3,4)
3      | !((a ^ b ^ c) % 7)           | see the table below
4+     | !(d | (a ^ b ^ c) % 7)       | always false

NB: The order of (a,b,c) doesn't matter because they're always XOR'd together.

The trickiest case is the 3rd one. Here is a table showing all possible combinations:

a | b | c | a^b^c | %7 | =0? | faces that sum to 7
--+---+---+-------+----+-----+--------------------
1 | 2 | 3 |   0   |  0 | Yes | none
1 | 2 | 4 |   7   |  0 | Yes | none
1 | 2 | 5 |   6   |  6 | No  | 2 + 5
1 | 2 | 6 |   5   |  5 | No  | 1 + 6
1 | 3 | 4 |   6   |  6 | No  | 3 + 4
1 | 3 | 5 |   7   |  0 | Yes | none
1 | 3 | 6 |   4   |  4 | No  | 1 + 6
1 | 4 | 5 |   0   |  0 | Yes | none
1 | 4 | 6 |   3   |  3 | No  | 1 + 6
1 | 5 | 6 |   2   |  2 | No  | 1 + 6
2 | 3 | 4 |   5   |  5 | No  | 3 + 4
2 | 3 | 5 |   4   |  4 | No  | 2 + 5
2 | 3 | 6 |   7   |  0 | Yes | none
2 | 4 | 5 |   3   |  3 | No  | 2 + 5
2 | 4 | 6 |   0   |  0 | Yes | none
2 | 5 | 6 |   1   |  1 | No  | 2 + 5
3 | 4 | 5 |   2   |  2 | No  | 3 + 4
3 | 4 | 6 |   1   |  1 | No  | 3 + 4
3 | 5 | 6 |   0   |  0 | Yes | none
4 | 5 | 6 |   7   |  0 | Yes | none

# Alt. version #1, 32 bytes

Takes input as an array. Returns a boolean.

a=>a.every(x=>a.every(y=>x+y-7))

### Test cases

let f =

a=>a.every(x=>a.every(y=>x+y-7))

console.log('[Truthy]')
console.log(f([6]      ))
console.log(f([6, 2]   ))
console.log(f([1, 3]   ))
console.log(f([2, 1, 3]))
console.log(f([3, 2, 6]))

console.log('[Falsy]')
console.log(f([1, 6]            ))
console.log(f([5, 4, 2]         ))
console.log(f([3, 1, 4]         ))
console.log(f([5, 4, 6, 2]      ))
console.log(f([1, 2, 3, 4, 5, 6]))

# Alt. version #2, Chrome/Firefox, 34 bytes

This one abuses the sort methods of Chrome and Firefox. It doesn't work with Edge.

Takes input as an array. Returns 0 or 1.

a=>a.sort((a,b)=>k&=a+b!=7,k=1)&&k

### Test cases

let f =

a=>a.sort((a,b)=>k&=a+b!=7,k=1)&&k

console.log('[Truthy]')
console.log(f([6]      ))
console.log(f([6, 2]   ))
console.log(f([1, 3]   ))
console.log(f([2, 1, 3]))
console.log(f([3, 2, 6]))

console.log('[Falsy]')
console.log(f([1, 6]            ))
console.log(f([5, 4, 2]         ))
console.log(f([3, 1, 4]         ))
console.log(f([5, 4, 6, 2]      ))
console.log(f([1, 2, 3, 4, 5, 6]))

# Python 2, 35 bytes

lambda a:any(7-i in a for i in a)<1

Try it online!

• -1 byte in Python 3. Dec 4, 2017 at 22:53
• @notjagan -1 more by replacing …<{1} with plain not… 13 hours ago

-3 bytes thanks to H.PWiz.

f l=all(/=7)$(+)<$>l<*>l

Try it online!

## Explanation

f l=all(/=7)$(+)<$>l<*>l

f l=                      -- make a function f that takes a single argument l
(+)<$>l<*>l -- take the sum of each pair in the cartesian product... all(/=7)$             -- ...and check if they're all inequal to 7

# Regex (Perl / Java / PCRE2 v10.34+), 30 29 bytes

^(?!.*\b(x(\2?+,.*\b)?){7}\b)

Try it online! - Perl
Try it online! - Java
Attempt This Online! - PCRE2 v10.40+

This is an adaptation of the 31 30 byte version below, but it prevents more than one split from occurring in a somewhat more complex manner. Upon matching a split, \2 captures the intervening elements, including commas – or just a single comma if there are no intervening elements.

How this prevents more than one split would be simple to explain if (?(2)\2) were used instead of \2?+. Then the mechanism would be that on subsequent attempts to match a splitting after one has already occurred, that would be forced to coincide with matching a duplicate element, or two commas in a row.

But \2?+ will successfully make an empty match if \2 is not an exact match at that position. However, note that if this did happen, it could only result in false negatives (returning "False" incorrectly) – never false positives – because it could make the pattern inside the negative lookahead match when it shouldn't, but it can't prevent a match that should have happened.

All lists of 4 or more numbers will return "False", so the addition of false negatives won't matter. And lists of 2 or fewer elements can only match one split anyway (where \2 captures a single comma alone), so no false negatives could result there.

So we only need to consider lists of 3 elements:

• Only two splits can occur at most, and if that is the case, \2 will contain exactly one comma. The first split prevents a second split from being matched because \2?+, would only match two commas in a row.
• Or if a split matches one intervening element, only one split can occur anyway, so there's no place for a second split to match.

And here is a test harness with all 156 lists of 3 or fewer elements, demonstrating this regex to work correctly:

Try it online! - Perl

# Regex (Perl / Java / Pythonregex / Ruby / PCRE), 31 30 bytes

^(?!.*\b(x\2?+(,).*\b|x){7}\b)

Try it online! - Perl
Try it online! - Java
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - Ruby
Try it online! - PCRE

This is an adaptation of the 33 32 31 byte version below, but it prevents more than one split from occurring with \2?+(,), which forces a split to coincide with matching two commas in a row (which can never happen in the input specification) if a split has already occurred.

# Regex (Perl / Boost / Python / Pythonregex / Ruby / PCRE / .NET), 3332 31 bytes

^(?!.*\b(?(1)x|x(,.*\b)?){7}\b)

Takes its input in comma-delimited unary, as a concatenation of strings of x characters whose lengths represent the numbers, separated by , characters.

Try it online! - Perl
Try it online! - Boost
Try it online! / Attempt This Online! - Python
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - Ruby
Try it online! - PCRE
Try it online! - .NET

This works by asserting that no two numbers add up to exactly 7. It does this by consuming exactly 7 x characters – a split is allowed to occur at any point within this, but not more than once.

^             # Anchor to start
(?!           # Negative lookahead - assert that the following can't match:
.*\b          # Skip to any occurrence of a word boundary, which if
# it is followed by "x", denotes the beginning of a
# number's unary representation.
(?(1)         # Conditional upon whether \1 is set:
# If \1 is set:
x             # tail -= 1
|
# If \1 is unset:
# (This is only allowed to match once within this loop. There is no
# need to verify afterward that it matched exactly once, because the
# input specification allows us to assume there will be no numbers
# greater than 6 – so, 7 will never appear.)
x             # tail -= 1
(
,.*\b         # Complete the match for the current number, and
# unary representation.
)?            # Match the above optionally
){7}          # Iterate the above exactly 7 times; this can never result in
# the 7th iteration ending in a split, as that would require
# matching 7 x's in a row, but the input is guaranteed not to
# contain a 7.
\b            # Assert that tail == 0 (i.e, that this is the end of a
# number's unary representation)
)

Strangely, this actually works with Python's re library, even though (?(2)...) is a forward-declared conditional, and re doesn't support forward-declared or nested backreferences; \2 in that position would throw an error.

Equally strangely, it works in Boost, even though that regex engine doesn't support nested or forward-declared backreferences either, and a \2 in that position would cause Boost to throw an error as well.

The previous 33 byte version did not work properly with Python's re; it used a nested conditional, and Python silently treated that as a no-op, making the regex return some false negatives. But strangely, that version works in Pythonregex, even though that engine doesn't support nested backreferences either.

# Regex (Perl / Java / Pythonregex / Ruby / PCRE / .NET), 3433 32 bytes

^(?!.*\b(x(?!\2),.*\b()|x){7}\b)

Try it online! - Perl
Try it online! - Java
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - Ruby
Try it online! - PCRE
Try it online! - .NET

This adds Java support to the above 33 32 31 byte version, by removing the use of the conditional (?(2)...). Support for Python and Boost is dropped, due to the use of the nested backreference \2.

# Regex (ECMAScript 2018 / Pythonregex / .NET), 41 36 bytes

^(?!(.*\b)(x(?<=^\1x+),.*\b|x){7}\b)

Try it online! - ECMAScript 2018
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - .NET

^             # Anchor to start
(?!           # Negative lookahead - assert that the following can't match:
(.*\b)        # Skip to any occurrence of a word boundary, which if
# it is followed by "x", denotes the beginning of a
# number's unary representation;
# \1 = the entire portion of the string that has been
# skipped, going all the way back to its beginning.
(
x             # tail -= 1
# The below is only allowed to match once within this loop. There is
# no need to verify afterward that it matched exactly once, because
# the input specification allows us to assume there will be no numbers
# greater than 6 (so, 7 will never appear).
(?<=          # Lookbehind - evaluated from right to left (so in this
# listing, read it from bottom to top)
^         # Assert this is the start of the string
\1        # Match \1
x+        # Skip back to the beginning of the unary representation
# of the current number
)
,.*\b         # Complete the match for the current number, and skip
# to the beginning of any subsequent number's unary
# representation.
|              # or...
x             # tail -= 1 (and do nothing else)
){7}          # Iterate the above exactly 7 times; this can never result in
# the 7th iteration ending in a split, as that would require
# matching 7 x's in a row, but the input is guaranteed not to
# contain a 7.
\b            # Assert that tail == 0 (i.e, that this is the end of a
# number's unary representation)
)

A previous 41 byte version using lookbehind appears to expose a bug in Pythonregex:

^(?!(.*\b)x+(,.*\b)x+\b(?<=^\1(\2?x){7}))

Try it online! - ECMAScript 2018 - works
Attempt This Online! - Python (with regex) - does not work
Try it online! - .NET - works

# Regex (ECMAScript or better), 7369464140 39 bytes

^(?!.*\b(?=x*(.*))(x(?=\1).+\b|x){7}\b)

Try it online! - ECMAScript (SpiderMonkey)
Try it online! - ECMAScript 2018 (Node.js)
Try it online! - Perl
Try it online! - Java
Try it online! - Boost
Try it online! - Python
Try it online! / Attempt This Online! - Python (with regex)
Try it online! - Ruby
Try it online! - PCRE
Try it online! - .NET

This now ports the 33 32 31 byte version's algorithm to support ECMAScript:

^             # Anchor to start
(?!           # Negative lookahead - assert that the following can't match:
.*\b          # Skip to any occurrence of a word boundary, which if
# it is followed by "x", denotes the beginning of a
# number's unary representation.
(?=x*(.*))    # \1 = the entire string following the current number's
#      unary representation
(
x             # tail -= 1
# The below is only allowed to match once within this loop. There is
# no need to verify afterward that it matched exactly once, because
# the input specification allows us to assume there will be no numbers
# greater than 6 (so, 7 will never appear).
(?=\1)        # Assert that the entire string following the current
# position matches what was captured in \1, which
# accomplishes two things – it asserts that we
# haven't skipped to another number yet, and that
# we've finished consuming the entire current number,
# i.e. that tail == 0.
# unary representation (the first character skipped
# will be a comma).
|              # or...
x             # tail -= 1 (and do nothing else)
){7}          # Iterate the above exactly 7 times; this can never result in
# the 7th iteration ending in a split, as that would require
# matching 7 x's in a row, but the input is guaranteed not to
# contain a 7.
\b            # Assert that tail == 0 (i.e, that this is the end of a
# number's unary representation)
)

The previous 73 69 byte version worked by treating every possible pair of numbers that add to 7 as a separate case, like the decimal version below:

^(?!(?=.*\bx\b).*x{6}|(?=.*\bxx\b).*\bx{5}\b|(?=.*\bxxx\b).*\bx{4}\b)

# Regex (.NET), 46 bytes

^(?!.*\b(){7}(?<-1>x)+,.*\b(?<-1>x)+(?(1)^)\b)

Obsoleted by the 33 32 byte version above.

# Regex (Perl / Boost / Python / Ruby / PCRE / .NET), 58 bytes

^(?!.*\b(x)?(xx)?(xxxx,.*\b|,.*\bxxxx)(?(2)|xx)(?(1)|x)\b)

Obsoleted by the versions above. Worked by capturing two numbers in binary, and asserting that the second number has all 3 of its lowermost bits flipped when compared to the first number (and asserting that this doesn't occur anywhere in the input).

# Regex (ECMAScript or better), 38 37 bytes

^(?!(?=.*1).*6|(?=.*2).*5|(?=.*3).*4)

Takes its input in decimal. There is no need for delimiters, because the full range fits into a single digit.

Try it online! - ECMAScript / Perl / Java / Python / .NET

Pure regex is very limited in what math can be done on decimal input, so this version just asserts that no two numbers occur anywhere in the list that add up to 7, by exhaustively listing all the pairs that could do so.

# APL (Dyalog), 7 bytes

~7∊∘.+⍨

Try it online!

∘.+⍨ - addition table (every element with every element)

7∊ - 7 exists?

~ - negate

# APL (Dyalog), 7 bytes

⍬≡⊢∩7-⊢

Try it online!

7-⊢ - subtract each element from 7

⊢∩ - intersect with the original array

⍬≡ - empty?

# R, 27 bytes

thanks to Gregor for fixing a bug

function(d)!any((7-d)%in%d)

Try it online!

Port of Chas Brown's answer. Having vectorized operations helps make this much shorter in R.

• I think you need some parens around (7-d), other wise d%in%d takes precedence. Dec 5, 2017 at 20:32
• @Gregor you're absolutely right. Dec 5, 2017 at 20:35

# Retina, 21 20 bytes

O.
M1.*6|2.*5|34
0

Try it online! Link includes test cases. Edit: Saved 1 byte thanks to @MartinEnder. Explanation:

O.

Sort the input.

M1.*6|2.*5|34

Check for a pair of opposite sides (3 and 4 sort next to each other). This returns 1 for an invalid die or 0 for a valid one.

0

Logically negate the result.

# Mathematica, 20 bytes

xFreeQ[#+x&/@x,7]

The is \[Function]

-12 bytes from Martin Ender
-7 bytes from Misha Lavrov

Try it online!

# ThunnoD, 7$$\5\log_{256}(96)\approx\$$ 4.12 bytes

7_Gze

Attempt This Online!

7_     # subtract each from 7
G    # map each number to the input with that number removed
ze  # all equal?

Now beating tied with the language's creator!

• Wow, you beat the language's creator! Mar 18 at 2:41
• @Deadcode And all because of a weird interpreter thing--G is supposed to run on the whole array, but for some reason it vectorizes to each element which is why I have to check if all are equal instead of check if it is empty. Mar 18 at 12:03
• @TheThonnu I think you implemented it incorrectly because its function doesn't really match its description... But it still came in handy here! Mar 18 at 12:11
• @TheThonnu That's alright, competition is fun :) Especially when I win :P Mar 18 at 12:17
• You're not winning any more :P Mar 18 at 12:49

# Nibbles, 5.5 bytes (11 nibbles)

-~+.$?@- 7 For each element x of input, checks tbat 7-x is not present in the input. Outputs 1 (truthy) if faces can be seen at the same time, and negative value (falsy) if they cannot. -~+.$?@- 7
.        # map over

Try it online!

# Jelly, 5 bytes

7_f⁸Ṇ

Try it online!

### Explanation

7_f⁸Ṇ
7_    Subtract each element from 7
f⁸  Filter with the original list
Ṇ Check if empty

# Pyth, 5 bytes

!@-L7

Try it here.

• I could swear I tried this two minutes ago and it didn’t work... Huh I wonder what went wrong Dec 4, 2017 at 21:04
• First thing I thought of? The Sandlot. Dec 4, 2017 at 22:23

# Actually, 8 bytes

;∙♂Σ7@cY

Try it online! (runs all the test cases)

Explanation:

;∙♂Σ7@cY
;∙        Cartesian product with self
♂Σ      sum all pairs
7@c   count 7s
Y  logical negate

## Husk, 5 bytes

Ëo≠7+

Try it online!

### Explanation

Ëo     Check that the following function gives a truthy value for all pairs
from the input.
+    Their sum...
≠7     ...is not equal to 7.

# Vyxal, 4 bytes

7ε↔¬

Try it Online!

Very simple answer, ports the approach of the 5 byte Jelly.

## Explained

7ε↔¬
7ε    # Abs difference of 7 with each item in the input
↔   # Remove items in that list that are also in the input
¬  # Logical negation - empty list turns into 1, non-empty turns into 0
• Shouldn't the explanation of '↔' read 'keep' instead of 'remove'? Mar 14 at 15:11

# Jelly, 4 bytes

7_ḟƑ

Try it online!

Relatively trivial golf of Erik's solution.

7_      For each face, subtract it from 7.
Ƒ    Is the list of results unchanged by
ḟ     filtering out elements of the original input?

Needless to say, a simple 7_f would win if inverted output were permitted.

# ThunnoD, $$\ 5 \log_{256}(96) \approx \$$ 4.12 bytes

7_cS!

#### Explanation

7_cS!  # Implicit input
7_     # Subtract each from 7
c    # Is each in the input?
S!  # All are false?
# Implicit output

# Nibbles, 6 bytes

-~,&.$- 7$

Attempt This Online!

Disgusting. Surely there is a better way to do this.

• Well, still disgusting, but at least half a byte shorter... Mar 18 at 19:21

## Alice, 18 bytes

/..y1nr@
\iReA6o/

Try it online!

Prints Jabberwocky for valid inputs and nothing otherwise.

### Explanation

Unfolding the zigzag control flow, the program is really just:

i.e16r.RyAno

i.  Read all input and duplicate it.
e16 Push "16".
r   Range expansion to get "123456".
.R  Duplicate and reverse.
y   Transliterate, replaces each face with its opposite.
A   Intersection with input.
n   Logical NOT, turns empty strings into "Jabberwocky"
and everything else into an empty string.

# Pyth, 5 bytes

-7sM*

Test suite.

isaacg saved a byte!

## Retina, 20 bytes

T_654d
M(.).*\1
0

Try it online!

An alternative to Neil's approach.

### Explanation

T_654d

Turn 6,5, 4 into 1, 2, 3, respectively.

M`(.).*\1

Try to find repeated characters and count the number of matches.

0

Make sure the result was zero (effectively a logical negation).

# Ruby, 36 31 24 23 bytes

->l{l-l.map{|x|7-x}==l}

Try it online!

It was so simple, I was looking for the solution to the wrong problem all the time.

# Perl 6, 18 bytes

!(1&6|2&5|3&4∈*)

Try it online!

1 & 6 | 2 & 5 | 3 & 4 is a junction consisting of the numbers 1 and 6, OR the numbers 2 and 5, OR the numbers 3 and 4. This junction is an element of () the input list * if it contains 1 and 6, or 2 and 5, or 3 and 4. That result is then negated (!) to get the required boolean value.

# Factor + sets.extras, 24 bytes

[ 7 over n-v disjoint? ]

Try it online!

! { 2 1 3 }
7         ! { 2 1 3 } 7
over      ! { 2 1 3 } 7 { 2 1 3 }
n-v       ! { 2 1 3 } { 5 6 4 }
disjoint? ! t    (i.e. is the intersection empty?)

# Japt-x!, 5 bytes

fUma7

-1 byte thanks to Shaggy

This is basically a port of Lyxal's Vyxal answer.

fUma7  x!
f          # elements in both the input and
Um        #   the input, with each num mapped to
a7      #     its absolute difference with 7
x!  # flags: x = sum, ! = logical not
• Nicely done :) You can reverse it for 5 bytes: fUma7. Mar 14 at 15:27

# Japt-!, 5 bytes

ï+ ø7

Try it

• Wow took me until today to realize that builtin meant cartesian product, very confusing description LOL. I thought it was [1, 2, 3] [4, 5, 6] -> [[1, 4], [2, 5], [3, 6]] Mar 17 at 23:10

# C (GCC), 77 bytes

i,j;r;f(v,l)int*v;{for(i=r=-1;++i<l;)for(j=0;j<l;)r*=v[i]+v[j++]-7;return r;}

Try It Online!

Explanation:

i,j;r;
f(v,l)int*v;
{
// i and r are both initialized to -1. i is incremented by 1 before the
// loop, making its value equal 0, and for each iteration of the loop,
// until it's out of bounds of v.
for(i=r=-1;++i<l;)
// j also loops through the vector
for(j=0;j<l;)
// If v[i]+v[j] == 7, set r to 0, otherwise multiply it by
// something. If i == j, the sum will never equal 7 since a whole
// number multiplied by 2 is never odd. Otherwise, the numbers
// will equal 7 if they're on opposite sides of the die.
r*=v[i]+v[j++]-7;
return r;
}
• 65 bytes Mar 18 at 8:11

# Desmos, 45 39 bytes

f(x)=0^{[(7-i-x)^2.minfori=x.sort].min}

Try it on Desmos!