Cooke and Wheatstone telegraph, five-needle

20

3

Definition

According to Wikipedia:

The Cooke and Wheatstone telegraph was an early electrical telegraph system dating from the 1830s invented by English inventor William Fothergill Cooke and English scientist Charles Wheatstone. It was the first telegraph system to be put into commercial service. The receiver consisted of a number of needles which could be moved by electromagnetic coils to point to letters on a board. This feature was liked by early users who were unwilling to learn codes, and employers who did not want to invest in staff training.

It works like this:

Scheme of Cooke and Wheatstone telegraph, five-needle

In the middle are five needles, which can be deflected clockwise (as is the case of the middle needle) or anti-clockwise (as is the case of the last needle).

In the picture above, the two deflected needles point to the letter G, which means that the letter being transmitted/received is the letter G.

Note that the letters C, J, Q, V, X, Z are missing and thus have to be substituted with other letters.

Task

You will receive a character in ABDEFGHIKLMNOPRSTUWY as input, and you will output the corresponding configuration of the five needles, with undeflected as |, deflected clockwise as /, and deflected anti-clockwise as \.

Testcases

This covers all the possible inputs

input output
A     /|||\
B     /||\|
D     |/||\
E     /|\||
F     |/|\|
G     ||/|\  (explanation: see above)
H     /\|||
I     |/\||
K     ||/\|
L     |||/\
M     \/|||
N     |\/||
O     ||\/|
P     |||\/
R     \|/||
S     |\|/|
T     ||\|/
U     \||/|
W     |\||/
Y     \|||/

Rules/Requirements

  • Each submission should be either a full program or function. If it is a function, it must be runnable by only needing to add the function call to the bottom of the program. Anything else (e.g. headers in C), must be included.
  • If it is possible, provide a link to a site where your program can be tested.
  • Your program must not write anything to STDERR.
  • Standard Loopholes are forbidden.
  • Your program can output in any case, but it must be printed (not an array or similar).

Scoring

Programs are scored according to bytes, in UTF-8 by default or a different character set of your choice.

Eventually, the answer with the least bytes will win.

Submissions

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

Leaderboard

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

/* Configuration */

var QUESTION_ID = 87104; // 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 = 48934; // 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>

Leaky Nun

Posted 2016-07-31T18:04:34.717

Reputation: 45 011

Answers

6

C, 124 107 98 bytes

As a function:

x,i;W(char*v){for(i=strcspn(" MRUYH NSWEI OTBFK PADGL",v);x<5;++x)putchar(x^i%5?x^i/5?124:92:47);}

// main(int c,char**v){W(v[1]);}

This works by using rotating the grid 45 degrees and looking up the row/column from the resulting block.


As a full executable (107 bytes):

x;main(i,v)char**v;{for(i=strcspn(" MRUYH NSWEI OTBFK PADGL",v[1]);x<5;++x)putchar(x^i%5?x^i/5?124:92:47);}

An alternative full executable: (same bytecount but takes input from stdin and includes newline after output)

main(i){char*r=" MRUYH NSWEI OTBFK PADGL",b[]="|||||";i=strchr(r,getchar())-r;b[i%5]=47;b[i/5]=92;puts(b);}

Breakdown:

x;                                      // Implicit int declaration
main(i,v)char**v;{                      // K&R function declaration to save a byte
    for(i=strcspn("<...>",v[1]);        // Find index of input in lookup table
        x<5;++x)                        // Loop 0 to 4
        putchar(x^i%5?x^i/5?124:92:47); //  Print /, \ or | depending on value of i
}

Alternate breakdown:

main(i){
    char*r="<...>",                     // Store lookup table
    b[]="|||||";                        // Malleable base string for return
    i=strchr(r,getchar())-r;            // Find input in lookup table
    b[i%5]=47;                          // Set correct char in output to /
    b[i/5]=92;                          // Set correct char in output to \
    puts(b);                            // Print result
}

Bonus: 0-9 extension from the wikipedia page:

x;main(i,v)char**v;{for(i=strcspn(" MRUY6H NSW7EI OT8BFK P9ADGL 012345",v[1]);x<5;++x)putchar(x^i%6?x^i/6?124:92:47);}

Bonus bonus: a complete (if messy) program for both encoding and decoding messages:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

static const char *REF = " MRUY6H NSW7EI OT8BFK P9ADGL 012345 ";

char sub(char c) {
    c = toupper(c);
    if(c == 'C') { c = 'K'; }
    if(c == 'J') { c = 'G'; }
    if(c == 'Q') { c = 'K'; }
    if(c == 'V') { c = 'W'; }
    if(c == 'X') { c = 'S'; }
    if(c == 'Z') { c = 'S'; }
    return c;
}

void print_encoded(char c) {
    char b[] = "|||||";
    const char *p = strchr(REF, sub(c));
    if(!p) { return; }
    int i = p - REF;
    if(i) {
        if(i%6 < 5) { b[i%6] = '/'; }
        if(i/6 < 5) { b[i/6] = '\\';}
    }
    puts(b);
}

char decode(const char *m) {
    int pf = 5;
    int pb = 5;
    for(int x=0;x<5;++x) {
        if(m[x] == '/') {
            pf=x;
        } else if(m[x] == '\\') {
            pb=x;
        } else if(m[x] == '\0') {
            return '!';
        }
    }
    return REF[pb*6+pf];
}

int main(int c, const char **v) {
    int inArg;
    bool isDecode;
    if(c > 1 && (strcmp(v[1], "-h") == 0 || strcmp(v[1], "--help") == 0)) {
        printf("Usage:\n  %s [-d] [<input>]\n\n", v[0]);
        printf("Converts input to/from Cooke and Wheatstone 5-needle encoding.\n\n");
        printf("If no input arguments are given, takes input from stdin.\n\n");
        printf("Parameters:\n");
        printf("  -h --help   Displays help.\n");
        printf("  -d --decode Switches to decode mode.\n");
        printf("\n");
        return 0;
    } else if(c > 1 && (strcmp(v[1], "-d") == 0 || strcmp(v[1], "--decode") == 0)) {
        inArg = (c > 2 ? 2 : 0);
        isDecode = true;
    } else if(c > 1) {
        inArg = 1;
        isDecode = false;
    } else {
        inArg = 0;
        isDecode = false;
    }
    if(isDecode) {
        if(inArg == 0) {
            char ln[6];
            while(scanf("%5s", ln) == 1) {
                putchar(decode(ln));
            }
        } else {
            for(int p = inArg; p < c; ++p) {
                for(const char *q = v[p], *e = strchr(v[p], '\0'); q < e; q += 5) {
                    while(*q == ' ') { ++q; }
                    putchar(decode(q));
                }
            }
        }
        putchar('\n');
    } else {
        if(inArg == 0) {
            int c;
            while((c = getchar()) != EOF) {
                print_encoded(c);
            }
        } else {
            for(const char *p = v[inArg]; *p; ++p) {
                print_encoded(*p);
            }
        }
    }
    return 0;
}

Dave

Posted 2016-07-31T18:04:34.717

Reputation: 7 519

5

CJam, 42 bytes

r"HEBAMRUYIFDNSWKGOTLP"5e!{_$"/\|"er}%_&er

Test it here

Although there's a lot of structure to the outputs I'm not entirely sure yet I can compute the results efficiently (in terms of bytes). So this is still a lookup table, but I'm generating the list of possible needle configurations via permutations of the list [0 1 2 3 4].

Martin Ender

Posted 2016-07-31T18:04:34.717

Reputation: 184 808

3

Python 2, 172 152 151 79 bytes

lambda x:r'/|||\/|||/\|||/|\||/||\|/||'['APONM LKIHY GFEWU DBTSR'.find(x):][:5]

No algorithm, just a lookup table.

Saved 20 bytes thanks to @LeakyNun!

Saved a byte thanks to @TheBikingViking!

Saved a whopping 72 bytes thanks to @Keeta!

Copper

Posted 2016-07-31T18:04:34.717

Reputation: 3 684

You can use find instead of index for -1 byte. – TheBikingViking – 2016-07-31T20:43:50.603

2If you take advantage of the overlap of the slashes, you can reduce by 72 characters to something like lambda x:r'/|||/|||/|||/|||/|||/||'['APONM LKIHY GFEWU DBTSR'.find(x):][:5] – Keeta - reinstate Monica – 2016-08-01T17:26:34.883

3

MATL, 50 bytes

'!#$kYAqof^EZC}40iA*9n4JK?45/J~v'6Y2'\|/'Za5eioZ)!

Try it online!

Short explanation

The code decompresses the shown string ('!#$...J~v') into a string containing \, | and /; reshapes it into an array where each column corresponds to a letter; and indexes that array with the input character.

Long explanation

The compressesed string has been obtained (offline) using base-3 to base-95 encoding. The data from the challenge has been arranged into a long string of \, | and /, where each group of 5 characters corresponds to a letter. This string is interpreted as the base-3 representation of some big number, which is converted to base-95, using all printable ASCII chars as digits. The result is the compressed string that appears in the code ('!#$...J~v').

The program starts decompressing this string, that is, converting from base-95 to base-3 with alphabet \, |, /. The decompressed string is reshaped into a 5-row 2D char array, in which each column representing a letter. Let us call this array Λ. This array will be indexed using the ASCII code point of the input letter.

The array Λ includes two tricks:

  1. It has been filled with dummy values for the five letters missing between A and Y;
  2. It starts with L (not A) and then proceeds circularly.

The reasons for these two tricks are as follows:

  1. Letter A has code point 65. The last letter that needs to be handled is Y, with code point 89. So we need to handle a range of 25 values, even if some intermediate ones (such as letter C) don't exist. To facilitate indexing, the five missing letters between A and Y have been filled with a dummy representation, so they do have a column in Λ. Thus, Λ has size 5×25.

  2. Modular indexing is used. So letter A, or number 65, is the same as 65 mod 25, that is 15. Therefore A needs to be in column 15 of Λ, B in column 16, ..., and Y in column 14.

Commented code

'!#$kYAqof^EZC}40iA*9n4JK?45/J~v'     % Compressed string (in base-95)
6Y2                                   % Predefined literal 'AB...Z': source alphabet
                                      % for decompression
'\|/'                                 % Target alphabet for decompression
Za                                    % Change of base representation (decompress)
5e                                    % Reshape into 5-row array `Λ`
i                                     % Input letter
o                                     % Convert to number (ASCII code point)
Z)                                    % Use as column index into `Λ`
!                                     % Transpose into a row. Implicitly display

Luis Mendo

Posted 2016-07-31T18:04:34.717

Reputation: 87 464

1

05AB1E, 37 34 bytes

Code:

"/\|||"œ€JÙ•3wxìeNðƒ2xGÑäß•36BIk<è

Uses the CP-1252 encoding. Try it online!.

Adnan

Posted 2016-07-31T18:04:34.717

Reputation: 41 965

1

JavaScript (ES6), 97 89 bytes

c=>(n=`ABEHMDFINRGKOSULPTWY`.search(c),s=[...`|||||`],s[4-n%5]=`\\`,s[n>>2]=`/`,s.join``)

Edit: Saved 3 bytes by switching to a lookup table that doesn't need padding. Saved 5 bytes by setting array elements instead of trying to edit a string.

Explanation: The table ABEHMDFINRGKOSULPTWY is organised so that if you split it into 5 groups of 4 adjacent letters then each letter in the group is on the same / slant in the diagram, while if you split it into 5 groups by taking the index modulo 5 then each letter in the group is on the same \ slant in the diagram. These latter groups are in reverse order but that's easily handled by subtracting from 4. (Arranging the table so that the former groups were in reverse order cost more to fix.)

Neil

Posted 2016-07-31T18:04:34.717

Reputation: 95 035

1

VBA, 106 bytes

Function v(s):v="|||||":p=InStr(1,v &"MRUYH NSWEI OTBFK PADGL",s):Mid(v, p\5)="\":Mid(v, (p Mod 5)+1)="/"

Final byte is enter which auto-generates End Function. With acknowledgements to the scheme @Dave devised.

Invoke in spreadsheet or in VBA Immediate window eg with ?v("K")

Joffan

Posted 2016-07-31T18:04:34.717

Reputation: 832

0

Mathematica, 129 bytes

""<>(IntegerDigits[IntegerDigits[36^^3ucgb2abu46m2rewohw225q4lc6hczypueyb3,190][[LetterNumber@#]],3,5]/.{0->"|",1->"/",2->"\\"})&

Anonymous function. Takes a string as input and returns a string representing its code as output. Uses a relatively simple encoding scheme.

LegionMammal978

Posted 2016-07-31T18:04:34.717

Reputation: 15 731

0

Python 2, 115 111 bytes

This is a simple implementation, but it could use some golfing. Suggestions welcome.

def f(c):s=["|"]*5;a=0xdb52384ebd9f46caa72899c838d50/25**(ord(c)-65)%25;s[a/5]="/";s[a%5]="\\";return''.join(s)

Ungolfed:

def f(c):
    s = ["|"] * 5
    d = ord(c) - 65
    # 0xdb52384ebd9f46caa72899c838d50 is our lookup number
    # 0040004100304231200043322110342300120124130214000304
    # in hexadecimal
    a = 0xdb52384ebd9f46caa72899c838d50 / 25**d % 25
    s[a/5] = "/"
    s[a%5] = "\\"
    return ''.join(s)

Sherlock9

Posted 2016-07-31T18:04:34.717

Reputation: 11 664

0

Pyth, 27 bytes

@{.p"/|\||"x."AW
Ú/Ç\x94E\x18µð££

Replace the escapes \x94, \x18 with the corresponding bytes.

Try it online

How it works

@                                      index into this list:
  .p"/|\||"                              permutations of /|\||
 {                                       deduplicate
                                       at index:
            ."AW\nÚ/Ç\x94E\x18µð££"      compressed string: EBAHIFDNSWKGOTLPMRU
           x                       Q     index in that of input (or -1 for Y)

Pyth, 32 bytes

Without using any hard-coded lookup tables.

@o-xN\/xN\\{.p"/\|||"x-rG2"CJQVX

Try it online

How it works

@                                    index into this list:
            .p"/\|||"                  all permutations of /\|||
           {                           deduplicate
 o                                     sort by the following key for N in the list:
   xN\/                                  index of / in N
  -    xN\\                              … minus index of \ in N
                                     at index:
                       rG2             capitalized alphabet
                      -   "CJQVX"      minus CJQVX
                     x           Q     index in that of input

Anders Kaseorg

Posted 2016-07-31T18:04:34.717

Reputation: 29 242

0

C, 78 bytes

i;f(x){for(i=5;i--;)putchar("|/\\|"["^\\ NXLFPH DBow{} gsyc q a"[x-65]>>i&3]);}

version shown is all printable ASCII, 79 bytes. The second \\ can be replaced by any single byte that has the same last 6 bits as the \ character 0x5C : 0x1C (if your compiler allows it), 0x9C or 0xDC.

The input character is looked up in the magic string which contains values for A to Y (including spaces for the unsupported characters CJQVX.) The character from the lookup table is interpreted as five overlapping 2-bit codes where:

01 = /   10 = \    00 or 11 = |

Commented code in test program

/*
magic string codes: bytes are 01XXXXXX
A     /|||\ 011110 ^
B     /||\| 011100 \\
D     |/||\ 001110 N 
E     /|\|| 011000 X
F     |/|\| 001100 L
G     ||/|\ 000110 F
H     /\||| 010000 P
I     |/\|| 001000 H
K     ||/\| 000100 D
L     |||/\ 000010 B
M     \/||| 101111 o
N     |\/|| 110111 w
O     ||\/| 111011 {
P     |||\/ 111101 }
R     \|/|| 100111 g
S     |\|/| 110011 s
T     ||\|/ 111001 y
U     \||/| 100011 c
W     |\||/ 110001 q
Y     \|||/ 100001 a

                                     ABBCDEFGHIJKLMNOPQRSTUVWXY*/
i;f(x){for(i=5;i--;)putchar("|/\\|"["^\\ NXLFPH DBow{} gsyc q a"[x-65]>>i&3]);}

j;
main(){
  j=getchar();
  f(j);
} 

Level River St

Posted 2016-07-31T18:04:34.717

Reputation: 22 049

0

Ruby, 159 bytes

v=[1,2,3,4,7,8,9,13,14,19];w=v+v.map{|e|25+e};a="HEBAIFDKGLMRUYNSWOTP";b="\\/"
x=w[a.index($*[0][0])];g="|"*5;y=(x>25)?0:1;g[(x/5)%5]=b[y];g[x%5]=b[1-y];puts g

Explanation:

The positions of the deflected needles are mapped to 0..4, and thought as a base-5 number (2 digits). For A-L, the numbers are "as is"; for M-Z, add 25 to the number. The map is from variables a to w.

Given the number corresponding to the letter, use its base-5 representation: the 5s digit for the first needle, the 1s digit for the second needle, and the 25s digit for the needles' directions.

A program to encode an entire string, instead of one character, is just a bit longer: 172 bytes.

v=[1,2,3,4,7,8,9,13,14,19];w=v+v.map{|e|25+e};a="HEBAIFDKGLMRUYNSWOTP";b="\\/"
$*[0].each_char{|c|x=w[a.index(c)];g="|"*5;y=(x>25)?0:1;g[(x/5)%5]=b[y];g[x%5]=b[1-y];puts g}

jose_castro_arnaud

Posted 2016-07-31T18:04:34.717

Reputation: 229