view 2017/day10/app.d @ 35:1d99d733cf13 default tip @

day08: replace static foreach with workaround
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Tue, 16 Jan 2018 11:28:55 -0500
parents bc652fa0a645
children
line wrap: on
line source

import std.stdio;
import std.range: iota, array, chunks;
import std.algorithm: invert=reverse, map, reduce;
import std.conv: to;
import std.format: format;
import std.string: join;

void reverse(int Size)(ref int[Size] twine, int a, int b) {
  a = a % Size;
  b = b % Size;
  if (a <= b) {
    invert(twine[a..b]);
  }
  else {
    auto result = twine[a..$] ~ twine[0..b];
    invert(result);
    twine[a..$] = result[0..Size-a];
    twine[0..b] = result[Size-a..$];
  }
}

auto pos = 0, skip = 0;
auto knotUp(int Size)(int[] lengths, int[Size] twine) {
  foreach(length; lengths) {
    reverse(twine, pos, pos+length);
    pos = (pos + length + skip) % Size;
    skip = (skip + 1) % Size;
  }
  return twine;
}

auto calcHash(int Size=256, int Rounds=64, int ChunkSize=16)(string input)
  if( Size % ChunkSize == 0)
{
  int[] lengths = to!(int[])(cast(ubyte [])(input));
  static salt = [17, 31, 73, 47, 23];
  lengths ~= salt;
  int[Size] twine = iota(0, Size).array;
  for(int i = 0; i < Rounds; i++) {
    twine = knotUp(lengths, twine);
  }
  pos=skip=0;
  return twine.array.chunks(ChunkSize).map!(
      x => reduce!((a,b) => a ^ b)(x[0], x[1..$])
  ).array.to!(ubyte[Size/ChunkSize]);
}

auto getHash(int Size=256, int Rounds=64, int ChunkSize=16)(string input)
  if( Size % ChunkSize == 0)
{
  auto hash = calcHash!(Size, Rounds, ChunkSize)(input);
  return hash.array.map!(x => format("%02x", x)).join;
}

version(standalone) {
  void main(string[] args){
    auto hash = getHash(args[1]);
    writeln(hash);
  }
}