Diary

Welcome! :-)

This is both a wiki (a website editable by all) and a blog (an online diary about the stuff Alex Schroeder reads and does). If you’re a friend or relative, you might be interested in reading Life instead of this page. If you’ve come here from an RPG blog, you might want to head over to RPG. There are other similar categories to be found on the SiteMap.

Für Rollenspieler gibt es ebenfalls eine eigene RSP Kategorie.

2016-12-09 Advent of Code in Python

It was pretty easy to slide back into Python. I used Python 3 because I hear that’s what one ought to use. I really like the Python documentation. A very good read. You can tell because I prefer reading the documentation to searching for examples on StackExchange. Well done!

Part 1: Count how many strings comply with the following specification:

  1. Each string consists of some letters, with one or more sections in square brackets, e.g. alex[berta]otto.
  1. The string must have a four character palindrome consisting of two different letters outside square brackets, e.g. otto in the example above.
  1. No such string may be found withing square brackets.
  2. There may be multiple sets of square brackets within the string.
import sys
import re

def has_palindrome(word):
    m = re.search(r"([a-z])([a-z])\2\1", word)
    # aaaa is not a valid palindrome
    if (m and m.group(1) != m.group(2)):
        return 1

def check_line(line):
    inside = 0
    outside = 0
    parts = re.findall('([a-z]+)(?:\[([a-z]+)\])?', line)
    for part in parts:
        if (has_palindrome(part[0])):
            outside += 1
        if (has_palindrome(part[1])):
            inside += 1
    return inside == 0 and outside > 0

def check_input():
    sum = 0
    for line in sys.stdin:
        if check_line(line):
            sum += 1
    return sum
    
if __name__ == '__main__':
    print (str(check_input()))

Part 2: Count how many strings comply with the following specification:

  1. Each string consists of some letters, with one or more sections in square brackets, e.g. ala[lala]otto.
  1. The string must have a three character palindrome consisting of two different letters outside square brackets, e.g. ala, and a matching inverted three character palindrome inside any of the square brackets, e.g. lal in the example above.
  1. There may be multiple sets of square brackets within the string.

This was surprisingly more difficult!

import sys
import re

def check_line(line):
    inside = []
    outside = []
    for part in re.findall('([a-z]+)(?:\[([a-z]+)\])?', line):
        outside.append(part[0])
        if part[1]:
            inside.append(part[1])
    for word in outside:
        for i in range(len(word) - 2):
            if word[i] == word[i+2] and word[i] != word[i+1]:
                for other in inside:
                    if re.search(word[i+1] + word[i] + word[i+1], other):
                        return 1

def check_input():
    sum = 0
    for line in sys.stdin:
        if check_line(line):
            sum += 1
    return sum
    
if __name__ == '__main__':
    print (str(check_input()))

Call using python part1.py < data and python part2.py < data.

I also wondered about an integrated Python debugger for Emacs. Sadly, I used print statements all over the place as I was searching for bugs.

Tags:

Comments on 2016-12-09 Advent of Code in Python

You can use the fileinput module for reading the data: https://docs.python.org/2/library/fileinput.html

Instead of for i in range(len(word) - 2): you can do something like for a, b, c in zip(word, word[1:], word[2:]):

Instead of re.search you can simply use the “in” operator.

Radomir Dopieralski 2016-12-09 08:23 UTC


Thanks!

– AlexSchroeder 2016-12-09 11:40 UTC

Add Comment

2016-12-09 Advent of Code in Clojure

I have had even less time for Advent of Code these days and I have fallen behind. Sadness! And yet, I wanted to try something new. A while ago I bought two Clojure books, The Joy of Clojure and Practical Clojure. And then I didn’t read them and it never went far. These simple coding exercises seem like a good opportunity to dig up these small half forgotten attempts at learning a language.

Clojure it is! And I did suffer. Immutable data structures and no idea of how to do stuff, it was bad. But the miracle of Google, StackExchange and ClojureDocs allowed me to quickly get going.

Part 1: Given a list of input strings, find the solution which consists of the most common letter in each position. With the following input, the solution would be “alex”.

aeex
alrx
blet

Part 2: Given the same input, find the solution which consists of the least common letters. With the input above, the solution would be “bert”.

(ns day06.core
  (:gen-class)
  (:use [clojure.string :only [split join]])
  (:use [clojure.pprint :only [pprint]]))

(defn make-hashes
  [letters]
  (apply vector (map (fn [c] {}) letters)))

(defn read-lines
  []
  (map (fn [s] (split s #""))
       (line-seq (java.io.BufferedReader. *in*))))

(defn process-line
  [line hashes]
  (loop [[c & rest] line  
         hashes hashes
         i 0]
    (if c
      (recur rest
             (update-in hashes [i c] (fn [v] (if v (+ v 1) 1)))
             (+ i 1))
      hashes)))

(defn process
  ([lines] (process lines (make-hashes (first lines))))
  ([lines hashes]
   (if hashes
     (let [line (first lines)]
       (if line
         (recur (rest lines)
                (process-line line hashes))
         hashes)))))

(defn result
  [hashes]
  (println "Most common letters: "
           (join (map (fn [hash]
                        (first (first (sort-by val > hash))))
                      hashes)))
  (println "Least common letters:"
           (join (map (fn [hash]
                        (first (last (sort-by val > hash))))
                      hashes))))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (result (process (read-lines))))

Run the example using lein run < data.

I even found the time to write some tests for the code on GitHub.

Since I haven’t written any Clojure code in ages, I’d love to heard about improvements or style issues!

Tags:

Comments on 2016-12-09 Advent of Code in Clojure

I guess I should get rid of pprint.

– AlexSchroeder 2016-12-09 13:50 UTC

Add Comment

2016-12-08 Cider Woes

I’m trying to get Cider to work on my laptop running OSX and failing. This makes me unhappy because I managed to do it on a Windows machine with lots of Cygwin so I felt that getting it to work on a Mac should be a breeze.

Basically, what I have set up my little project using lein and can run it from the command line and from eshell, and I use Clojure Mode, but when I run M-x cider-jack-in I see is this in my *Messages* buffer:

Starting nREPL server via /Users/alex/bin/lein update-in :dependencies conj \[org.clojure/tools.nrepl\ \"0.2.12\"\ \:exclusions\ \[org.clojure/clojure\]\] -- update-in :plugins conj \[cider/cider-nrepl\ \"0.15.0-SNAPSHOT\"\] -- repl :headless...
Mark set
nREPL server started on 53929
[nREPL] Establishing direct connection to localhost:53929 ...
error in process filter: nrepl--direct-connect: [nREPL] Direct connection failed
error in process filter: [nREPL] Direct connection failed

But now I have three buffers named *nrepl-server ... with contents such as nREPL server started on port 53872 on host 127.0.0.1 - nrepl://127.0.0.1:53872.

This reminds me… My Mac keeps deleting my /etc/hosts file which means that localhost is borked:

$ ping localhost
ping: cannot resolve localhost: Unknown host

So I added it back to /etc/hosts.

127.0.0.1 localhost

Then I killed the three nrepl-server buffers and tried C-c M-j again.

And it works. Phew!

Sometimes writing these posts just helps me focus as I’m troubleshooting.

Tags:

Comments on 2016-12-08 Cider Woes

Your mac deleting /etc/hosts file sounds really bad

– nickf 2016-12-08 22:53 UTC


Yeah. I think it rewrites the file whenever the system updates? So any code that depends on localhost mapping to 127.0.0.1 usually breaks after an update. Gah!

– Alex Schroeder 2016-12-08 22:59 UTC


Hi Alex, that deletion of /etc/hosts sounds vary odd. I use emacs, cider, lein etc almost daily on OSX and have not run itno that issue ever. I do use hombrew for emacs and lein. I am now running macOSSierra, but have been doing clojure et. al. on a Macbook for the past few years and used the last2 or 3 OSX versions.

– Tim X 2016-12-09 08:30 UTC


Strange. I also have OpenVPN installed on the Mac and it puts stuff into the file. Googling for the problem shows that some versions of a Cisco VPN used to do the same. I should just deinstall it and see whether that resolves it.

– AlexSchroeder 2016-12-09 11:47 UTC

Add Comment

2016-12-05 Advent of Code in Perl 5

Today I don’t have a lot of time for Advent of Code. So, Perl 5 it is. My Swiss Army knife!

I’ll have to save the interesting languages for days when I have a lot of time. This will be hard. :(

Question 1: You start with a string such as “abc” and append an index, then compute the MD5 hash, and if its hex representation starts with five zeroes, then the sixth character is a letter in your password. Keep increasing the index until you have eight letters for your password. Using “abc” as the example, the first match would be “abc3231929” which produces a hash of “00000155f8105dff7f56ee10fa9b9abd” and thus the first letter of the password would be “1”.

use Modern::Perl;
use Digest::MD5 qw(md5_hex);

my $prefix = 'abc';
my $i = 0;
my $length = 0;
my $pwd;
while ($length < 8) {
  my $digest = md5_hex($prefix . $i++);
  if ('00000' eq substr($digest, 0, 5)) {
    $pwd .= substr($digest, 5, 1);
    $length++;
    print "$pwd\n";
  }
}

Question 2: Same as before, but now the the sixth character indicates the position of the seventh character. In the example above, this means that position 1 has the number “5”. The password is zero indexed. Ignore positions outside the password and don’t overwrite characters you’ve alreay found.

use Modern::Perl;
use Digest::MD5 qw(md5_hex);

$" = '';
my $prefix = 'abc';
my $i = 0;
my $length = 0;
my @pwd = qw(_ _ _ _ _ _ _ _);
while ($length < 8) {
  my $digest = md5_hex($prefix . $i++);
  if ('00000' eq substr($digest, 0, 5)) {
    my $p = hex(substr($digest, 5, 1));
    next if $p >= 8 or $pwd[$p] ne "_";
    my $c = substr($digest, 6, 1);
    $length++;
    $pwd[$p] = $c;
    print "@pwd\n";
  }
}

Tags:

Add Comment

2016-12-04 Advent of Code in Java

I use Java to earn money, even though I don’t really like working with it. Everything is so damn verbose. If you return to writing Java code within Emacs you’ll realize that a big chunk of the code you’re writing gets written by the IDE, e.g. imports. Static typing and object orientation has resulted in basically every object defining a separate interface which you need to memorize. It’s hard to write code without completion. Anyway, I decided to solve today’s Advent of Code riddles using Java.

First question. Your input is a list of strings. Each string has the form NAME-ID[CHECKSUM]. NAME consists of lowercase letters separated by dashes, ID is a number and CHECKSUM are the five most common letters in NAME, sorted by frequency with ties broken by alphabetical sorting. What is the sum of all the IDs where the CHECKSUM is correct?

This checksum is valid, for example and thus the sum would be 123:

zzzyyyxxxwwva-123[xyzwa]

The enjoyable part about this exercise was that I got to use Java 8 streams. Yay me!

import java.lang.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;

class Part1 {

  Scanner scanner = new Scanner(System.in);
  Pattern p = Pattern.compile("([a-z-]+)-([0-9]+)\\[([a-z]{5})\\]");

  String readRoom() {
    return scanner.next();
  }

  int readValidSectorId () {
    String room = readRoom();
    Matcher m = p.matcher(room);
    if (m.matches()) {
      String name = m.group(1);
      int id = Integer.parseInt(m.group(2));
      String checksum = m.group(3);
      // count the occurences of every character
      HashMap<Character, Integer> charMap = new HashMap<Character, Integer>();
      for (Character c: name.toCharArray()) {
        if (charMap.containsKey(c)) {
          charMap.put(c, charMap.get(c) + 1);
        } else {
          charMap.put(c, 1);
        }
      }
      // get the five most common characters
      String computed =
        charMap.keySet().stream()
        .filter((elem) -> elem.charValue() != '-')
        .sorted(new Comparator<Character>() {
            @Override
            public int compare(Character a, Character b) {
              int r = charMap.get(b).compareTo(charMap.get(a));
              if (r == 0) {
                return a.compareTo(b);
              }
              return r;
            }
          })
        .limit(5)
        .map(Object::toString)
        .collect(Collectors.joining());
      if (checksum.equals(computed)) {
        return id;
      }
      // System.out.println(computed + " != " + checksum);
    }
    return 0;
  }

  int sum () {
    int sum = 0;
    try {
      while (true) {
        sum += readValidSectorId();
      }
    } catch (NoSuchElementException e) {
      // end of file
    }
    return sum;
  }

  public static void main(String args[]) {
    Part1 p = new Part1();
    System.out.println("Sum: " + p.sum());
  }
}

Second question. For every string with correct CHECKSUM, rotate the letters in NAME by the ID. The example given shows how the letter q in a NAME with ID 343 would end up a v. To find the actual answer asked for in the question, grep the result for a line containing “north”.

import java.lang.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;

class Part2 {

  Scanner scanner = new Scanner(System.in);
  Pattern p = Pattern.compile("([a-z-]+)-([0-9]+)\\[([a-z]{5})\\]");

  String readRoom() {
    return scanner.next();
  }

  void readValidSectorId () {
    String room = readRoom();
    Matcher m = p.matcher(room);
    if (m.matches()) {
      String name = m.group(1);
      int id = Integer.parseInt(m.group(2));
      String checksum = m.group(3);
      // count the occurences of every character
      HashMap<Character, Integer> charMap = new HashMap<Character, Integer>();
      for (Character c: name.toCharArray()) {
        if (charMap.containsKey(c)) {
          charMap.put(c, charMap.get(c) + 1);
        } else {
          charMap.put(c, 1);
        }
      }
      // get the five most common characters
      String computed =
        charMap.keySet().stream()
        .filter((elem) -> elem.charValue() != '-')
        .sorted(new Comparator<Character>() {
            @Override
            public int compare(Character a, Character b) {
              int r = charMap.get(b).compareTo(charMap.get(a));
              if (r == 0) {
                return a.compareTo(b);
              }
              return r;
            }
          })
        .limit(5)
        .map(Object::toString)
        .collect(Collectors.joining());
      if (checksum.equals(computed)) {
        // do the rotating
        String s = name.chars()
          .map(c -> {
              if (c == '-') {
                return ' ';
              } else {
                return ((c + id - 'a') % 26 + 'a');
              }
            })
          .mapToObj(c -> Character.toString((char)c))
          .collect(Collectors.joining());
        System.out.println(room + " = " + s);
      }
    }
  }

  void read () {
    try {
      while (true) {
        readValidSectorId();
      }
    } catch (NoSuchElementException e) {
      // end of file
    }
  }

  public static void main(String args[]) {
    Part2 p = new Part2();
    p.read();
  }
}

Tags:

Add Comment

2016-12-03 Donations

Time to start another of these pages. I start these about once a year and keep updating it.

2015 was not a very generously year…

I think simply paying for journalism these days should also count as a donation. After all, I could have read it for free, online.

Today I followed yet another Guardian link and saw a “support us” plea. Ok, I thought. I had already once seen such a link and registered and saw that I needed to enter an annual obligation, which I did not do. But today I saw a one-off PayPal link. That works for me.

Talking about newspapers: for years, I’ve been paying double the subscription fee in order to support the local leftist weekly newspaper [1] and the German translation of Le Monde Diplomatique [2].

  • ProWOZ (CHF 530, half of which is a “real donation”)

Right now, it’s the Wikipedia fundraising campaign. OK, why not. I might not like their politics, and the deletionism, but in general, I must say: I use Wikipedia every single day of my life. It’s the most awesome thing on the net. It’s hard to imagine a time without it.

And I regularly donate about $10/month to the EFF and the FSF, and €120/year to the FSFE.

Tags:

Tags:

Add Comment

2016-12-03 Advent of Code in C

Since the previous two days of Advent of Code went so well, I decided to up the ante and try different programming languages. Today: C. I haven’t written C since abandoning German Atlantis.

The question is this: given three numbers per line, count the potential triangles. “In a valid triangle, the sum of any two sides must be larger than the remaining side.”

Here goes. Save as day3.c, compile using make day3, test from the shell using echo 1 2 3 | ./day3 (not a triangle), save your input in a file called data and run using ./day3 < data.

#include <stdio.h>
#include <stdlib.h>

int read_num () {
  int k;
  if (scanf("%d", &k) == 1) {
    return k;
  }
  return 0;
}

int * read_triangle() {
  static int t[3];
  for (int i = 0; i < 3; i++) {
    int n = read_num();
    if (n == 0) {
      if (i == 0) {
	return 0;
      }
      fprintf(stderr, "triangle incomplete, missing %d sides.\n", 3 - i);
      abort();
    }
    t[i] = n;
  }
  return t;
}

int legal(int *t) {
  if (t[0] + t[1] > t[2]
      && t[0] + t[2] > t[1]
      && t[1] + t[2] > t[0]) {
    return 1;
  }
  return 0;
}

int main() {
  int n = 0;
  int *t;
  while ((t = read_triangle()) != 0) {
    /* if (legal(t) == 1) { */
    /*   printf("triangle: [%d %d %d]\n", t[0], t[1], t[2]); */
    /* } else { */
    /*   printf("not a triangle: [%d %d %d]\n", t[0], t[1], t[2]); */
    /* } */
    n += legal(t);
  }
  printf("Counted %d triangles.\n", n);
  return 0;
}

The setup I had was particularly fortuitous for the second part because the array could just as well hold three triangles instead of just one, and the legal function could return a count instead of just 1 or 0.

In part two, we count vertical triangle candidates. In other words, we read three rows and get three potential triangles. Here’s the example given:

101 301 501
102 302 502
103 303 503
201 401 601
202 402 602
203 403 603

This counts as 6 triangles, because every [101 102 103] is a triangle, [201 202 203] is a triangle, etc.

#include <stdio.h>
#include <stdlib.h>

int read_num () {
  int k;
  if (scanf("%d", &k) == 1) {
    return k;
  }
  return 0;
}

int * read_three_triangles() {
  static int t[9];
  for (int i = 0; i < 9; i++) {
    int n = read_num();
    if (n == 0) {
      if (i == 0) {
	return 0;
      }
      fprintf(stderr, "triangle incomplete, missing %d sides.\n", 3 - i);
      abort();
    }
    t[i] = n;
  }
  return t;
}

int legal(int *t) {
  int n = 0;
  for (int i = 0; i < 3; i++) {
    if (t[i + 0] + t[i + 3] > t[i + 6]
	&& t[i + 0] + t[i + 6] > t[i + 3]
	&& t[i + 3] + t[i + 6] > t[i + 0]) {
      n++;
    }
  }
  return n;
}

int main() {
  int n = 0;
  int *t;
  while ((t = read_three_triangles()) != 0) {
    n += legal(t);
  }
  printf("Counted %d triangles.\n", n);
  return 0;
}

All in all I must say C was quite easy to slide back into. The core itself is easy. Luckily this exercise did not require memory management.

Tags:

Add Comment

2016-12-02 Emacs Avent of Code Day 2

First question of day 2: You start on key 5 on a keypad as shown below. With instructions to go up, down, left or right. Ignore instructions that would take you off the keypad.

1 2 3
4 5 6
7 8 9

The example input provided for the four numbers is shown below. At the end of each line you’ll end up on the key which is part of the answer. In this example the correct answer is 1985.

ULL
RRDDD
LURDL
UUUUD

Code:

(let ((pos 5)
      (code nil)
      (instructions '((U L L)
		      (R R D D D)
		      (L U R D L)
		      (U U U U D))))
  (dolist (instruction instructions)
    (dolist (move instruction)
      (case move
	((U) (when (> pos 3) (setq pos (- pos 3))))
	((D) (when (< pos 7) (setq pos (+ pos 3))))
	((L) (when (not (= (mod pos 3) 1)) (setq pos (- pos 1))))
	((R) (when (> (mod pos 3) 0) (setq pos (+ pos 1))))))
    (push pos code))
  (reverse code))

For the second star, I was too lazy to figure out how to compute the next position and decided to implement tables instead:

    1
  2 3 4
5 6 7 8 9
  A B C
    D

Given a direction, I just list all the possible positions and the results. It’s crude, but it works.

(let ((pos 5)
      (code nil)
      (instructions '((U L L)
		      (R R D D D)
		      (L U R D L)
		      (U U U U D))))
(dolist (instruction instructions)
    (dolist (move instruction)
      (setq pos (funcall move pos)))
    (push pos code))
  (reverse code))

(defun U (pos)
  (case pos
    ((3) 1)
    ((6) 2)
    ((7) 3)
    ((8) 4)
    ((A) 6)
    ((B) 7)
    ((C) 8)
    ((D) 'B)
    (t pos)))

(defun D (pos)
  (case pos
    ((1) 3)
    ((2) 6)
    ((3) 7)
    ((4) 8)
    ((6) 'A)
    ((7) 'B)
    ((8) 'C)
    ((B) 'D)
    (t pos)))

(defun L (pos)
  (case pos
    ((6) 5)
    ((3) 2)
    ((7) 6)
    ((B) 'A)
    ((4) 3)
    ((8) 7)
    ((C) 'B)
    ((9) 8)
    (t pos)))

(defun R (pos)
  (case pos
    ((5) 6)
    ((2) 3)
    ((6) 7)
    ((A) 'B)
    ((3) 4)
    ((7) 8)
    ((B) 'C)
    ((8) 9)
    (t pos)))

Tags:

Add Comment

2016-12-01 Emacs Advent of Code

I looked at Advent of Code and foolishly decided to solve the first riddle. Perhaps we’ll learn something about Elisp coding style? Feel free to leave comments regarding the code.

You must follow instructions: R or L means turn left or right, followed by a number of steps to take. What’s the final distance in steps? Example: “R5, L5, R5, R3 leaves you 12 blocks away.”

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R5, L5, R5, R3")))
      (direction 0)
      (x 0)
      (y 0))
  (dolist (instruction instructions)
    (destructuring-bind (turn . steps) instruction
      (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
      (case direction
	(0 (setq y (+ y steps)))
	(1 (setq x (+ x steps)))
	(2 (setq y (- y steps)))
	(3 (setq x (- x steps))))))
  (+ (abs x) (abs y)))

Sadly, for the second star, my solution fails… The question is now: which location was visited twice? The example provided says “if your instructions are R8, R4, R4, R8, the first location you visit twice is 4 blocks away, due East.” The code works for the example given but fails for the data I was provided with in the test.

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R8, R4, R4, R8")))
      (direction 0)
      (x 0)
      (y 0)
      (last-x 0)
      (last-y 0)
      (seen nil)
      (final-x nil)
      (final-y nil))
  (or (catch 'twice
	(dolist (instruction instructions)
	  (destructuring-bind (turn . steps) instruction
	    (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
	    (case direction
	      (0 (setq y (+ y steps)))
	      (1 (setq x (+ x steps)))
	      (2 (setq y (- y steps)))
	      (3 (setq x (- x steps)))))
	  (dolist (line (cdr seen))	; skip the last element
	    (destructuring-bind ((x1 . y1) (x2 . y2)) line
	      (when (or (and (= x last-x) ; last move was vertical 
			     (= y1 y2)	  ; looking at a horizontal
			     (>= x x1)  (<= x x2)
			     (or (and (<= y y1)  (>= last-y y1))
				 (and (>= y y1)  (<= last-y y1)))
			     (setq final-x x
				   final-y y1))
			(and (= y last-y) ; last move was horizontal
			     (= x1 x2)	  ; looking at a vertical
			     (>= y y1)  (<= y y2)
			     (or (and (<= x x1)  (>= last-x x1))
				 (and (>= x x1)  (<= last-x x1)))
			     (setq final-x x1
				   final-y y)))
		;; (error "Moving from %S to %S crosses the line from %S to %S in %S"
		;; 	   (cons last-x last-y) (cons x y)
		;; 	   (cons x1 y1) (cons x2 y2)
		;; 	   seen)
		(throw 'twice (+ (abs final-x) (abs final-y))))))
	  (push (list (cons last-x last-y) (cons x y)) seen)
	  (setq last-x x
		last-y y)))
      (+ (abs x) (abs y))))

Well, I decided to brute force it and remember every point I moved through because my “crossing lines” solution was obviously off by 3. Perhaps I just reported the wrong result, who knows.

(let ((instructions (mapcar (lambda (s)
			      (cons (aref s 0)
				    (string-to-number (substring s 1))))
			    (split-string "R8, R4, R4, R8")))
      (direction 0)
      (x 0)
      (y 0)
      (last-x 0)
      (last-y 0)
      (seen '((0 . 0))))
  (or (catch 'twice
	(dolist (instruction instructions)
	  (destructuring-bind (turn . steps) instruction
	    (setq direction (mod (funcall (if (= turn ?R) '1+ '1-) direction) 4))
	    (case direction
	      (0 (setq y (+ y steps)))
	      (1 (setq x (+ x steps)))
	      (2 (setq y (- y steps)))
	      (3 (setq x (- x steps)))))
	  (while (not (and (= last-x x) (= last-y y)))
	    (if (not (= last-x x))
		(setq last-x (funcall (if (< last-x x) '1+ '1-) last-x))
	      (setq last-y (funcall (if (< last-y y) '1+ '1-) last-y)))
	    (let ((last (cons last-x last-y)))
	      (if (member last seen)
		  (error "Repetition seen: %S in %S" last seen)
		(push last seen))))))
      (error "No repetitions in %S" seen)))

Tags:

Add Comment

2016-11-27 Work and Basic Income

We lost the Basic Income initiative in Switzerland but I think I need to start another link collection page.

Fuck work. “Economists believe in full employment. Americans think that work builds character. But what if jobs aren’t working anymore?”

Tags:

Add Comment

More...

Comments


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. See Info for text formatting rules. You can edit this page if you need to fix typos. You can subscribe to updates by email without leaving a comment.

To save this page you must answer this question:

Please say HELLO.

Referrers: Gothridge Manor Planet Emacsen $ cat /dev/brain > /dev/blog Dreams of Mythic Fantasy frothsof D&D Diary