27
\$\begingroup\$

Your task: given an input string, determine whether the binary representation of that string does not have 4 1s or 0s in a row, anywhere. Furthermore, your code itself should not contain any such runs of four in a row.

Test Cases

String      Binary              Result

U3          01010101 00110011   Truthy

48          00110100 00111000   Falsy

Foobar      01000110 01101111   Falsy
            01101111 01100010
            01100001 01110010

Feeber      01000110 01100101   Truthy
            01100101 01100010
            01100101 01110010

$H          00100100 01001000   Truthy

<Empty>     -                   Truthy

Rules

  • Input will always be within the range of printable ASCII, including whitespace characters.
    • Your code may use any encoding, since it only matters at the bit level.
  • Because this condition prevents the use of white space and many other chars, your code actually can contain such runs of four in a row, at a 10 byte penalty for each run.
    • A run of 5 1s or 0s counts as two runs, 6 in a row counts as three runs, etc.
  • Input will be a string or char array, not any other form.
  • You may write a complete program or function.
  • You must provide the binary representation of your code in your answer.

Good luck, lowest score wins!

This script might help you with your challenge, put your code in the input and it will give you your code's binary representation, it's length, your penalty, and the total score, if you're using UTF-8.

Leaderboard

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

/* Configuration */

var QUESTION_ID = 111758; // 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 = 60042; // 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() {
  jQuery.ajax({
    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+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    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)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

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) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        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;
    ++place;
    
    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);
    jQuery("#answers").append(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.push(languages[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);
    jQuery("#languages").append(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">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<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>
  </tbody>
</table>
<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>
  </tbody>
</table>

\$\endgroup\$
16
  • 1
    \$\begingroup\$ I'm pretty sure that snippet is buggy, e.g. I see || listed and that is 0111110001111100. \$\endgroup\$ Commented Mar 1, 2017 at 5:46
  • \$\begingroup\$ Right, good point. One second. \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 5:47
  • 2
    \$\begingroup\$ Would have been even more fun if the task was to find the score of a string. \$\endgroup\$
    – Adám
    Commented Mar 1, 2017 at 6:54
  • 1
    \$\begingroup\$ @JonathanAllan well, the way I intended it, it does, but upon further reflection I don't really see a reason for that, so I'll change it. \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 15:03
  • 1
    \$\begingroup\$ @Pavel The scoring is not based solely on bytes if there are penalties. This makes it a [code-challenge], not [code-golf]. From the tag wiki: "If source code length is not the primary scoring criterion, consider using another tag instead." TL;DR, since the actual score =/= the program's byte count, and the shortest code doesn't mean getting the best score, it's not [code-golf]. \$\endgroup\$
    – mbomb007
    Commented Mar 1, 2017 at 20:23

18 Answers 18

19
\$\begingroup\$

Jelly, 18 bytes + 0 penalties = 18

79Ọv2;$ḅ⁹b2+4\b4FẠ

Returns 1 if there are no equal bit strings of length 4 or more in the 8-bit word representation of the ASCII string input, and 0 otherwise.

Try it online! (test suite with some extra cases added)

Using Jelly's codepage there are no length 4 or longer substrings of equal bits:

7    0x37    00110111
9    0x39    00111001
Ọ    0xB5    10110101
v    0x76    01110110
2    0x32    00110010
;    0x3B    00111011
$    0x24    00100100
ḅ    0xD4    11010100
⁹    0x89    10001001
b    0x62    01100010
2    0x32    00110010
+    0x2B    00101011
4    0x34    00110100
\    0x5C    01011100
b    0x62    01100010
4    0x34    00110100
F    0x46    01000110
Ạ    0xAB    10101011

With equal-bit run lengths of:

221323221211111312322133122121221111213121123132213111122211311332313211313211111112

How?

Tricks to avoid demerits are:

  • to avoid the "convert from character to ordinal" monad O by converting the number 79 to a character using followed by an "evaluation of Jelly code with input", v.

  • to avoid direct conversion to binary using B (0x42, 1000010) by the simple two-byte alternative b2 using the generic dyadic base conversion.

  • to avoid a few normal choices for counting the runs of equal bits - first choice would be "all overlapping slices of given length", (0xF5 or 11110101). A second choice might be to utilise "all sublists", (0xCF or 11001111).
    A workaround I used before the current one was to take the increments (between consecutive elements) with I (putting zeros and ones on an equal footing), and to look for any occurrence of three zeros in a row. To do that I converted all the zeros to ones by use of the binomial function with 2c i.e. 2Cx - making the -1s become 0s the 1s become 2s, and the 0s become 1s; that way the code can look for the first occurrence of the sublist [1,1,1] with w111.
    However a shorter way became apparent - to mimic the action of "all overlapping slices of given length", , one can use a 4-wise overlapping reduce with some dyad, <dyad>4\. If this is performed with addition, +4\, it counts the 1s, so then any 0 or 4 being present is the indicator to return a truthy value. The issue here is that the next obvious step would be to take the modulo 4 of that to put the 0 and 4 entries on an equal footing while leaving the other possible values (1, 2, and 3) unchanged, but +\%4 has \% inside, which has bit-value 0101110000100100. In order to avoid that penalty the numbers are all converted to base 4 with b4 (mapping 0 to [0], 1 to [1], 2 to [2], 3 to [3], and 4 to [1,0]) and the whole list is flattened with F. Now the last test is simply to check if there are any 0s in the list, achievable directly with the monad .

79Ọv2;$ḅ⁹b2+4\b4FẠ - Main link: printable ASCII character list
79                 - 79
  Ọ                - character from ordinal : 'O'
   v               - evaluate as Jelly code : input -> 'O' converts the input to ordinals
      $            - last two links as a monad
    2              -     2
     ;             -     concatenate (why? see the note beneath the code block)
       ḅ⁹          - convert from base 256 : gets an integer representing the byte string
         b2        - convert to base 2 AKA binary
            4\     - 4-wise reduce with
           +       -     addition (sums all overlapping slices of length 4)
              b4   - convert to base 4 (vectorises)
                F  - flatten into a single list
                 Ạ - any falsy?

Note: The reason a 2 is concatenated with the ordinal list is to deal with the edge cases where the only run of 4 in the input string is in the leading zeros of the very first character - these characters are: tab; line-feed; and carriage-return. Without this the base 256 conversion effectively strips leading zeros from the (fully concatenated) binary string; with the leading 2 the leading zeros will be there and an extra one and zero before them. Since no printable ASCII has exactly three leading zeros there is no need to discard these extra bits before the rest of the check.

\$\endgroup\$
6
  • \$\begingroup\$ I'm assuming you could just add a negate or something similar to comply with The value you output/return for truthy and falsy must be consistent which I interpret as "same value each time for truthy" and same for falsy. Also your true/false is opposite the ones in the question. \$\endgroup\$
    – Emigna
    Commented Mar 1, 2017 at 11:13
  • \$\begingroup\$ I just enquired about that - when I originally read it (many hours ago) I took "The value you output/return for truthy and falsy must be consistent." to mean we could output either way around so long as it stayed the same way around between runs... A straight forward negate will incur demerit. \$\endgroup\$ Commented Mar 1, 2017 at 11:16
  • \$\begingroup\$ I could definitely save some as well if I don't have to do that. Down to a very low score with the new version I'm working on. I hope you're the one who's interpreted correctly :) \$\endgroup\$
    – Emigna
    Commented Mar 1, 2017 at 11:25
  • \$\begingroup\$ Well I've given a two byte suffix that does the trick, giving both the same way around as the examples and strictly consistent values of 0 and 1 if need be. \$\endgroup\$ Commented Mar 1, 2017 at 11:44
  • \$\begingroup\$ Nice. Looking forward to seeing how you did it. I only get down to 15 if I ignore all demerits :) \$\endgroup\$
    – Emigna
    Commented Mar 1, 2017 at 11:54
11
\$\begingroup\$

Java 7, 812 726 673 644 634 616 599 588 145 bytes + 10*44 = 585

boolean
b(char[]b){String
g="";for(char
c:b)g+=g.format("%"+(1-1)+"8d",new
Integer(Integer.toString(c,2)));return!g.matches(".*(.)\\1\\1\\1.*");}

I am using newlines instead of spaces to try to minimize penalty...

Try it online!

Binary

01100010011011110110111101101100011001010110000101101110000010100110001000101000011000110110100001100001011100100101101101011101011000100010100101111011010100110111010001110010011010010110111001100111000010100110011100111101001000100010001000111011011001100110111101110010001010000110001101101000011000010111001000001010011000110011101001100010001010010110011100101011001111010110011100101110011001100110111101110010011011010110000101110100001010000010001000100101001000100010101100101000001100010010110100110001001010010010101100100010001110000110010000100010001011000110111001100101011101110000101001001001011011100111010001100101011001110110010101110010001010000100100101101110011101000110010101100111011001010111001000101110011101000110111101010011011101000111001001101001011011100110011100101000011000110010110000110010001010010010100100101001001110110111001001100101011101000111010101110010011011100010000101100111001011100110110101100001011101000110001101101000011001010111001100101000001000100010111000101010001010000010111000101001010111000101110000110001010111000101110000110001010111000101110000110001001011100010101000100010001010010011101101111101


Old bitshifting solution 141 bytes + 10*101 = 1,151

boolean
b(char[]b){
int
o=0,p=0,i;
for(char
c:b){for(i=0;i<8;){if((c&(1<<i++))<1){o=0;p++;}else{p=0;o++;}if(3<o|3<p)return
6<5;}}return
5<6;}

Try it online!

Binary

011000100110111101101111011011000110010101100001011011100000101001100010001010000110001101101000011000010111001001011011010111010110001000101001011110110000101001101001011011100111010000001010011011110011110100110000001011000111000000111101001100000010110001101001001110110000101001100110011011110111001000101000011000110110100001100001011100100000101001100011001110100110001000101001011110110110011001101111011100100010100001101001001111010011000000111011011010010011110000111000001110110010100101111011011010010110011000101000001010000110001100100110001010000011000100111100001111000110100100101011001010110010100100101001001111000011000100101001011110110110111100111101001100000011101101110000001010110010101100111011011111010110010101101100011100110110010101111011011100000011110100110000001110110110111100101011001010110011101101111101011010010110011000101000001100110011110001101111011111000011001100111100011100000010100101110010011001010111010001110101011100100110111000001010001101100011110000110101001110110111110101111101011100100110010101110100011101010111001001101110000010100011010100111100001101100011101101111101
\$\endgroup\$
3
  • \$\begingroup\$ Nice trick with the newlines. Counting 00000/11111 as two runs, 000000/111111 as three, etc. I count 101 runs total. \$\endgroup\$ Commented Mar 1, 2017 at 16:01
  • \$\begingroup\$ @ETHproductions Fixed \$\endgroup\$
    – Poke
    Commented Mar 1, 2017 at 16:15
  • \$\begingroup\$ This should just win since Java was never meant for this \$\endgroup\$
    – user63187
    Commented Mar 1, 2017 at 16:21
9
\$\begingroup\$

APL (Dyalog Classic), 26 + 1 × 10 = 36 bytes

Notes

Contains one 4-run of 1s. Requires ⎕IO←0 which is default on many systems. Note that this must be run on a Classic interpreter so that strings are one byte per character.

Submission

1≠⊃⌽⌈\∊(×4\¨⍳≢⍬⍬)⍷¨⊂11⎕DR⍞

Try it online!

Binary source

0011000110101100100111001011001010010111010111001011100100101000110101110011010001011100101010001011110010111011101010111010101100101001101110101010100010011011001100010011000110001100010001000101001010001101

Explanation

 Prompt for string input

11 ⎕DR convert to 1-bit Boolean (1) Data Representation

 enclose so we can apply multiple things to it

() ⍷¨ binary indicators where each of the following sequences begin…

× sign (no-op on binary data, but included as spacer to split runs)

4 \¨ expand (copy) each to length four

 the integers up to

 the tally of

⍬⍬  the list consisting of two empty numeric lists

 enlist (flatten)

⌈\ cumulative maximum

�� reverse

 pick the first

1 ≠ is one different from? (i.e. NOT)

Walk-through

We will input "48" to the ungolfed un-de-runned version ~ ∨/ ∊ (0 0 0 0)(1 1 1 1) ⍷¨ ⊂ 11 ⎕DR ⍞:

11 ⎕DR ⍞ converts "48" to 0 0 1 1 0 1 0 0 0 0 1 1 1 0 0 0 (i.e. Dec 52 56, Hex 34 38)

(0 0 0 0)(1 1 1 1) ⍷¨ ⊂ finds beginnings of 0-runs and 1-runs; (0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0) (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)

∨/ ∊ looks if there is any Truth (i.e. any runs); 1

~ negates that; 0

\$\endgroup\$
4
\$\begingroup\$

Jelly 28 + 140 demerits = 168

L8_0xṭ
OBUÇ€UFŒr<4FẠ

Explanation

OB

Converts the argument to a list of their binary encodings, e.g.

“U3”OB -> [[1, 0, 1, 0, 1, 0, 1], [1, 1, 0, 0, 1, 1]]

The next piece

UÇ€U

fixes the fact that the above list can be missing characters as B does not include leading zeros. ǀ calls the previously defined link over each element which restores that

L8_0xṭ

This link is equivalent to

lambda x: x + repeat(0, 8 - len(x))

For example

[1, 1, 0, 0, 1, 1] L8_0xṭ -> [1, 1, 0, 0, 1, 1, [0, 0]]

We upend the list before and after this operation (the two U calls in that list) to get that to be a prepend rather than an append. The next piece

FŒr

Flattens the list (F), giving the total binary string of the ASCII encoding, and run-length encodes the output (Œr). So for example

L8_0xṭ
“U3”OBUÇ€UF -> [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0]

and

L8_0xṭ
“U3”OBUÇ€UFŒr -> [[1, 1], [0, 1], [1, 1], [0, 1], [1, 1], [0, 1], [1, 1], [0, 1], [1, 2], [0, 2], [1, 2], [0, 2]]

Finally we check whether each element is < 4 (thankfully this is always true for 0,1) with

<4F

For example

L8_0xṭ
“U3”OBUÇ€UFŒr<4F -> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Finally

Returns 0 if any of those are falsy (in this case, 0).

Code Pages

In Jelly's code page this code is 20 bytes but has 27 runs worth of rule violations. In UTF-8 it is 28 bytes but with only 14 runs worth of violations.

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

05AB1E, 22 + 3 * 10 = 52

Saved 2 penalty runs borrowing the delta trick from Jonathan Allan's Jelly answer

$Ç256+bvy¦}J¥J6Ìb¦å2ÍQ

Try it online!

Explanation

$                       # push 1 and input (1 to handle the empty string)
 Ç                      # convert to list of ascii values
  256+                  # add 256 to each
      b                 # convert each to binary
       vy¦}             # chop off the leading digit of each
           J            # join to string
            ¥           # take delta's
             J          # join to string
              6Ìb¦      # push bin(6+2)[1:] = 000 
                  å     # check if this exists in the delta's string
                   2ÍQ  # compare to 2-2 = 0

Binary representation of the code

00100100 11000111 00110010 00110101 00110110 00101011 01100010 01110110
01111001 10100110 01111101 01001010 10100101 01001010 00110110 11001100
01100010 10100110 11100101 00110010 11001101 01010001

The 3 penalty runs come from vy¦} which is used to chop off the first byte in each binary string, but it's still cheaper than the 4 runs we'd get from the shorter €¦.

\$\endgroup\$
2
  • \$\begingroup\$ @JonathanAllan: I mention it a bit at the end (but not in detail), but unfortunately the binary representation of in CP-1252 is 10000000 which incurs a penalty of 4 by itself. \$\endgroup\$
    – Emigna
    Commented Mar 2, 2017 at 8:19
  • \$\begingroup\$ Ah, so you do! ...and my Python code for getting the representation was incorrect as I put # coding: cp1252 at the top >_< \$\endgroup\$ Commented Mar 2, 2017 at 8:27
3
\$\begingroup\$

Perl, 33 + 160 = 193

32 bytes of code + 1 byte for -n flag.

$_=unpack"B*";print!m+(.)\1\1\1+

(the input needs to be supplied without final newline. The Try it online link has -l flag on to remove newlines, but for a single input, it's not needed).

Try it online!

xxd dump :

00000000: 00100100 01011111 00111101 01110101 01101110 01110000  $_=unp
00000006: 01100001 01100011 01101011 00100010 01000010 00101010  ack"B*
0000000c: 00100010 00111011 01110000 01110010 01101001 01101110  ";prin
00000012: 01110100 00100001 01101101 00101011 00101000 00101110  t!m+(.
00000018: 00101001 01011100 00110001 01011100 00110001 01011100  )\1\1\
0000001e: 00110001 00101011                                      1+

A few notes:

  • (.)\1\1\1 saves a few penalties over (.)\1{3}, 1111|0{4} or any other regex I could think of (using 0 or {} comes at a heavy cost).
  • print saves ~8 points over using -p and $_= because p contains a run of 4 0 while n doesn't.
  • + as a delimiter for the regex saves a run of 1 that is in /.
  • doing two steps instead of one with !~ saves two runs (~ is 01111110 in binary).
  • unpack"B*" is quite expensive (4 runs), but I couldn't find cheaper (solutions bases on ord will be even more expensive).
\$\endgroup\$
3
\$\begingroup\$

PHP, 98 + 270 = 368 bytes

I wanted to take a different approach from what Titus proposed, and ended with a slightly longer, yet less penalized program.

$v=unpack('H*',$argv[1]);$e=base_convert($v[1],16,2);echo!stristr($e,'0000')&&!stristr($e,'1111');

Outputs 1 for truthy, nothing for falsey.

Try it here !

Binary-encoded :

0010010001110110001111010111010101101110011100000110000101100011011010110010100
0001001110100100000101010001001110010110000100100011000010111001001100111011101
1001011011001100010101110100101001001110110010010001100101001111010110001001100
0010111001101100101010111110110001101101111011011100111011001100101011100100111
0100001010000010010001110110010110110011000101011101001011000011000100110110001
0110000110010001010010011101101100101011000110110100001101111001000010111001101
1101000111001001101001011100110111010001110010001010000010010001100101001011000
0100111001100000011000000110000001100000010011100101001001001100010011000100001
0111001101110100011100100110100101110011011101000111001000101000001001000110010
1001011000010011100110001001100010011000100110001001001110010100100111011

(22 occurences of 0000 and 5 occurrences of 1111, hence 270 bytes of penalty)

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

PHP, 86 bytes+370=456

for(;$c=ord($argn[$i++]);)$s.=sprintf("%08b",$c);echo!preg_match("#(.)\\1\\1\\1#",$s);

creates the binary string and uses a regex to detect streaks. Output is 1 for truthy; empty for falsy.

Run with echo '<string>' | php -nR '<code>'.

tweaks

  • backreferences save 100 penalty for 3 bytes. (-97 score)

abandoned ideas

  • join(array_map(str_split())) would cost 31 bytes and 90 penalty
  • and <?=/$argv[1] instead of echo/$argn cost another 2+40.
  • str_pad(decbin()) is costlier than sprintf: 7 bytes and 110 penalty.
  • strtr saves 80 penalty for 13 extra bytes, but backreferences are better.
  • Grouping the backreferences #(.)\\1{3} saves 3 bytes, but adds 10 penalty.
  • foreach costs 3+50.
  • No saving possible on the variable names.
  • output buffering costs 42+120.
\$\endgroup\$
1
  • \$\begingroup\$ Add a § at for(§; for -9. \$\endgroup\$
    – Christoph
    Commented Apr 25, 2017 at 12:45
2
\$\begingroup\$

JavaScript (ES8), 91 bytes + 430 penalty = 521 total

This will output 1 for true and 0 for false.

s=>1-/(.)\1\1\1/.test([...s].map(c=>c.charCodeAt().toString(2).padStart(3+5,1-1)).join(""))
01110011001111010011111000110001001011010010111100101000001011100010100101011100001100010101110000110001010111000011000100101111001011100111010001100101011100110111010000101000010110110010111000101110001011100111001101011101001011100110110101100001011100000010100001100011001111010011111001100011001011100110001101101000011000010111001001000011011011110110010001100101010000010111010000101000001010010010111001110100011011110101001101110100011100100110100101101110011001110010100000110010001010010010111001110000011000010110010001010011011101000110000101110010011101000010100000110011001010110011010100101100001100010010110100110001001010010010100100101110011010100110111101101001011011100010100000100010001000100010100100101001

Try it

f=

s=>1-/(.)\1\1\1/.test([...s].map(c=>c.charCodeAt().toString(2).padStart(3+5,1-1)).join(""))

console.log(f("U3"))
console.log(f("48"))
console.log(f("Foobar"))
console.log(f("Feeber"))
console.log(f("$H"))
console.log(f(""))

\$\endgroup\$
2
  • \$\begingroup\$ padStart isn't in ES6. \$\endgroup\$
    – Neil
    Commented Apr 25, 2017 at 12:22
  • \$\begingroup\$ Damnit! I keep forgetting to change to ES8 whenever I use it (same with ES7 and Array.includes()) - thanks, @Neil. \$\endgroup\$
    – Shaggy
    Commented Apr 25, 2017 at 12:24
2
\$\begingroup\$

MATL, 16 bytes + 60 = 76 bytes

8&B!1e&Y'tgw4<Z&

Try it at MATL Online

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

CJam, 23 bytes

Uses Jonathan Allan's idea to work with deltas.

1q256b2b2ew::-[TTT]#)g-

Try it online!

Binary representation:

00110001011100010011001000110101
00110110011000100011001001100010
00110010011001010111011100111010
00111010001011010101101101010100
01010100010101000101110100100011
001010010110011100101101

Explanation:

1     e# Push a 1 for (much) later, because we can't use ! for logical NOT.
q     e# Read input.
256b  e# Treat characters as base 256 digits.
2b    e# Convert to binary. The last two steps together give us a flat binary
      e# representation of the input, avoiding both :~ and e_ for flattening.
2ew   e# Get all pairs of consecutive bits.
::-   e# Compute their differences.
[TTT] e# Push [0 0 0].
#     e# Find its index in the list of differences, or -1 if not found.
)g    e# Increment and take signum. We've now got the result we want but 
      e# with the wrong truth value.
-     e# Subtract it from the 1 we pushed earlier to negate the truth value.
\$\endgroup\$
1
\$\begingroup\$

Pyth, 19 + 12 * 10 = 139

!|}*"0"4.BQ}*"1"4.B

Binary

00100001 01111100 01111101 00101010
00100010 00110000 00100010 00110100
00101110 01000010 01010001 01111101
00101010 00100010 00110001 00100010
00110100 00101110 01000010         

Explanation

!|}*"0"4.BQ}*"1"4.B
            *"1"4     # Repeat  ; '1111'
                 .B   # Convert ; input as a binary string
           }          # In      ; '1111' in the binary repr
   *"0"4              # Repeat  ; '0000'
        .BQ           # Convert ; input as a binary string
  }                   # In      ; '0000' in the binary repr
 |                    # Or      ; 4 consequent idenical digits found
!                     # Negate  ; True if not found, False if found
\$\endgroup\$
0
1
\$\begingroup\$

JavaScript, 173 + 89 * 10 = 1063

JavaScript is not good at converting strings to binary, but I figured I'd give this challenge a shot just for fun.

Code:

function(n){b="";for(var t=0;t<n.length;t++)c=[n.charCodeAt(t).toString(2)],c.unshift(Array(8-c[0].length+1).join(0)),b+=c.join("");return b.match(/[1]{4,}|[0]{4,}/g)?!1:!0}

Binary:

0110011001110101011011100110001101110100011010010110111101101110001010000110111000101001011110110110001000111101001000100010001000111011011001100110111101110010001010000111011001100001011100100010000001110100001111010011000000111011011101000011110001101110001011100110110001100101011011100110011101110100011010000011101101110100001010110010101100101001011000110011110101011011011011100010111001100011011010000110000101110010010000110110111101100100011001010100000101110100001010000111010000101001001011100111010001101111010100110111010001110010011010010110111001100111001010000011001000101001010111010010110001100011001011100111010101101110011100110110100001101001011001100111010000101000010000010111001001110010011000010111100100101000001110000010110101100011010110110011000001011101001011100110110001100101011011100110011101110100011010000010101100110001001010010010111001101010011011110110100101101110001010000011000000101001001010010010110001100010001010110011110101100011001011100110101001101111011010010110111000101000001000100010001000101001001110110111001001100101011101000111010101110010011011100010000001100010001011100110110101100001011101000110001101101000001010000010111101011011001100010101110101111011001101000010110001111101011111000101101100110000010111010111101100110100001011000111110100101111011001110010100100111111001000010011000100111010001000010011000001111101

Explanation:

Create a string to work with:

b="";

Loop over each character in the string:

for(var t=0;t<n.length;t++)

Create an array and convert the string to binary using character code:

c=[n.charCodeAt(t).toString(2)]

Add the leading zeros to the array:

c.unshift(Array(8-c[0].length+1).join(0))

Join the array back into a string:

b+=c.join("")

Return whether or not a string of four or more 1's or 0's was found in the binary result using a regular expression:

return b.match(/[1]{4,}|[0]{4,}/g)?!1:!0

Fiddle:

https://jsfiddle.net/vrtLh97c/

Stats:

Length: 173 bytes Penalty: 890 Total: 1063

Code Golf is hard :)

\$\endgroup\$
4
  • \$\begingroup\$ Can you provide the binary representation of your code, and document the penalties? \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 17:05
  • \$\begingroup\$ This has a penalty of 890 for a total score of 1063. \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 17:49
  • \$\begingroup\$ Added totals to original post. \$\endgroup\$ Commented Mar 1, 2017 at 18:20
  • 1
    \$\begingroup\$ Using 1-1 instead of 0 in a few places could save you some demerits. \$\endgroup\$
    – Poke
    Commented Apr 26, 2017 at 20:31
1
\$\begingroup\$

Pyth, 21 + 2 * 10 = 41

J-T2-4eS%2.nr.[dJ.BwJ

Try it online!

Binary representation:

01001010 00101101 010101[00 00]110010 00101101 00110100 01100101 01010011
00100101 00110010 00101110 01101110 01110010 00101110 01011011 01100100
01001010 00101110 01[0000]10 01110111 01001010
\$\endgroup\$
1
\$\begingroup\$

Retina, 101 + 1390 = 1491

The code contains unprintable characters, but they show up in Chrome if you edit the post. - is \x01-\x7f.

¶
±
S_`
%(S`±
{2`
$`
}T01`-`_o
)Ms`.
.+
$*
+`(1+)\1
${1}0
01
1
m+`^(?!.{8})
0
0{8}|¶

M&`(.)\1{3}
0

Try it online

This code uses this ord, followed by conversion to binary and a simple check for overlapping sequences of four.

In binary:

11000010101101100000101011000010101100010000101001010011010111110110000000001010001001010010100001010011011000001100001010110001000010100111101100110010011000000000101000100100011000000000101001111101010101000011000000110001011000000000000100101101011111110110000001011111011011110000101000101001010011010111001101100000001011100000101000101110001010110000101000100100001010100000101000101011011000000010100000110001001010110010100100000001000010100010010001111011001100010111110100110000000010100011000000110001000010100011000100001010011011010010101101100000010111100010100000111111001000010010111001111011001110000111110100101001000010100011000000001010001100000111101100111000011111010111110011000010101101100000101000001010010011010010011001100000001010000010111000101001000000010111101100110011011111010000101000110000

Penalties counted with this Python program.

\$\endgroup\$
3
  • \$\begingroup\$ Please provide a hexdump and binary representation, since this contains unprintables. \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 18:26
  • \$\begingroup\$ I already said what/where the unprintables are, along with providing a program that can print the binary string (uncomment the line at the bottom). \$\endgroup\$
    – mbomb007
    Commented Mar 1, 2017 at 19:36
  • \$\begingroup\$ Alright, then.. \$\endgroup\$
    – Pavel
    Commented Mar 1, 2017 at 19:49
1
\$\begingroup\$

Python 2, 74 (length) + 130 (penalty) = 204

k,n=2*[1]
for[c]in(input(n)*2*2*2)[:1:-1]:n,k=k*ord(c[:n%16%15])+n/2,k*128

Output is via exit code; 0 is truthy, 1 is falsy. Produces garbage output to STDOUT and STDERR.

Try it online!

Binary dump

00000000: 01101011 00101100 01101110 00111101 00110010 00101010  k,n=2*
00000006: 01011011 00110001 01011101 00001010 01100110 01101111  [1].fo
0000000c: 01110010 01011011 01100011 01011101 01101001 01101110  r[c]in
00000012: 00101000 01101001 01101110 01110000 01110101 01110100  (input
00000018: 00101000 01101110 00101001 00101010 00110010 00101010  (n)*2*
0000001e: 00110010 00101010 00110010 00101001 01011011 00111010  2*2)[:
00000024: 00110001 00111010 00101101 00110001 01011101 00111010  1:-1]:
0000002a: 01101110 00101100 01101011 00111101 01101011 00101010  n,k=k*
00000030: 01101111 01110010 01100100 00101000 01100011 01011011  ord(c[
00000036: 00111010 01101110 00100101 00110001 00110110 00100101  :n%16%
0000003c: 00110001 00110101 01011101 00101001 00101011 01101110  15])+n
00000042: 00101111 00110010 00101100 01101011 00101010 00110001  /2,k*1
00000048: 00110010 00111000                                      28
\$\endgroup\$
2
  • \$\begingroup\$ I have found that 0 is pretty bad to include. It's better to use 1-1 \$\endgroup\$
    – Poke
    Commented Mar 2, 2017 at 2:04
  • \$\begingroup\$ @Poke I just realized my mistake. The result is unused, so I'm not sure why I picked 0 in the first place. \$\endgroup\$
    – Dennis
    Commented Mar 2, 2017 at 2:06
1
\$\begingroup\$

JavaScript (ES6), 87 88 + 390 380 = 477 468 bytes

s=>1-/(.)\1\1\1/.test(s.replace(/[\S\s]/g,c=>(256+c.charCodeAt()).toString(2).slice(1)))

In binary:

01110011001111010011111000110001001011010010111100101000001011100010100101011100001100010101110000110001010111000011000100101111001011100111010001100101011100110111010000101000011100110010111001110010011001010111000001101100011000010110001101100101001010000010111101011011010111000101001101011100011100110101110100101111011001110010110001100011001111010011111000101000001100100011010100110110001010110110001100101110011000110110100001100001011100100100001101101111011001000110010101000001011101000010100000101001001010010010111001110100011011110101001101110100011100100110100101101110011001110010100000110010001010010010111001110011011011000110100101100011011001010010100000110001001010010010100100101001

Over half of the penalty is down to zeros in the overlap between bytes, rather than the runs in the following characters: =>//pa//=>aCoAo.

Since the /s (00101111) pay a penalty I tried a) switching from test to match b) switching from replace to map but the score always ended up higher. However I did find that [\S\s] was an improvement over [^]. Edit: Saved 9 bytes overall thanks to @Shaggy.

\$\endgroup\$
6
  • \$\begingroup\$ I think the | in the character class is not supposed to be there \$\endgroup\$ Commented Mar 1, 2017 at 16:51
  • \$\begingroup\$ @ETHproductions I got it right in my explanation... \$\endgroup\$
    – Neil
    Commented Mar 1, 2017 at 19:37
  • \$\begingroup\$ You could shave 10 off your penalty by replacing the ! with 1- for a total of 468. And you could make a further saving of 5 bytes by replacing [\S\s] with . for a total of 463. \$\endgroup\$
    – Shaggy
    Commented Apr 25, 2017 at 11:47
  • \$\begingroup\$ @Shaggy Thanks, although I'm not sure whether newlines count as printable, so I'll play it safe for now. \$\endgroup\$
    – Neil
    Commented Apr 25, 2017 at 12:27
  • \$\begingroup\$ Does js support a multiline regex flag? If so, you could accept Shaggy's suggestion and add the flag to still save bytes. \$\endgroup\$
    – Pavel
    Commented Sep 1, 2017 at 20:54
1
\$\begingroup\$

Pyth, 16 + 1 x 10 = 26 bytes

qZsm:.BQjk*4]dZ2
   m           2  for d being the natural numbers below 2
            ]d        [d]
          *4          [d,d,d,d]
        jk            "dddd"
    :         Z       search for the above in
     .BQ              the binary representation of the input
                      (true/false)
  s               sum the 2-element array generated above, 1 for True, 0 for False
qZ                is equal to 0

Try it online!

Binary

01110001 01011010 01110011 01101101
00111010 00101110 01[0000]10 01010001
01101010 01101011 00101010 00110100
01011101 01100100 01011010 00110010

Tricks

The following alternations are done to avoid the demerits:

  • Using qZ (is equal to zero) instead of ! (negate)
  • Using :xy0 (search for) instead of }xy (is sublist)
  • Using Z (variable, default to zero) instead of 0 (zero itself)

Improvements

I do not find any way to circumvent the penalty. We have these commands related to binary:

  • .B binary (00101110 01[0000]10)
  • C charcode (01[0000]11)
  • .O octary (00101110 0100[1111])
  • .H hexadecimal (00101110 01001[000)

Note that .H will also give us a penalty, because every printable character has its binary representation starting with 0. Therefore, I used the most direct one, which is .B, directly converting it to binary.

I can end with .H to avoid the penalty, but it costs me 27 bytes...

Generation

I found all allowed characters, which are those that do not contain 0000 or 1111, and that do not end with 000 (because the next character must start with 0):

  • "#$%&')*+,-.12345679:;DEFGIJKLMNQRSTUVWYZ[\]bcdefgijklmnqrstuvw

Here are the characters that end with 1000. They can only be used at the end:

  • (8HXhx
\$\endgroup\$

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