Self-Validating Triangular Checkerboard Program

10

1

A checkerboard program is a program where each individual character's ordinal value alternates from even to odd, excluding the line terminator (which can be any standard line-endings).

A triangular program is a program where each line has one additional character than the preceding line, with the first line having one character. You do not need to handle empty input.

Your task is to build a program that validates that the given input adheres to those criteria and outputs/returns something truthy if the program meets the criteria, or something falsy otherwise.

Your program must also meet these criteria.

Examples of valid programs

G
`e
@u^
5r{B

^
cB
+$C
VA01

Rules

  • Your program may start with either an odd or an even byte as long as the parity of the characters alternates.
  • Your program must validate programs that start with either an odd or an even character.
  • For unicode characters, the underlying byte values must have alternating parity.
  • You can assume that input only contains printable characters. If your program contains unprintables, it should still be able to validate itself.
  • Your program may include one trailing newline, this does not need to be allowed by your validation as you can assume this is removed prior to validating.
  • Standard loopholes are forbidden.
  • The shortest code in bytes, in each language, wins.

Dom Hastings

Posted 2018-03-16T08:56:12.330

Reputation: 16 415

@MartinEnder Thank you for your input! Hopefully this is now clear. Related to this, should I have left this in the sandbox for longer? – Dom Hastings – 2018-03-16T09:29:38.677

1is the even/odd alternating both horizontal and vertical ? I assume yes from "checkerboard", but I don't see where you say so. – Ton Hospel – 2018-03-16T09:39:42.590

@DomHastings A week seems fine. If you don't get any feedback after a few days, you can ask in chat if anyone has any more comments.

– Martin Ender – 2018-03-16T09:44:33.317

1@TonHospel My original examples did this, but it contradicted with my description, so for this implementation, no, it should be: E\nOE\nOEO. Hope that helps! – Dom Hastings – 2018-03-16T09:46:40.670

Can we assume that the input contains only printable characters? – Laikoni – 2018-03-16T12:33:33.197

@Laikoni Damn, that's a tough call. I'll assume yes for now and add a note to the Q, but I don't know how to validate any programs that would contain unprintables (since programs should self-validate). I don't know how likely that is. – Dom Hastings – 2018-03-16T13:10:07.320

"For unicode characters, the underlying byte values must have alternating parity". Can we choose an encoding? Otherwise, what do you consider to be the "underlying byte value" of a character? – recursive – 2018-03-16T16:22:33.077

@recursive I envisaged this as if a file is saved to disk, the bytes written would be alternative parity, for example î might be valid as it is made up of the bytes \xAE\xC3. Does that address the encoding issue too? – Dom Hastings – 2018-03-16T16:27:01.083

I understand the intention. It's not clear to me how to interpret this rule in online environments like TIO, where inputs and outputs are strings, not byte streams AFAIK, but I suppose that's not the fault of the challenge. – recursive – 2018-03-16T16:29:24.893

@DomHastings Can you confirm that answers must validate inputs starting with a newline in all cases or only if the source code itself contains a leading newline ? – Kaldo – 2018-03-16T17:53:14.207

@Kaldo I originally wanted to support the flexible input for all programs, but I don't intend to add pointless complexity to the challenge. Perhaps this did indeed need a bit more of a push in the sandbox. What're your opinions? – Dom Hastings – 2018-03-16T19:46:34.440

2My opinion: let answers assume input does not start or end with a newline. – Lynn – 2018-03-16T20:19:49.927

@Lynn Done. Thanks for the feedback! – Dom Hastings – 2018-03-16T21:16:56.677

@Jakob I'm not sure what you mean? I'm happy to accept any reasonable truthy/fasly values as output! Hope that helps! – Dom Hastings – 2018-06-28T13:24:42.570

@DomHastings Actually never mind; this no longer applies to my solution. – Jakob – 2018-06-28T14:49:54.863

Answers

3

Stax, 26 bytes

L
Y$
i:-
 {2%
*OFyF
%vi =*

Run test cases online

I had to introduce 3 junk characters. i is a no-op when outside all loop constructs. is always a no-op. O tucks a 1 under the top of the stack, but the value isn't used in the program.

LY      move input lines into a list and store in Y register
$       flatten
i       no-op
:-      get pairwise differences
{2%*OF  foreach delta, mod by 2, and multiply, then tuck a 1 under the top of stack
yF      foreach line in original input do...
  %v    subtract 1 from length of line
  i=    is equal to iteration index?
  *     multiply

Run this one

recursive

Posted 2018-03-16T08:56:12.330

Reputation: 8 616

Hey, I hope this doesn't mess with your code too much, but you can drop the leading newline validation. – Dom Hastings – 2018-03-16T21:18:06.687

8

C (gcc), 189 bytes

j
;l
;b;
d;f␉
(char
␉*␉t) 
{b=*␉t%
2;for␉(␉
j=d=0;j=j
+ 1,␉l=j+ 
1,␉*␉t; ) {
for␉(;l=l- 1
 ;t=t+ 1 )b= 
!b␉,␉d=d+ !(␉*
␉t␉*␉(␉*␉t- 10)
*␉(␉*␉t%2-b) ) ;
d␉|=*␉t- 10;t=t+ 
1 ; }b= !d; } ␉ ␉ 

Try it online!

represents a tab character (I'm sorry). Note that there are several trailing spaces/tabs (I'm more sorry). The original with tabs intact is best viewed in vim with :set tabstop=1 (words cannot express how sorry I am).

It's a function (called f, which isn't immediately obvious from glancing at it) that takes a string as an argument and returns either 0 or 1.

I could reduce this by at least one and probably two or more lines, but note that it gets increasingly messy and low-effort towards the end, mostly because writing such awful code (even by PPCG standards) was making me feel like a bad person and I wanted to stop as soon as possible.

The basic idea here is to avoid constructions that necessarily break the format (++, +=, return, etc.). Miraculously, important keywords like for, char, and while (which I didn't end up using) happen to fit the alternating parity rule. Then I used spaces (even parity) and tabs (odd parity) as padding to make the rest fit the rules.

Doorknob

Posted 2018-03-16T08:56:12.330

Reputation: 68 138

1I did not expect to see a solution in C! – Dom Hastings – 2018-03-17T07:11:22.037

If you isolate the solution portion of the program in the TIO by putting other stuff in the "Header" and "Footer" sections it's easier for people to verify the byte count. – Jakob – 2018-06-27T21:50:43.480

4

Haskell, 1080 1033 bytes

;
f=
 g 
ij=f
a =hi
hi = g
hij= ij
g ' ' =0
g '"' =0;
 g '$' =0;
 g '&' =0-0
g '(' =0-0-0
g '*' =0-0-0;
 g ',' =0-0-0;
 g '.' =0-0-0-0
g '0' =0-0-0-0-0
g '2' =0-0-0-0-0;
 g '4' =0-0-0-0-0;
 g '6' =0; g '8' =0
g ':' =0; g '<' =0-0
g '>' =0; g '@' =0-0;
 g 'B' =0; g 'D' =0-0;
 g 'F' =0; g 'H' =0-0-0
g 'J' =0; g 'L' =0-0-0-0
g 'N' =0; g 'P' =0-0-0-0;
 g 'R' =0; g 'T' =0-0-0-0;
 g 'V' =0; g 'X' =0-0-0-0-0
g 'Z' =0; g '^' =0; g '`' =0
g 'b' =0; g 'd' =0; g 'f' =0;
 g 'h' =0; g 'j' =0; g 'l' =0;
 g 'n' =0; g 'p' =0; g 'r' =0-0
g 't' =0; g 'v' =0; g 'x' =0-0-0
g 'z' =0; g '\92' =0-0; g '|' =0;
 g '~' =0; g y = 1 ;z=0; i(-0)z=z;
 i m('\10':y ) ="y"; ; ; ; ; ; ; ; 
i m(mnmnmnmnm:y ) = i(m - 1 ) y ; ; 
i k m ="y"; ; k i [ ] =01<1010101010;
 k m('\10':y ) = k(m + 1 )(i m y ) ; ;
 k m y =01>10; m o = k 1$'\10':o ; ; ; 
o i('\10':y ) = o i y ; ; ; ; ; ; ; ; ; 
o i(k:y )|g k<i = o(1 - i ) y ; ; ; ; ; ;
 o i(k:y )|g k>i = o(1 - i ) y ; ; ; ; ; ;
 o i [ ] =01<10; o i y =01>10;v=01>10101010
s y|o 1 y = m y|o(-0) y = m y ; s y =v; ; ; 

Try it online!

Explanation

This has been quite the interesting task for Haskell.

Parity

To start we need some way of determining if a character has an even or odd code-point. The normal way one might do this is to get the code-point and mod it by 2. However as one might be aware, getting the code-point of a character requires an import, which due to the source restriction means that it cannot be used. A more experienced Haskeller would think to use recursion. Char's are part of the Enum typeclass so we can get their predecessors and successors. However pred and succ are also both unusable because they don't alternate byte parity.

So this leaves us pretty stuck we pretty much can't do any manipulation with chars. The solution to this is to hardcode everything. We can represent (most) even chars as literals, odds we have trouble with because ' is odd so it can't be next to the char itself making the literal impossible to express most of the odd chars. So we hard code all of the even bytes, and then add a catch all for the odd bytes at the end.

The problem Bytes

You may notice that there are some even bytes for which literals cannot be made by wrapping it in single-quotes. They are the unprintables, newlines and \. We don't need to worry about unprintables since as long as we don't use any of them we don't need to verify. In fact we can still use odd unprintables, like tab, I just don't end up needing to. Newline can sagely be ignored because it will be trimmed from the program anyway. (We could include newline, because it's code-point is rather convenient, but we don't need to). This leaves \, now \ has the codepoint 92, which conveniently is an odd number followed by an even number, so \92 alternates between evens and odds thus the literal '\92' is perfectly valid. Later on when we do need to represent newline we will notice that it luckily has this same property '\10'.

Spacing problems

Now in order to start writing actual code we need to be able to put a sizable number of characters on a single line. In order to do this I wrote the cap:

;
f=
 g 
ij=f
a =hi
hi = g
hij= ij

The cap doesn't do anything except be valid Haskell. I had initially hoped to make definitions that would help us in the code later, but it didn't. There are also easier ways to make the cap, for example whitespace and semicolons, but they don't save bytes over this way so I haven't bothered to change it.

Hardcoder

So now that I have enough space on a line I start hardcoding values. This is mostly pretty boring, but there are a few things of interest. For one once the lines start getting even longer we can use ; to put multiple declarations on a line, which saves us a ton of bytes.

The second is that since we can't always start a line with a g every so often we have to indent the lines a bit. Now Haskell really cares about indentation, so it will complain about this. However if the last line before the indented line ends in a semicolon it will allow it. Why? I haven't the faintest, but it works. So we just have to remember to put the semicolons on the end of the lines.

Function Building Blocks

Once the hardcoder is done it is smooth sailing to the end of the program. We need to build a few simple functions. First I build a version of drop, called i. i is different from drop in that if we attempt to drop past the end of the string it just returns "y". i is different from drop also in that if it attempts to drop a newline it will return "y", These will be useful because later when we are verifying that the program is a triangle this will allow us to return False when the last line is not complete, or when a line ends early.

Next we have k which in fact verifies that some string is triangular. k is pretty simple, it takes a number \$n\$ and a string \$s\$. If \$s\$ is empty it returns True. If the string begins with a newline it removes the newline and \$n\$ characters from the front. It then calls k again with \$n+1\$ and the new string. If the string does not start with a newline it returns False.

We then make an alias for k, m. m is just k with 1 in the first argument, and a newline prepended to the second argument.

Next we have o. o takes a number and a string. It determines if the string bytes (ignoring newlines) alternate in parity (using our g) starting with the input number.

Lastly we have s which runs o with both 1 and 0, if either succeeds it defers to m. If it fails both it just returns False. This is the function we want. It determines that the input is triangular and alternating.

Post Rock Garf Hunter

Posted 2018-03-16T08:56:12.330

Reputation: 55 382

1A triangular string starts with a 1-character line, not an empty line. – Jakob – 2018-06-28T06:08:23.193

@Jakob I think that's dumb but it was an easy enough fix. – Post Rock Garf Hunter – 2018-06-28T14:47:17.840

3

05AB1E, 34 26 bytes

¶
¡D
©€g
´ā´Q
´sJÇÈ
¥Ä{´нP

Try it online!

Takes the input as a multiline string (input between """). Explanations to come later.

Kaldo

Posted 2018-03-16T08:56:12.330

Reputation: 1 135

1Unless I've misunderstood the rules, the program needs to be able to validate input starting with a newline as well. – Emigna – 2018-03-16T12:04:53.257

@Emigna I think your program has to be able to validate a leading newline only if it itself starts with a leading newline. – Ton Hospel – 2018-03-16T17:48:24.740

I have no idea if this is correct (I am awful at reading specifications): Try it online!

– Magic Octopus Urn – 2018-03-16T18:17:19.173

@MagicOctopusUrn Your answer looks OK to me but I'm wondering about the input: are we allowed to take it as an array ? In your link, your first input is an empty space, not a newline char. – Kaldo – 2018-03-16T18:23:06.233

@MagicOctopusUrn: Depends on the code-page used. I would assume that both 05AB1E and unicode would be fine. Although if you use unicode you can't count all commands as 1 byte each. Both unicode and 05AB1E has 0 at 48 though. – Emigna – 2018-03-16T18:42:34.640

@MagicOctopusUrn: Not for any encoding I know. – Emigna – 2018-03-16T19:22:22.697

1Hey, I hope this doesn't mess with your code too much, but you can drop the leading newline validation. – Dom Hastings – 2018-03-16T21:17:49.743

@DomHastings Thanks for specifying that :-) – Kaldo – 2018-03-17T00:17:04.120

1

Java 10, 209 bytes

A void lambda taking an iterable or array of byte. Indicates true by returning normally, false by throwing a runtime exception. The program expects the final line to be properly terminated, i.e. end with a newline character. The final line of the program is similarly terminated.

Everything is done under UTF-8, with the interpretation that "character" refers to Unicode code points.

Tabs are replaced with spaces in this view.

d
->
{  
long
f= 1,
 h=0 ,
c = - 1
,e ;for 
( byte a:
 d) {var b
=(e = a^10)
<1&e>- 1 ;f=
b?( h ^ f)> 0
?0/0 : f+ 1: f
;h=b?0 :a>-65 ?
h+ 1: h; c =b? c
:c>=0 & ( (c^a )&
1 )<1 ?0/0 :a ; } 
/*1010101010101*/ }

Try It Online

Hex dump

Revert with xxd -p -r on Unix.

640a2d3e0a7b20090a6c6f6e670a663d20312c0a09683d30092c0a63203d
202d20310a2c65203b666f72090a28096279746520613a0a096429207b76
617209620a3d2865203d20615e3130290a3c3126653e2d2031203b663d0a
623f280968095e0966293e09300a3f302f30093a09662b20313a09660a3b
683d623f30093a613e2d3635203f0a682b20313a09683b2063203d623f20
630a3a633e3d30092609280928635e612029260a3120293c31203f302f30
093a61203b207d200a2f2a313031303130313031303130312a2f207d0a

Ungolfed

d -> {
    long f = 1, h = 0, c = ~h, e;
    for (byte a : d) {
        var b = (e = a^10) < 1 & e > -1;
        f = b ?
            (h^f) > 0 ? 0/0 : f + 1
            : f
        ;
        h = b ? 0 :
            a > -65 ? h + 1 : h
        ;
        c = b ? c :
            c >= 0 & ((c^a) & 1) < 1 ? 0/0 : a
        ;
    }
}

f is the expected number of characters on the current line, h is the number of characters seen so far on the current line, c is the last byte seen, and b is whether a is the newline.

The condition a > -65 tests whether a is the first byte in a character. This works because the single-byte (ASCII) characters are nonnegative in 8-bit two's complement, the first byte of longer characters has binary form 11xxxxxx (at least -64 in two's complement), and the non-leading bytes in those characters are of the form 10xxxxxx, at most -65 in two's complement. (Source)

When a character violates the triangular or checkerboard pattern (i.e. a newline appears early or late or a byte of the wrong parity appears), the left branch of the corresponding ternary (in assignment to f or c) activates and the method throws an arithmetic exception.

Jakob

Posted 2018-03-16T08:56:12.330

Reputation: 2 428

0

Python 3 (3.4?), 350 bytes

A tricky challenge for a language as particular about whitespace as Python 3. The submission prints 0 or 1 to standard out and crashes for some inputs. The program expects the final line to be properly terminated, i.e. end with a newline character. The final line of the program is similarly terminated. UTF-8 is used to check byte parity.

Tabs are replaced with spaces in this view.

0
i\
= 1
t=(#
 '0'*
 0) ;(
g,) =(#
 open (1
, "w"),) 
k = eval (
'p' + 'rin'
 + 't' ) #01
for  a in (#0
open ( 0) ):#0
#01010101010101
 a = a [:- 1 ] #
 if ( len (a )<i\
or len (a )>i ):[\
k('0' ),1 /0] #0101
 i, t= -~i, t+ a #01
(k( 2-len ({(c^i )&1\
 for  i,c in  eval (#0
 "enu"+"m"+"erate")(#01
 eval ( " byte"+"s")( t#
,' u8' ) ) } ) ) ) #01010

Works for me with Python 3.4.2; doesn't work on any Python 3 on TIO. Seems to me to be a bug in TIO's interpreters.

Hex Dump

Revert with xxd -p -r on Unix.

300a695c0a3d20310a743d28230a202730272a0a093029203b280a672c29
203d28230a206f70656e0928310a2c09227722292c29200a6b203d206576
616c09280a277027202b202772696e270a202b202774272029202330310a
666f7209206120696e092823300a6f70656e092809302920293a23300a23
30313031303130313031303130310a2061203d2061205b3a2d2031205d20
230a2069660928096c656e09286120293c695c0a6f72096c656e09286120
293e6920293a5b5c0a6b2827302720292c31202f305d2023303130310a20
692c09743d202d7e692c09742b2061202330310a286b2809322d6c656e09
287b28635e69202926315c0a09666f720920692c6320696e09206576616c
092823300a0922656e75222b226d222b2265726174652229282330310a20
6576616c092809220962797465222b22732229280974230a2c2720753827
20292029207d202920292029202330313031300a

Jakob

Posted 2018-03-16T08:56:12.330

Reputation: 2 428