Write a program that turns every 17th bit of a text file to a 1

10

My coworker and I work on a legacy piece of software that we hate sometimes. Whenever you run it, debug asserts come flying everywhere, and it's never a guarantee that anything will work. The motivation for this round of code golf came from my coworker saying the following about our software.

"It's like every time you run this program, you're agreeing to some terms of service that says every 17th bit on your hard drive will be turned into a 1"

Goal: Write a program that will make an exact copy of a file and turn every 17th bit of a text file into a 1

  • You may NOT turn EVERY bit of the file to a 1. i.e. your program must show some intelligence that it is only targeting every 17th bit
  • You may NOT write to the original file in any way shape or form
  • The Winner is the smallest program submission at the end of the month

Have fun with this one! Go!

C. Tewalt

Posted 2014-09-03T04:56:23.497

Reputation: 227

7>

  • Every question needs an objective winning criterion. Most questions are code-golf, i.e., shortest code in bytes wins. A code-challenge needs a well specified scoring system. 2. Turning every 18th bit of a hard drive into a 1 is only possible by writing directly to the drive. This cannot be accomplished by creating and/or modifying files. 3. Doing this will render the entire drive unusable, so a compliant solution will be destructive. I don't know how well the community will receive a request to write malware...
  • < – Dennis – 2014-09-03T05:52:03.257

    @Dennis I agree with the closing of the question, but I do not agree with the reason (I see you were not among the close voters.) I personally had no problem with the insult question, but requesting malware is different. It's irresponsible and potentially criminal, so this question should remain closed. Given that a stack exchange employee closed the insult question (and many people lost a lot of reputation overnight) this question would definitely be deleted too. http://meta.codegolf.stackexchange.com/q/1638/15599.

    – Level River St – 2014-09-03T08:21:49.170

    If the most votes wins, you need to have tagged this a [tag:popularity-contest] – Beta Decay – 2014-09-03T14:46:52.270

    I am not requesting malware! I had a funny experience at work yesterday and thought "Hmm, maybe that would be a fun way to jump into the code golf community." Anyway, I modified the rules a little bit because I see your point. My intention was not to be criminal or irresponsible. – C. Tewalt – 2014-09-03T14:48:53.253

    @matrixugly if you have a the popularity contest tag, you should remove the code challenge tag – proud haskeller – 2014-09-03T17:35:39.407

    I made a bunch of edits, can it not be off topic anymore? – C. Tewalt – 2014-09-03T19:12:07.890

    @matrixugly OK, I realise you're new round here, but if the rules state that the submitted program must corrupt the hard drive that's what valid entries must do, and we don't want to become a manual for writing malware. Changing it to text is a lot more innocuous, and most people know the structure of text files anyway. I've changed my downvote to an upvote, but I'm holding off on the reopen vote, because I think a question like this would go best as code-golf (shortest code) and not popularity-contest (most votes.) – Level River St – 2014-09-04T16:22:54.240

    2I'd vote to re-open this question, if only I had enough rep. :/ – Sammitch – 2014-09-04T19:14:13.510

    3@steveverrill I'll change it to code golf, however I'm going to change it from 18th bit to 17th bit, to make things interesting. – C. Tewalt – 2014-09-04T22:48:09.137

    1@matrixugly 17th bit certainly is more interesting. Bear in mind that it is not good form to change the rules in a way that invalidates existing answers (that's why questions get put on hold, in order to avoid answers being posted that make the question impossible to fix.) However the existing answer doesn't comply with other current rules anyway, so it's not a big problem in this case. – Level River St – 2014-09-04T23:50:43.447

    1How is the file read in? stdin? – Milo – 2014-09-05T03:55:18.110

    1Do we have to write the edited file to another file or can we just leave it? – Beta Decay – 2014-09-05T09:16:55.983

    Do the file need to be written to the disk or a memory/printed representation is ok ? – sebcap26 – 2014-09-05T11:33:10.513

    Answers

    9

    CJam, 22 bytes

    q256b2H#b1f|2H#b256b:c
    

    Try it online.

    Touches every 17th bit, counting from the last.

    I've used STDIN and STDOUT since CJam has no file I/O. If that's not allowed, the program can be wrapped in a Bash script at the cost of 24 extra bytes:

    cjam <(echo q256b2H#b1f\|2H#b256b:c)<"$1">"$2"
    

    How it works

    q                      " Read from STDIN.                                                 ";
     256b                  " Convert to integer by considering the input a base 256 number.   ";
         2H#b              " Convert to array by considering the integer a base 2**17 number. ";
             1f|           " Set the LSB of every integer in the array element to 1.          ";
                2H#b       " Convert to integer by considering the array a base 2**17 number. ";
                    256b   " Convert to array by considering the integer a base 256 number.   ";
                        :c " Turn character codes into characters.                            ";
    

    Dennis

    Posted 2014-09-03T04:56:23.497

    Reputation: 196 637

    1+1, I really need to look into CJam. Awesome how much obfuscation you can get into a 22 byte code that still serves a purpose... – Padarom – 2014-09-05T11:37:16.510

    1Well done. It converted "Take the every 17th bit and turn it to a 1" into ""Tike vhe eöery 17th fiv and turn yt(to c 1" – C. Tewalt – 2014-09-05T16:44:41.740

    Why does this work? I don't follow.. – Claudiu – 2014-09-06T01:20:01.727

    @Claudiu: The basic idea is to take an array of 8-bit integers (bytes), convert it into an array of 17-bit integers, set the LSB of each integer to 1 and undo the array conversion. – Dennis – 2014-09-06T01:55:58.857

    Oh gotcha. I didn't realize "Set the LSB to 1" meant "Set the LSB of each element in the array to 1" – Claudiu – 2014-09-06T03:06:02.370

    Technically, the rule was to make a copy of a file. I'm on the fence as to whether I'll end up accepting this answer since CJam doesn't do file I/O. But I absolutely applaud the creativity and give a "thumbs up" – C. Tewalt – 2014-09-07T18:41:57.097

    1Yes, I wasn't sure if I should post it, but since the Perl answer did basically the same... A Bash wrapper to meet the file I/O requirements would elevate the byte count to 46. More than twice as long, but still the shortest answer. – Dennis – 2014-09-07T18:55:31.643

    1

    @matrixugly sorry! the spec left your file IO intent a little ambiguous. i personally didn't recognize an issue. not to keep harping on the merits of the codegolf sandbox, but the question getting closed and this requirement confusion probably could have been avoided. enjoyed the challenge regardless

    – ardnew – 2014-09-08T04:05:54.250

    6

    Perl 59

    regex substitution on bit strings:

    $/=$\;$_=unpack"B*",<>;s|(.{16}).|${1}1|g;print pack"B*",$_
    

    usage:

    perl this.pl < infile.txt > outfile.txt
    

    ardnew

    Posted 2014-09-03T04:56:23.497

    Reputation: 2 177

    the endianness can be toggled by switching between b and B in the pack templates – ardnew – 2014-09-05T03:58:21.303

    2

    C, 125

    Assumes big-endian and 16-bit integers.

    Works by applying a bitwise-OR on every two bytes.

    Input file is y, output is z.

    unsigned a,b;main(c){void*f=fopen("y","r"),*g=fopen("z","w");while(b=fread(&c,1,2,f))c|=a,a?a/=2:(a=32768),fwrite(&c,1,b,g);}
    

    Ungolfed

    // The commented out /* short */ may be used if int is not 16 bits, and short is. 
    unsigned /* short */ a = 0,b;
    main(/* short */ c){
        void *f = fopen("y", "r"), *g = fopen("z", "w");
        while(b = fread(&c, 1, 2, f)){
          // __builtin_bswap16 may be used if you are using GCC on a little-endian machine. 
          //c = __builtin_bswap16(c);
            c |= a;
            if(a) a >>= 1;
            else a = 32768;
          //c = __builtin_bswap16(c);
            fwrite(&c, 1, b, g);
        }
    }
    

    es1024

    Posted 2014-09-03T04:56:23.497

    Reputation: 8 953

    rules on this question have been updated... – Level River St – 2014-09-04T23:51:06.007

    @steveverrill and the answer has now been updated accordingly – es1024 – 2014-09-05T02:07:18.067

    @Comintern What should happen around the time when a becomes 0: 00000000 00000001 00000000 00000000 10000000 00000000, thus a should be zero at certain points. The machine must use big endian (or else you would have 00000000 10000000 instead of 10000000 00000000, which would give the wrong value). – es1024 – 2014-09-05T06:59:57.120

    Hrm... Never mind. Taking out c = __builtin_bswap16(c); corrected it. – Comintern – 2014-09-05T13:07:40.423

    2

    Python 2, 112 bytes

    b=open('i').read().encode('hex')
    open('o','w').write(('%x'%(int('1'+b,16)|16**len(b)/131071))[1:].decode('hex'))
    

    This sets every 17th big-endian bit, starting 17th from the beginning. It uses no libraries. It works by converting the input file to a gigantic n-bit integer and bitwise ORing with 2**n/(2**17 - 1) == 0b10000000000000000100000000000000001….

    Anders Kaseorg

    Posted 2014-09-03T04:56:23.497

    Reputation: 29 242

    1

    C - 139

    Reads from a file named "i", outputs to a file named "o".

    c;main(){unsigned char b,m=1;void *i=fopen("i","r"),*o=fopen("o","w");for(;(b=fgetc(i))<129;fputc(b,o))((c+=8)%17<8)?b|=m=(m-1)?m/2:128:0;}
    

    With line breaks:

    c;main()
    {
        unsigned char b,m=1;
        void *i=fopen("i","r"),*o=fopen("o","w");
        for(;(b=fgetc(i))<129;fputc(b,o))
            ((c+=8)%17<8)?b|=m=(m-1)?m/2:128:0;
    }
    

    Counts bits of input and then uses a floating bitmask to set every seventeenth bit.

    Comintern

    Posted 2014-09-03T04:56:23.497

    Reputation: 3 632

    1

    Java - 247

    Uses a BitSet and a simple loop instead of handling/masking the bytes manually. Of course this being java, the boilerplate is half the program, so it's not exactly short.

    Still, not last! :D

    import java.util.*;import java.nio.file.*;class F{public static void main(String[]a)throws Exception{BitSet b=BitSet.valueOf(Files.readAllBytes(Paths.get(a[0])));for(int j=0;j<b.size();b.set(j),j+=17);Files.write(Paths.get("o"),b.toByteArray());}}
    

    No-scroll version:

    import java.util.*;
    import java.nio.file.*;
    class F{
        public static void main(String[]a)throws Exception{
            BitSet b=BitSet.valueOf(Files.readAllBytes(Paths.get(a[0])));
            for(int j=0;j<b.size();b.set(j),j+=17);
            Files.write(Paths.get("o"),b.toByteArray());
        }
    }
    

    Geobits

    Posted 2014-09-03T04:56:23.497

    Reputation: 19 061

    1

    Python - 98 bytes

    Read from i, write to o. Uses bitarray library https://pypi.python.org/pypi/bitarray

    from bitarray import*;a=bitarray();a.fromfile(open('i','rb'));a[::17]=1;a.tofile(open('o','wb'))
    

    ungolfed

    from bitarray import *
    a=bitarray()
    a.fromfile(open('i','rb'))
    a[::17]=1
    a.tofile(open('o','wb'))
    

    user590028

    Posted 2014-09-03T04:56:23.497

    Reputation: 111

    Wouldn't it need to be a[::17]=1? – undergroundmonorail – 2014-09-08T10:38:04.387

    Also, I believe you can save a byte with from bitarray import* and a=bitarray(). – undergroundmonorail – 2014-09-08T10:39:06.117

    0

    Cobra - 308

    use System.Text.RegularExpressions
    class P
        def main
            t,b='',File.readAllBytes('x')
            for n,i in b.numbered,for l in 8,b[n]=if(l,b[n],0)+if(Regex.replace(t+='00000000'[(j=Convert.toString(i,2)).length:]+j,'.{17}',do(m as Match)='[m]'[:-1]+'1')[n*=8:n+8][7-l]<c'1',0,2**l)to uint8
            File.writeAllBytes('y',b)
    

    Every time I do one of these 'manipulate the individual bits of something' challenges, I wish that either Cobra or the .NET standard library had a binary string => integer converter.

    Οurous

    Posted 2014-09-03T04:56:23.497

    Reputation: 7 916

    0

    Javascript (+HTML5), 282

    Probably not the shortest, but it's user friendly :D

    It's cross browser, but it seems that chrome is the only one allowing it when the html file is a local file (= access with file://...). For the other browsers, you need to put it on a web server.

    The output file should be saved to the default download directory, maybe with a file prompt (depending on your configuration).

    <input type=file onchange="r=new FileReader();r.onloadend=function(){w=window;a=new Uint8Array(r.result);for(i=17;i<a.length*8;i+=17)a[i/8>>0]|=1<<8-i%8;w.location.replace(w.URL.createObjectURL(new Blob([a],{type:'application/octet-binary'})));};r.readAsArrayBuffer(this.files[0])">
    

    Ungolfed version :

    <input type=file onchange="
        var reader = new FileReader();
        reader.onloadend = function() {
            var arr = new Uint8Array(reader.result);
            for(var i = 17 ; i < arr.length * 8 ; i += 17) {
                arr[Math.floor(i / 8)] |= 1 << (8 - (i % 8));
            }
            window.location.replace(
                window.URL.createObjectURL(
                    new Blob([arr], {type: 'application/octet-binary'})
                )
            );
        };
        reader.readAsArrayBuffer(this.files[0]);
    ">
    

    sebcap26

    Posted 2014-09-03T04:56:23.497

    Reputation: 1 301

    0

    Python 3 - 187 bytes


    Reads in from i and writes to o.

    Code:

    o=open;j="".join;f=list(j(format(x,"08b")for x in o("i","rb").read()))
    f[16::17]="1"*(len(f)//17)
    with o("o","wb") as f2:f2.write(bytes(int(j(f[i*8:(i+1)*8]),2)for i in range(len(f)//8)))
    

    Ungolfed:

    # read file and convert to binary string e.g. "101010010101010101"
    f = list("".join(format(x, "08b") for x in open("in.txt", "rb").read()))
    # set every 17th bit to 1
    f[16::17] = "1" * (len(f)//17)
    with open("out.txt","wb") as f2:
        data = []
        for i in range(len(f)//8)): # for each byte
            byte = "".join(f[i*8:(i+1)*8] # get each byte
            data.append(int(byte),2) # convert to int
        f2.write(bytes(data)) # convert to byte string and write
    

    matsjoyce

    Posted 2014-09-03T04:56:23.497

    Reputation: 1 319

    -1

    Python 3 - 103 chars

    Change f to the path of the file you want to read and o to path of the file you want to write to.

    l=open;t=list(l(f,'r').read())
    for i in range(len(t)):
     if i%18==0:t[i]='1'
    l(o,'w').write(''.join(t)) 
    

    Beta Decay

    Posted 2014-09-03T04:56:23.497

    Reputation: 21 478

    6It's every 17th bit, not byte. – matsjoyce – 2014-09-05T12:34:54.707

    1Also, it's 17th, not 18th. – Dennis – 2014-09-05T18:50:57.837