대략 Moby Dick 작성


297

다음은 Herman Melville의 Moby-Dick 의 텍스트를 포함 하는 1.2Mb ASCII 텍스트 파일 입니다 . 또는, 고래 . 당신의 임무는 한 번에 한 문자 씩이 파일을 제공 할 프로그램이나 함수 (또는 클래스 등-아래 참조)를 작성하는 것이며 각 단계에서 다음 문자를 추측해야합니다.

이것은 입니다. 당신의 점수는

2*L + E

어디는 L바이트 제출의 크기이며, E그것은 잘못 추측 문자 수입니다. 가장 낮은 점수가 이깁니다.

추가 세부 사항

제출물은 여러 번 호출되거나 호출되거나 전송되는 프로그램 또는 기능 등입니다. (1215235 번 정확해야합니다.) n 번째 시간 동안 호출되면 n 번째 문자 whale.txt또는 whale2.txt( n + 1 ) 번째 문자에 대한 추측 값을 출력해야합니다 . E점수 의 구성 요소는 잘못 추측 한 총 문자 수입니다.

대부분의 제출은 호출간에 몇 가지 상태를 저장해야하므로 호출 된 횟수와 이전 입력이 무엇인지 추적 할 수 있습니다. 외부 파일에 static쓰거나 전역 변수 를 사용 하거나 함수가 아닌 클래스를 제출하거나 상태 모나드를 사용하거나 언어에 적합한 다른 것을 사용하여이를 수행 할 수 있습니다. 제출에는 첫 번째 호출 전에 상태를 초기화하는 데 필요한 모든 코드가 포함되어야합니다.

프로그램은 결정 론적으로 실행되어야하므로 항상 동일한 입력이 주어지면 항상 같은 추측을하게됩니다 (따라서 항상 같은 점수를 얻습니다).

답변에는 제출물뿐만 아니라 E점수 의 일부 를 계산하는 데 사용한 코드도 포함해야합니다 . 제출 한 언어와 동일한 언어로 작성 될 필요는 없으며 바이트 수에 포함되지 않습니다. 읽을 수 있도록하는 것이 좋습니다.

제출과이 점수 계산 프로그램 간의 인터페이스와 관련하여 프로그램이 다음 바이트 입력을 받기 전에 항상 1 바이트의 출력을 제공하는 한 아무 문제가 없습니다. (예를 들어, 모든 입력을 포함하는 문자열을 전달하고 모든 출력을 포함하는 문자열을 다시 가져올 수는 없습니다.)

출품작을 제출하기 전에 시험 프로그램을 실제로 실행하고 점수를 계산 / 확인해야합니다. 제출물이 점수를 확인하기에 너무 느리게 진행되는 경우 원칙적으로 점수가 무엇인지 알더라도 경쟁 할 수 없습니다.

L점수 의 구성 요소는 코드 골프 챌린지에 대한 일반적인 규칙에 따라 계산됩니다. 제출물에 여러 파일이 포함 된 경우 해당 경우 점수디렉토리 구조 규칙을 참고하십시오 . 코드에서 사용하는 모든 데이터가 L점수에 포함되어야합니다 .

기존 라이브러리를 가져올 수 있지만 다른 외부 파일을로드 할 수 없으며 코드가 whale.txt또는whale2.txt위에서 설명한 방법 이외의 방법으로 파일을 저장하십시오. 사전 훈련 된 신경망 또는 기타 통계 데이터 소스를로드 할 수 없습니다. 신경망을 사용하는 것이 좋지만 제출에 가중치 데이터를 포함시키고 바이트 수로 계산해야합니다. 어떤 이유로 언어 또는 라이브러리에 Moby Dick의 일부 또는 모든 텍스트를 제공하는 기능이 포함 된 경우 해당 기능을 사용하지 못할 수 있습니다. 그 외에도 언어 또는 표준 라이브러리의 일부인 한 텍스트 처리, 예측 또는 압축과 관련된 기능을 포함하여 원하는 다른 내장 또는 라이브러리 기능을 사용할 수 있습니다. 통계 데이터 소스를 포함하는보다 이국적인 특수 루틴의 경우이를 직접 구현하고 바이트 수에 포함시켜야합니다.

일부 제출에는 코드에 의해 자체적으로 생성 된 구성 요소가 포함될 수 있습니다. 이 경우 해당 코드를 생성하는 데 사용 된 코드를 답변에 포함시키고 작동 방식을 설명하십시오 . 제출을 실행하는 데이 코드가 필요하지 않으면 바이트 수에 포함되지 않습니다.

기록적인 이유로 파일에는 두 가지 버전이 있으며 둘 중 하나를 답변에 사용할 수 있습니다. 에서 whale2.txt줄 바꿈 문단의 끝에 만 나타나도록 (위 링크) 텍스트는, 포장되지 않습니다. 원본 whale.txt에서 텍스트는 74 자 너비로 줄 바꿈되므로 각 줄의 끝을 예측하고 텍스트를 예측해야합니다. 이로 인해 도전이 더 어려워 지므로 whale2.txt새로운 답변에 권장됩니다. 두 파일의 크기는 1215236 바이트입니다.


요약하면 모든 답변에는 다음 사항이 포함되어야합니다.

  • 제출 자체. (코드와 사용하는 모든 데이터 파일-크면 링크가 될 수 있습니다.)
  • 코드 작동 방식에 대한 설명 다음 문자를 예측하는 방법과 I / O 방법을 설명하십시오. 귀하의 알고리즘에 대한 설명은 중요하며, 좋은 설명은 저에게 바운티를 얻게됩니다.
  • 점수를 평가하는 데 사용한 코드입니다. (이것이 이전 답변과 동일하면 링크 할 수 있습니다.)
  • 제출물을 생성하는 데 사용한 코드 및 해당 코드에 대한 설명 여기에는 매개 변수를 최적화하고 데이터 파일을 생성하는 데 사용되는 코드가 포함됩니다 (바이트 수에는 포함되지 않지만 답변에 포함되어야 함).

리더 보드

바운티

때때로 나는 다른 접근법을 장려하기 위해 바운티를 제공 할 것입니다.

첫 번째 50 점은 A. Rex에 수여되었으며 당시 최고 점수를 받았습니다.

두 번째 100 점도 A. Rex에게도 주어졌으며, 그들은 기존 답변에 아주 좋은 설명을 추가했기 때문에 같은 답변을 받았습니다.

다음 현상금 인 200 점

  • 새로운 기술을 사용하는 경쟁적인 답변. (이것은 현상금에 들어가는 나의 담당자이기 때문에 나의 주관적인 판단에 근거 할 것이지만, 당신은 저를 공평하게 믿을 수 있습니다. 당신의 대답은 그것이 어떻게 작동하는지 이해하기 위해 충분한 설명을 포함해야합니다!) 최고 점수를 획득하지 않고 기존 답변과 비교하여 합리적으로 잘 수행해야합니다. 특히 반복적 인 신경망을 기반으로 한 솔루션을보고 싶어하지만 현재 최고 점수를 차지하는 Markov 모델과는 다른 것으로 바운티를 수여합니다.

또는:

  • 어떤 방법 으로든 A. Rex의 최고 점수 (현재 444444)를이기는 사람.

200 포인트 현상금이 청구되면 400 포인트 1을 제공하고 그에 따라 요구 사항을 업데이트합니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Dennis

9
xkcd.com/1960 이이 과제에 대한 참조 인 것 같습니다!
A. Rex

나는 이것을 압축하는 것을 생각했다. 그러나 나의 컴퓨터가 어깨를 으
나루 요코

답변:


135

/// , 2 * 1 + 1020874 = 1020876

 

공백을 인쇄합니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Dennis

그것은 매우 똑똑한 보상 해킹입니다! AGI 여야합니다.)
Alex

97

Node.js, 2 * 224 + 524279 = 524727

점수 업데이트에 대해서는이 게시물 끝에있는 변경 로그를 참조하십시오.

바이트를 가져오고 리턴하는 함수입니다.

a=[...l='14210100'],m={},s={},b={}
f=c=>a.some((t,n)=>x=s[y=l.slice(n)]>t|/^[A-Z '"(]/.test(y)&&b[y],l+=String.fromCharCode(c),a.map((_,n)=>(m[x=l.slice(n)]=-~m[x])<s[y=l.slice(n,8)]||(s[y]=m[x],b[y]=c)),l=l.slice(1))&&x||32

마지막 8자를보고 다음을 예측 하는 간단한 PPM 모델 로 구성됩니다 .

T 는 적어도 T [L] 번 발생했을 때 길이 L 의 패턴을 신뢰합니다 . 여기서 T 는 임의의 임계 값의 배열입니다 : [1,1,2,1,2,3,5,2] . 또한 우리는 항상 첫 문자가 일치하는 패턴을 신뢰합니다 .[A-Z '"(]

가장 긴 신뢰할 수있는 패턴을 선택하고 통화시이 패턴과 관련된 가장 높은 점수로 예측을 반환합니다.

노트

  • 속도에 최적화되지는 않았지만 랩톱에서 약 15 초 안에 실행됩니다.

  • 모델을 재설정하지 않고 프로세스를 연속으로 여러 번 반복 할 수 있으면 5 번 반복 한 후 오류 수가 ~ 268000으로 수렴됩니다.

  • 예측 함수의 현재 성공률은 ~ 56.8 %입니다. 의견에서 @immibis가 알 수 있듯이, 잘못된 추측과 올바른 추측이 혼합되어 있으면 결과를 거의 읽을 수 없습니다.

    예를 들어 책 끝 부분에있는이 스 니펫은 다음과 같습니다.

    Here be it said, that this pertinacious pursuit of one particular whale,[LF]
    continued through day into night, and through night into day, is a thing[LF]
    by no means unprecedented in the South sea fishery.
    

    된다 :

    "e e be it said, that thes woacangtyous sarsuet of tie oort cular thale[LF][LF]
     orsinued toeough tir on e togh   and sheough toght an o ters af t shin[LF][LF]
    be to means insrocedented tn hhe sputh Sevsaonh ry,
    

    잘못된 추측을 밑줄로 바꾸면 함수의 올바른 결과를 더 잘 알 수 있습니다.

    _e_e be it said, that th_s _____n___ous __rsu_t of __e __rt_cular _hale_[LF]
    _o__inued t__ough ___ _n__ __gh__ and _h_ough __ght _n_o ____ __ _ _hin_[LF]
    b_ _o means _n_r_cedented _n _he __uth _e_____h_ry_
    

    NB : 위 예제는 이전 버전의 코드로 작성되었으며, 입력 파일의 첫 번째 버전에서 작업합니다.

테스트 코드

/**
  The prediction function f() and its variables.
*/
a=[...l='14210100'],m={},s={},b={}
f=c=>a.some((t,n)=>x=s[y=l.slice(n)]>t|/^[A-Z '"(]/.test(y)&&b[y],l+=String.fromCharCode(c),a.map((_,n)=>(m[x=l.slice(n)]=-~m[x])<s[y=l.slice(n,8)]||(s[y]=m[x],b[y]=c)),l=l.slice(1))&&x||32

/**
  A closure containing the test code and computing E.
  It takes f as input.
  (f can't see any of the variables defined in this scope.)
*/
;
(f => {
  const fs = require('fs');

  let data = fs.readFileSync('whale2.txt'),
      len = data.length,
      err = 0;

  console.time('ElapsedTime');

  data.forEach((c, i) => {
    i % 100000 || console.log((i * 100 / len).toFixed(1) + '%');

    if(i < len - 1 && f(c) != data[i + 1]) {
      err++;
    }
  })

  console.log('E = ' + err);
  console.timeEnd('ElapsedTime');
})(f)

변경 로그

  • 524727 -whale2.txt로 전환하여 19644 포인트 절약 (챌린지 업데이트)
  • 544371- 대문자, 따옴표, 큰 따옴표 또는 여는 괄호로 시작하는 패턴을 항상 신뢰하도록하여 327 점을 절약했습니다.
  • 544698- 공백으로 시작하는 패턴을 항상 신뢰할 수 있도록하여 2119 포인트 절약
  • 546817- 임계 값을 조정하고 예측 기능을 골프화 하여 47 점을 저장했습니다.
  • 546864- 최대 패턴 길이를 8 자로 확장하여 1496 포인트 절약
  • 548360- 신뢰할 수있는 패턴의 개념을 도입하여 길이에 따른 임계 값으로 6239 포인트를 절약했습니다.
  • 554599- 줄 바꿈 예측을 개선하여 1030 점을 절약했습니다.
  • 555629- 예측 기능을 골프로하여 22 포인트 절약
  • 555651- 예측 기능을 골프로하여 40 점을 저장했습니다
  • 555691- 초기 점수

44
호기심을 위해, 이것은 Moby Dick과 같은 것을 생산하지 않습니다. 전체가 많이 sidg tlanses,oeth to, shuld hottut tild aoersors Ch, th! Sa, yr! Sheu arinning whales aut ihe e sl he traaty of rrsf tg homn Bho dla tiasot a shab sor ty, af etoors tnd hocket sh bts ait mtubb tiddin tis aeewnrs, dnhost maundy cnd sner aiwt d boelh cheugh -aaieiyns aasiyns taaeiins! th, tla있습니다. 때로는 몇 가지 완전한 단어를 얻을 수 있습니다. 처럼 whales.
immibis 2012 년

23
@immibis 도전의 제목은 현명하게 선택되었습니다. 이것은 대략 Moby Dick 입니다. :-)
Arnauld

3
@Nathaniel 많은 업데이트가 있었으므로 거의 읽을 수 없으며 실제로 유익하지 않습니다. 개선 사항에 대한 간단한 설명과 함께 변경 로그를 추가했습니다.
Arnauld

45
귀하의 프로그램이 실제로 게 일어로 완벽한 번역을하고 있다고 생각합니다.
Beska

1
@ Draco18s이 쉼표가 좋은지 나쁜지 말하기는 어렵습니다. 만약 추측이 틀렸다면, 예측 함수는 합법적으로 편지를받은 후에 실제로 다른 편지 나 쉼표 대신에 편지를 넣으려고 시도했을 수 있습니다 .
Arnauld

91

펄, 2 · 70525 + 326508 = 467558

예언자

$m=($u=1<<32)-1;open B,B;@e=unpack"C*",join"",<B>;$e=2903392593;sub u{int($_[0]+($_[1]-$_[0])*pop)}sub o{$m&(pop()<<8)+pop}sub g{($h,%m,@b,$s,$E)=@_;if($d eq$h){($l,$u)=(u($l,$u,$L),u($l,$u,$U));$u=o(256,$u-1),$l=o($l),$e=o(shift@e,$e)until($l^($u-1))>>24}$M{"@c"}{$h}++-++$C{"@c"}-pop@c for@p=($h,@c=@p);@p=@p[0..19]if@p>20;@c=@p;for(@p,$L=0){$c="@c";last if" "ne pop@c and@c<2 and$E>99;$m{$_}+=$M{$c}{$_}/$C{$c}for sort keys%{$M{$c}};$E+=$C{$c}}$s>5.393*$m{$_}or($s+=$m{$_},push@b,$_)for sort{$m{$b}<=>$m{$a}}sort keys%m;$e>=u($l,$u,$U=$L+$m{$_}/$s)?$L=$U:return$d=$_ for sort@b}

이 프로그램을 실행하려면 이 파일이 필요 합니다 (여기서 이름을 지정해야 함) B. 위 문자 의 두 번째 인스턴스 에서이 파일 이름을 변경할 수 있습니다 B.이 파일을 생성하는 방법은 아래를 참조하십시오.

이 프로그램은 본질적으로 user2699의 답변 에서와 같이 Markov 모델의 조합을 사용 하지만 약간의 수정이 있습니다. 이것은 다음 캐릭터에 대한 분포 를 생성합니다 . 우리는 정보 이론을 사용하여 B인코딩 힌트 에 오류를 허용할지 또는 스토리지 비트를 소비할지 여부를 결정합니다 (있는 경우). 우리는 산술 코딩 을 사용 하여 모델의 소수 비트를 최적으로 저장합니다.

프로그램의 길이는 582 바이트 (불필요한 최종 개행 포함)이고 이진 파일의 B길이는 69942 바이트이므로 여러 파일의 점수 를 매기는 규칙에L 따라 582 + 69942 + 1 = 70525 로 점수 가 매겨집니다.

이 프로그램에는 거의 확실하게 64 비트 (little-endian?) 아키텍처가 필요합니다. m5.largeAmazon EC2 의 인스턴스에서 실행하는 데 약 2.5 분이 걸립니다 .

테스트 코드

# Golfed submission
require "submission.pl";

use strict; use warnings; use autodie;

# Scoring length of multiple files adds 1 penalty
my $length = (-s "submission.pl") + (-s "B") + 1;

# Read input
open my $IN, "<", "whale2.txt";
my $input = do { local $/; <$IN> };

# Run test harness
my $errors = 0;
for my $i ( 0 .. length($input)-2 ) {
    my $current = substr $input, $i, 1;
    my $decoded = g( $current );

    my $correct = substr $input, $i+1, 1;
    my $error_here = 0 + ($correct ne $decoded);
    $errors += $error_here;
}

# Output score
my $score = 2 * $length + $errors;
print <<EOF;
length $length
errors $errors
score  $score
EOF

테스트 하네스는 제출이 파일에 있다고 가정 submission.pl하지만 두 번째 줄에서 쉽게 변경할 수 있습니다.

텍스트 비교

"And did none of ye see it before?" cried Ahab, hailing the perched men all around him.\\"I saw him almost that same instant, sir, that Captain 
"And wid note of te fee bt seaore   cried Ahab, aasling the turshed aen inl atound him. \"' daw him wsoost thot some instant, wer, that Saptain 
"And _id no_e of _e _ee _t _e_ore__ cried Ahab, _a_ling the __r_hed _en __l a_ound him._\"_ _aw him ___ost th_t s_me instant, __r, that _aptain 

Ahab did, and I cried out," said Tashtego.\\"Not the same instant; not the same--no, the doubloon is mine, Fate reserved the doubloon for me. I 
Ahab aid  ind I woued tut,  said tashtego, \"No, the same instant, tot the same -tow nhe woubloon ws mane. alte ieserved the seubloon ior te, I 
Ahab _id_ _nd I ___ed _ut,_ said _ashtego__\"No_ the same instant_ _ot the same_-_o_ _he _oubloon _s m_ne_ __te _eserved the __ubloon _or _e_ I 

only; none of ye could have raised the White Whale first. There she blows!--there she blows!--there she blows! There again!--there again!" he cr
gnly  towe of ye sould have tersed the shite Whale aisst  Ihere ihe blows! -there she blows! -there she blows! Ahere arains -mhere again!  ce cr
_nly_ _o_e of ye _ould have ___sed the _hite Whale _i_st_ _here _he blows!_-there she blows!_-there she blows! _here a_ain__-_here again!_ _e cr

이 샘플 ( 다른 답변 에서 선택됨 )은 텍스트에서 다소 늦게 발생하므로이 시점에서 모델이 상당히 개발되었습니다. 이 모델은 캐릭터를 추측하는 데 도움이되는 70 킬로바이트의 "힌트"에 의해 확장됩니다. 단순히 위의 짧은 코드 스 니펫으로 구동되지는 않습니다.

힌트 생성

다음 프로그램은 위의 정확한 제출 코드 (표준 입력)를 수락하고 위의 정확한 B파일 (표준 출력)을 생성합니다 .

@S=split"",join"",<>;eval join"",@S[0..15,64..122],'open W,"whale2.txt";($n,@W)=split"",join"",<W>;for$X(0..@W){($h,$n,%m,@b,$s,$E)=($n,$W[$X]);',@S[256..338],'U=0)',@S[343..522],'for(sort@b){$U=($L=$U)+$m{$_}/$s;if($_ eq$n)',@S[160..195],'X<128||print(pack C,$l>>24),',@S[195..217,235..255],'}}'

유사한 계산을 수행하기 때문에 제출만큼 실행하는 데 거의 시간이 걸립니다.

설명

이 섹션에서는이 솔루션이 수행하는 작업을 사용자가 "집에서 시도"할 수있을만큼 충분히 자세하게 설명하려고합니다. 이 답변을 다른 답변과 구별하는 주요 기술은 "되감기"메커니즘으로 분류되는 몇 가지 섹션이지만, 거기에 도달하기 전에 기본 사항을 설정해야합니다.

모델

솔루션의 기본 성분은 언어 모델입니다. 우리의 목적을 위해 모델 은 어느 정도의 영어 텍스트 를 사용하고 다음 문자에 대한 확률 분포 를 반환하는 것 입니다. 모델을 사용할 때 영어 텍스트는 Moby Dick의 접두사입니다. 원하는 결과는 가장 가능성이 높은 문자에 대한 단일 추측이 아니라 분포 입니다.

우리의 경우, 우리는 본질적 으로 user2699에 의한이 답변 에서 모델을 사용합니다 . Anders Kaseorg 의 최고 점수 (우리 자신이 아닌)의 모형을 사용하지 않았습니다 . 단 하나의 최선의 추측보다는 분포를 추출 할 수 없었기 때문입니다. 이론적으로, 그 대답은 가중 기하 평균을 계산하지만, 문자 그대로 해석했을 때 다소 나쁜 결과를 얻었습니다. 우리의 "비밀 소스"는 모델이 아니라 전체적인 접근 방식이기 때문에 다른 답변에서 모델을 "훔친"것입니다. 누군가가 "더 나은"모델을 가지고 있다면 나머지 기술을 사용하여 더 나은 결과를 얻을 수 있어야합니다.

참고로, Lempel-Ziv와 같은 대부분의 압축 방법은 이러한 방식으로 "언어 모델"로 간주 될 수 있지만 약간 움켜 쥐어 야 할 수도 있습니다. (Brows-Wheeler 변환을 수행하는 것은 특히 까다 롭습니다!) 또한 user2699의 모델은 Markov 모델의 수정 사항입니다. 본질적으로이 도전에 대한 경쟁 또는 대체로 텍스트를 모델링하는 다른 어떤 것도 없습니다.

전반적인 아키텍처

이해를 돕기 위해 전체 아키텍처를 여러 조각으로 나누는 것이 좋습니다. 최상위 수준 관점에서 약간의 상태 관리 코드가 필요합니다. 이것은 특별히 흥미롭지는 않지만, 완전성을 위해 프로그램이 다음 추측을 요구할 때마다 Moby Dick의 올바른 접두사를 사용할 수 있다고 강조하고 싶습니다. 우리는 과거의 잘못된 추측을 어떤 식 으로든 사용하지 않습니다. 효율성을 위해 언어 모델은 첫 번째 N 문자의 상태를 재사용하여 첫 번째 (N + 1) 문자의 상태를 계산할 수 있지만 원칙적으로 호출 될 때마다 처음부터 다시 계산할 수 있습니다.

프로그램의 기본 "드라이버"를 따로 설정하고 다음 문자를 추측하는 부분을 들여다 보도록합시다. 언어 모델 (위에서 논의), "힌트"파일 및 "통역사"의 세 부분을 개념적으로 분리하는 데 도움이됩니다. 각 단계에서 통역사는 언어 모델에 다음 문자의 배포를 요청하고 힌트 파일에서 일부 정보를 읽을 수 있습니다. 그런 다음 이러한 부분을 추측으로 결합합니다. 정확히 힌트 파일에 어떤 정보가 있고 어떻게 사용되는지는 나중에 설명 할 것이지만 지금은이 부분들을 정신적으로 분리시키는 데 도움이됩니다. 구현 측면에서 힌트 파일은 문자 그대로 별도의 (이진) 파일이지만 프로그램 내부에 저장된 문자열이거나 무언가 일 수 있습니다. 근사치로

이 답변 에서처럼 bzip2 와 같은 표준 압축 방법을 사용하는 경우 "hints"파일은 압축 파일에 해당합니다. "통역사"는 압축 해제기에 해당하는 반면 "언어 모델"은 약간 암시 적입니다 (위에서 언급 한 바와 같이).

힌트 파일을 사용하는 이유는 무엇입니까?

추가 분석을위한 간단한 예를 선택해 봅시다. 텍스트가 N길고 근사한 문자 라고 가정합니다. 모든 문자는 E확률이 절반보다 약간 작은 문자 , 확률이 절반보다 약간 작은 문자 T, A1/1000 = 0.1 %의 확률을 갖는 문자 (독립적으로) 입니다. 다른 문자는 불가능하다고 가정하자. 어쨌든 A이전에 보지 못한 캐릭터가 파란색으로 보이는 경우와 매우 유사합니다.

만약 우리가 L 0 체제에서이 질문에 대한 다른 답변들 대부분이 아닌 대부분을 운영한다면, Eand 중 하나를 선택하는 것보다 통역사에게 더 나은 전략은 없습니다 T. 평균적으로 문자의 약 절반이 맞습니다. 따라서 E ≈ N / 2와 ≈ N / 2도 점수입니다. 그러나 압축 전략을 사용하면 문자 당 하나 이상의 비트로 압축 할 수 있습니다. L은 바이트 단위로 계산되므로 L ≈ N / 8을 얻으므로 이전 전략보다 두 배 좋은 strategy N / 4를 얻습니다.

이 모델에서 문자 당 하나 이상의 비트를이 속도로 달성하는 것은 사소한 것이 아니지만 한 가지 방법은 산술 코딩입니다.

산술 코딩

일반적으로 알려진 바와 같이, 인코딩 은 비트 / 바이트를 사용하여 일부 데이터를 나타내는 방법입니다. 예를 들어 ASCII는 영어 텍스트 및 관련 문자의 7 비트 / 문자 인코딩이며, 고려중인 원본 Moby Dick 파일의 인코딩입니다. 일부 문자가 다른 문자보다 일반적인 경우 ASCII와 같은 고정 너비 인코딩이 최적이 아닙니다. 이러한 상황에서 많은 사람들이 허프만 코딩에 도달합니다 . 문자 당 정수 비트 수의 고정 (프리픽스 프리) 코드를 원하는 경우에 최적입니다.

그러나 산술 코딩 이 훨씬 좋습니다. 대략적으로 말하면, "분수"비트를 사용하여 정보를 인코딩 할 수 있습니다. 온라인으로 사용할 수있는 산술 코딩에 대한 많은 안내서가 있습니다. 온라인에서 사용 가능한 다른 리소스로 인해 여기에서 세부 사항 (특히 실제 구현, 프로그래밍 측면에서 약간 까다로울 수 있음)을 건너 뛰지 만 누군가가 불평하면이 섹션을 더 자세히 설명 할 수 있습니다.

알려진 언어 모델에 의해 실제로 생성 된 텍스트가있는 경우, 산술 코딩은 해당 모델의 텍스트를 기본적으로 최적으로 인코딩합니다. 어떤 의미에서 이것은 해당 모델의 압축 문제를 "해결"합니다. (실제로 주요 문제는 모델을 알지 못하고 일부 모델은 인간의 텍스트를 모델링 할 때 다른 모델보다 낫다는 것입니다.)이 콘테스트에서 오류를 허용하지 않은 경우 이전 섹션의 언어로 이 과제에 대한 해결책을 만드는 한 가지 방법은 산술 인코더를 사용하여 언어 모델에서 "힌트"파일을 생성 한 다음 산술 디코더를 "통역사"로 사용하는 것입니다.

이 본질적으로 최적화 된 인코딩에서, 우리는 확률 p를 갖는 문자에 대해 -log_2 (p) 비트를 소비하게되고, 인코딩의 전체 비트 레이트는 Shannon 엔트로피 입니다. 이는 확률이 1/2에 가까운 문자는 인코딩하는 데 약 1 비트가 걸리고, 1/1000의 확률이있는 문자는 약 10 비트가됩니다 (2 ^ 10은 대략 1000이므로).

그러나이 과제에 대한 점수 메트릭은 압축을 최적의 전략으로 피하기 위해 잘 선택되었습니다. 더 짧은 힌트 파일을 얻는 데있어 트레이드 오프로 오류를 만드는 방법을 찾아야합니다. 예를 들어, 시도 할 수있는 전략 중 하나는 간단한 분기 전략입니다. 일반적으로 가능한 경우 산술 인코딩을 사용하려고하지만 모델의 확률 분포가 "나쁜"경우 가장 가능성이 높은 문자를 추측하여 인코딩하지 마십시오.

왜 오류가 발생합니까?

왜 우리가 "의도적으로"오류를 만들고 싶을 지 동기를 부여하기 위해 이전의 예를 분석해 봅시다. 올바른 문자를 인코딩하기 위해 산술 코딩을 사용하는 경우 E또는 의 경우 대략 1 비트를 사용 T하지만의 경우에는 약 10 비트를 사용합니다 A.

전반적으로, 이것은 세 가지 가능성이 있지만 문자 당 조금 이상을 소비하는 꽤 좋은 인코딩입니다. 기본적으로 A는 가능성이 거의 없으며 해당 10 비트를 너무 자주 소비하지 않습니다. 그러나 A? 의 경우 대신 오류를 만들 수 있다면 좋지 않을까요? 결국 문제에 대한 메트릭은 1 바이트 = 8 비트 길이의 길이가 2 개의 오류와 같다고 간주합니다. 따라서 문자에 8/2 = 4 비트 이상을 소비하는 대신 오류를 선호 해야하는 것처럼 보입니다. 하나의 오류를 저장하기 위해 1 바이트 이상을 소비하면 확실히 차선책으로 들립니다!

"되감기"메커니즘

이 섹션에서는이 솔루션의 주요 영리한 측면에 대해 설명합니다.이 방법은 비용없이 잘못된 추측을 처리 할 수있는 방법입니다.

우리가 분석 한 간단한 예에서 되감기 메커니즘은 특히 간단합니다. 인터프리터는 힌트 파일에서 1 비트를 읽습니다. 0이면 추측 E합니다. 1이면 추측 T합니다. 다음에 호출 될 때 올바른 문자가 무엇인지 확인합니다. 힌트 파일이 제대로 설정 되면 Eor 의 경우 T인터프리터가 올바르게 추측 할 수 있습니다. 그러나 어떻 A습니까? 되감기 메커니즘의 아이디어는 단순히 코드 A를 작성 하지 않는 것 입니다. 더 정확하게 말하면, 인터프리터가 나중에 올바른 문자가이라는 것을 알게되면 A은유 적으로 " 테이프를 되감습니다 ": 이전에 읽은 비트를 반환합니다. 읽은 비트는 코딩 E하거나T그러나 지금은 아닙니다. 나중에 사용됩니다. 이 간단한 예에서 이것은 기본적으로 동일한 문자 ( 또는 )가 올바르게 될 때까지 계속 추측 한다는 것을 의미합니다 . 그런 다음 다른 비트를 읽고 계속 진행합니다.ET

이 힌트 파일의 인코딩은 매우 간단합니다. 모든 s를 완전히 무시하면서 모든 Es를 0 비트로, Ts를 1 비트로 전환 A합니다. 이전 섹션의 끝 부분에있는 분석에 따르면이 체계는 오류를 발생 시키지만 As를 인코딩하지 않으면 서 전체적으로 점수를 줄 입니다. 더 작은 효과로 실제로 힌트 파일의 길이도 절약됩니다. 비트 E와 비트가 T아닌 비트 와 비트마다 정확히 하나의 비트를 사용하기 때문 입니다.

작은 정리

언제 오류를 내야합니까? 모델이 다음 캐릭터에 대한 확률 분포 P를 제공한다고 가정합니다. 가능한 문자를 codednot coded의 두 클래스로 분리합니다 . 올바른 문자가 코딩되지 않은 경우 "되감기"메커니즘을 사용하여 길이에 상관없이 오류를 허용합니다. 올바른 문자가 코딩되면 다른 분포 Q를 사용하여 산술 코딩으로 인코딩합니다.

그러나 어떤 분포 Q를 선택해야합니까? 코딩 된 문자가 코딩되지 않은 문자보다 높은 확률 (P)을 가져야한다는 것을 너무 어렵지 않습니다. 또한 분포 Q는 코드화 된 문자 만 포함해야합니다. 결국 우리는 다른 것들을 코딩하지 않기 때문에 엔트로피를 "지출"해서는 안됩니다. 확률 분포 Q가 코딩 된 문자에서 P에 비례해야한다는 것을보기에는 조금 까다 롭습니다. 이러한 관찰 결과를 종합하면 가장 가능성이 높은 문자를 코딩해야하지만 가능성이 적은 문자는 코딩하지 않아야하며 Q는 코딩 된 문자에 대해 단순히 P 배율이 조정됩니다.

또한 코딩 문자에 대해 어떤 "컷오프"를 선택해야하는지에 대한 멋진 정리가 있음이 밝혀졌습니다. 다른 코드화 된 문자가 결합 될 가능성이 최소 1 / 5.393 인 한 문자를 코딩해야합니다. 이것은 5.393위의 프로그램의 끝 부분에있는 것처럼 보이는 임의의 상수 모양을 "설명"합니다 . 숫자 1 / 5.393 ≈ 0.18542는 방정식 -p log (16)-p log p + (1 + p) log (1 + p) = 0에 대한 해 입니다.

아마도이 절차를 코드로 작성하는 것이 합리적입니다. 이 스 니펫은 C ++입니다.

// Assume the model is computed elsewhere.
unordered_map<char, double> model;

// Transform p to q
unordered_map<char, double> code;
priority_queue<pair<double,char>> pq;
for( char c : CHARS )
    pq.push( make_pair(model[c], c) );
double s = 0, p;
while( 1 ) {
    char c = pq.top().second;
    pq.pop();
    p = model[c];
    if( s > 5.393*p )
        break;
    code[c] = p;
    s += p;
}
for( auto& kv : code ) {
    char c = kv.first;
    code[c] /= s;
}

함께 모아서

이전 섹션은 불행히도 약간 기술적 인 부분이지만 다른 부분을 모두 합하면 구조는 다음과 같습니다. 프로그램이 주어진 올바른 문자 다음에 다음 문자를 예측하도록 요청 될 때마다 :

  1. Moby Dick의 알려진 올바른 접두사에 올바른 문자를 추가하십시오.
  2. 텍스트의 (Markov) 모델을 업데이트하십시오.
  3. 비밀 소스 : 이전 추측이 정확하지 않으면, 되감기 이전 추측하기 전에 상태로 산술 디코더의 상태를!
  4. 다음 캐릭터에 대한 확률 분포 P를 예측하도록 Markov 모델에 요청하십시오.
  5. 이전 섹션의 서브 루틴을 사용하여 P를 Q로 변환합니다.
  6. 분포 Q에 따라 산술 디코더에 힌트 파일의 나머지 부분에서 문자를 디코딩하도록 요청하십시오.
  7. 결과 캐릭터를 맞춰보세요.

힌트 파일의 인코딩도 비슷하게 작동합니다. 이 경우 프로그램은 올바른 다음 문자가 무엇인지 알고 있습니다. 그것이 코딩되어야하는 문자라면, 물론 그 위에 산술 인코더를 사용해야합니다. 그러나 코드화되지 않은 문자이면 산술 인코더의 상태를 업데이트하지 않습니다.

확률 분포, 엔트로피, 압축 및 산술 코딩과 같은 정보 이론적 배경을 이해했지만이 게시물을 이해하지 못하고 시도하지 않은 경우 (이론이 참인 이유는 제외) 알려 주시면 정리할 수 있습니다. 읽어 주셔서 감사합니다!


8
와우, 인상적인 답변. B파일 을 생성하는 데 필요한 추가 코드가 있다고 가정 합니까? 그렇다면 답변에 포함시킬 수 있습니까?
Nathaniel

8
우수한! 500k 점수 장벽을 깰 첫 번째 (그리고 지금까지 유일한) 대답.
ShreevatsaR

5
"울 고래를 숨겼다"세상에 내가 울고있다
Phill

5
현상금 기간 동안 새로운 답변이 게시되지 않았으므로 최고의 점수와 가장 정교한 방법으로 답변에 수여합니다. 혹시 시간이 있다면, 나는 것이 정말 정확히 알고리즘이 무엇인지 즉,이 답변이 어떻게 작동하는지에 대한보다 깊이있는 설명을, 감사?
Nathaniel

2
@Nathaniel :이 게시물에 설명을 추가했습니다. 솔루션을 직접 재현 할 수있을 정도로 상세하다고 생각되면 알려주십시오.
A. Rex

77

파이썬 3, 2 · 267 + 510193 = 510727

예언자

def p():
 d={};s=b''
 while 1:
  p={0:1};r=range(len(s)+1)
  for i in r:
   for c,n in d.setdefault(s[:i],{}).items():p[c]=p.get(c,1)*n**b'\1\6\f\36AcWuvY_v`\270~\333~'[i]
  c=yield max(sorted(p),key=p.get)
  for i in r:e=d[s[:i]];e[c]=e.get(c,1)+1
  s=b'%c'%c+s[:15]

이것은 0,…, 16 Markov 모델의 가중치 베이지안 조합을 사용하고 가중치는 [1, 6, 12, 30, 65, 99, 87, 117, 118, 89, 95, 118, 96, 184, 126, 219, 126].

결과는 이러한 가중치의 선택에 매우 민감하지는 않지만 각 후보 돌연변이가있는 "상원 다수결"에 대한 답변 에서 사용한 것과 동일한 후기 허용 언덕 등반 알고리즘을 사용하여 가중치를 최적화했습니다. 단일 중량에 대해 ± 1 씩 증가합니다.

테스트 코드

with open('whale2.txt', 'rb') as f:
    g = p()
    wrong = 0
    a = next(g)
    for b in f.read():
        wrong += a != b
        a = g.send(b)
    print(wrong)

2
작업에 적합한 도구입니다. 좋은 점수. 좋은데
agtoever

1
가능한 설명 : b"\0\3\6\r\34'&-20'\22!P\n[\26"가중치를 아스키 표현한 것으로, 인쇄 할 수없는 작은 값이 8 진수로 이스케이프됩니다.
Cœur

텍스트가 줄 바꿈되지 않은 파일 버전으로 질문을 업데이트했습니다. 코드를 다시 실행 해보십시오 (약간 더 나을 수도 있음)
Nathaniel

3
그 설명에 감사드립니다-질문에 대한 개요를 편집 할 수 있다면 좋을 것입니다. (이전의 과제 인 Paint Starry Night에 대한 경험 은 이러한 최적화 절차가 답변에서 가장 흥미로운 부분이므로 답변에 해당 코드와 설명이 포함되어 있으면 훨씬 좋습니다. 두 규칙 모두에 규칙을 포함 시켰습니다. 그들이해야한다고 말하는 도전.)
Nathaniel

1
@Christoph 내 모델 조합은 실제로 가중 기하 평균입니다. 그러나 물류 영역에서 PAQ의 평균은 약간 다릅니다. 더 나은지 확인해야합니다.
Anders Kaseorg

55

Python 3 , 2 * 279 + 592920 = 593478 2 * 250 + 592467 = 592967 2 * 271 + 592084 = 592626 2 * 278 + 592059 = 592615 2 * 285 + 586660 = 587230 2 * 320 + 585161 = 585801 2 * 339 + 585050 = 585728

d=m={}
s=1
w,v='',0
def f(c):
 global w,m,v,s,d
 if w not in m:m[w]={}
 u=m[w];u[c]=c in u and 1+u[c]or 1;v+=1;q=n=' ';w=w*s+c;s=c!=n
 if w in m:_,n=max((m[w][k],k)for k in m[w])
 elif s-1:n=d in'nedtfo'and't'or'a'
 elif'-'==c:n=c
 elif"'"==c:n='s'
 elif'/'<c<':':n='.'
 if v>4*(n!=q)+66:n='\n'
 if s:d=c
 if c<q:w=w[:-1]+q;v=s=0
 return n

온라인으로 사용해보십시오!

전역 변수를 사용하는 함수. 단어 수준에서 모델을 구축하면서 학습합니다. 이 단어에서 지금까지 본 것 중에서 가장 일반적인 다음 문자는 무엇입니까? 더 많은 입력이 들어 오면 텍스트에서 일반적인 단어를 꽤 잘 배우고 다음 단어 를 시작하는 가장 일반적인 문자를 배웁니다 .

예를 들면 다음과 같습니다.

  • 지금까지 본 것이 'Captai'인 경우 "n"을 예측합니다.
  • "캡틴"이면 공간을 예측합니다
  • 단어의 시작이고 마지막 단어가 "캡틴"인 경우 'A'를 예측합니다.
  • 지금까지 단어가 'A'이면 'h'(그리고 'a'와 'b'; 'C'와 유사하게)를 예측합니다.

처음에는 잘하지 않지만 결국 실제 단어의 큰 부분이 나옵니다. 대체 옵션은 공백이며, 앞의 문자가 "nedtfo", 숫자 또는 하이픈 또는 아포스트로피 중 하나가 아닌 한 공백은 "a"입니다. 또한 71 자 뒤의 줄 바꿈 또는 66 자 뒤의 공백이 예상되는 경우 적극적으로 줄 바꿈을 예측합니다. 둘 다 데이터에 맞게 조정되었습니다 ( "t"는 공백 후에 훨씬 흔하지 만 이미 자주 예측되었으므로 " a "는 6 가지 특수한 경우를 제외하고 더 나은 추측입니다.)

어떤 단어 쌍이 함께되었는지 배우고 매핑을 미리 설정하는 것은 가치가없는 것으로 밝혀졌습니다.


다음과 같은 텍스트로 끝납니다.

nl tneund his    I woi tis tnlost ahet toie tn tant  wod, ihet taptain Ahab ses
 snd t
oeed Sft   aoid thshtego    Io, fhe soie tn tant  tot the soie      ahe sewbtoon
swn tagd  aoths eatmved fhe sewbtoon wor ta  I sfey  aote of totsonld nive betse
d ahe
hate Whale iorst  Ihe e ioi beaos! -there soi beaos! -there soi beaos!

이것은 입력 의이 부분에 해당합니다.

그의 주위에.

타슈 테고 대변인은“아브 선장과 거의 같은 순간을 보았습니다.

"동일한 순간이 아니었다. 동일하지 않다.-아니, doubloon은 나의 것이다. Fate는 나를 위해 doubloon을 예약했다. 나는 오직 어느 누구도 흰 고래를 먼저 올릴 수 없었다. -그녀가 불었다!

적절한 명사가 어디에서 나오는지 알 수 있지만 단어의 끝이 대부분 옳습니다. "dou"이 표시되면 "doubt"가 필요하지만 "l"이 표시되면 "doubloon"이됩니다.

동일한 모델로 두 번째로 실행하면 방금 구축 한 또 다른 92k 정확도 (51.7 %-> 59.3 %)가 발생하지만 두 번째 반복에서 항상 60 % 미만입니다.


측정 코드는 TIO 링크에 있거나 약간 더 나은 버전입니다.

total = 0
right = 0
with open('whale.txt') as fp:
    with open('guess.txt', 'w') as dest:
        for l in fp.readlines():
            for c in l:
                last = c
                if p == c: right += 1
                n = f(c)
                p = n
                total += 1
                dest.write(n)
                if total % 10000 == 0:
                    print('{} / {} E={}\r'.format(right, total, total-right), end='')
print('{} / {}: E={}'.format(right, total, total - right))

guess.txt 끝에 추측 된 출력이 있습니다.


3
이것은 훌륭한 접근법입니다!
Skyler

2
너무 많은 <s> </ s>;)
FantaC

1
이 접근법은 LZW 압축 알고리즘을 상기 시켰기 때문에 +1입니다.
Marcos

25

C ++, 점수 : 2 * 132 + 865821 = 866085

217 바이트를 절약 한 @Quentin에게 감사드립니다!

int f(int c){return c-10?"t \n 2  sS \n  -  08........       huaoRooe oioaoheu thpih eEA \n   neo    enueee neue hteht e"[c-32]:10;}

문자가 주어지면 입력 문자 다음에 가장 자주 나타나는 문자를 출력하는 매우 간단한 솔루션입니다.

다음을 사용하여 점수를 확인하십시오.

#include <iostream>
#include <fstream>

int f(int c);

int main()
{
    std::ifstream file;
    file.open("whale2.txt");

    if (!file.is_open())
        return 1;

    char p_ch, ch;
    file >> std::noskipws >> p_ch;
    int incorrect = 0;
    while (file >> std::noskipws >> ch)
    {
        if (f(p_ch) != ch)
            ++incorrect;
        p_ch = ch;
    }

    file.close();

    std::cout << incorrect;
}

편집 :를 사용 whale2.txt하면 점수가 높아집니다.


5
이 배열을 문자열 리터럴로 변환 L하고 많은 문자를 저장하는 대신 직접 인라인 할 수 있습니다. :
Quentin

@Quentin 감사합니다! 이제 왜 내가 처음부터 그런 생각을하지 않았는지 궁금합니다.
Steadybox

20

파이썬, 2 * 516 + 521122 = 522154

연산:

또 다른 파이썬 제출,이 알고리즘은 길이 1, ..., l의 시퀀스를보고 가장 가능성이 높은 다음 문자를 계산합니다. 확률의 합이 사용되며 더 나은 결과를 얻기위한 몇 가지 트릭이 있습니다.

from collections import Counter as C, defaultdict as D
R,l=range,10
s,n='',[D(C) for _ in R(l+1)]
def A(c):
 global s;s+=c;
 if len(s)<=l:return ' '
 P=D(lambda:0)
 for L in R(1,l+1):
  w=''.join(s[-L-1:-1]);n[L][w].update([c]);w=''.join(s[-L:])
  try:
   q,z=n[L][w].most_common(1)[0];x=sum(list(n[L][w].values()))
  except IndexError:continue
  p=z/x
  if x<3:p*=1/(3-x)
  P[q]+=p
 if not P:return ' '
 return max(P.items(),key=lambda i:i[1])[0]
import this, codecs as d
[A(c) for c in d.decode(this.s, 'rot-13')]

결과 :

대부분의 횡설수설이지만 "Father Mapple"과 같은 간혹 문구가 나타납니다.

errors: 521122
TRAINING:
result:  tetlsnowleof the won -opes  aIther Mapple,woneltnsinkeap hsd   lnd the  thth a shoey,aeidorsbine ao
actual: ntal knobs of the man-ropes, Father Mapple cast a look upwards, and then with a truly sailor-like bu
FINAL:
result: mnd wnd round  ahe   ind tveryaonsracting th ards the sol ens-ike aeock tolblescn the sgis of thet t
actual: und and round, then, and ever contracting towards the button-like black bubble at the axis of that s

테스트 코드 :

매우 간단합니다. 텍스트의 몇 가지 예를 다른 지점에서 출력합니다. whale2.txt를 사용하면 줄 바꿈을 계산하는 추가 논리가 필요하지 않습니다.

from minified import A

def score(predict, text):
    errors = 0
    newtext = []
    for i, (actual, current) in  enumerate(zip(text[1:], text[:-1])):
        next = predict(current)
        errors += (actual != next)
        newtext.append(next)
        if (i % (len(text) // 100) == 0):
            print ('.', end='', flush=True)
    return errors, ''.join(newtext)

t = open('whale2.txt')
text = t.read()
err2, text2 = score(A, text)
print('errors:', err2)
print("TRAINING:")
print(text2[100000:100100].replace('\n', '\\n'))
print(text1[100001:100101].replace('\n', '\\n'))
print("FINAL:")
print(text2[121400:1215500].replace('\n', '\\n'))
print(text[121401:1215501].replace('\n', '\\n'))

3
사이트에 오신 것을 환영합니다! 이것은 환상적인 첫 번째 작품입니다. :)
DJMcMayhem

@DJMcMayhem, 환영합니다. 나는 한동안보고있는 것을 즐겼다. 이것은 참가에 대한 나의 관심을 끄는 첫번째 콘테스트이다.
user2699

19

C (gcc) , 679787 652892

84 76 바이트, 679619 652740 잘못된 추측

p[128][128][128][128];a,b,c,d;g(h){p[a][b][c][d]=h;h=p[a=b][b=c][c=d][d=h];}

온라인으로 사용해보십시오!

업데이트 : 업데이트 된 파일로 ~ 27000 포인트, 더 나은 골프 기능으로 16 포인트 (8 바이트).

설명

이것이 작동하는 방식은 코드가 텍스트를 통과 할 때 주어진 4 문자 시퀀스를 종료 한 마지막 문자를 기억하고 해당 값을 반환한다는 것입니다. 위의 Arnauld의 접근 방식과 다소 유사하지만 동일한 방식으로 종료되는 두 개의 주어진 4 문자 시퀀스의 고유 한 가능성에 의존합니다.

골퍼 제거 :

p[128][128][128][128];
a,b,c,d;
g(h){
    p[a][b][c][d]=h; // Memorize the last character.
    h=p[a=b][b=c][c=d][d=h]; // Read the guess. We save several
                             // bytes with the assignments inside indices.
}

... TIO 링크는 쓸모가 없습니다. 따라서 함수는 마지막 할당 값을 반환합니까?
user202729

설명으로 답을 편집 한 다음 :)

1
@Rogem 나는 골프를 타지 않은 버전을 추가했다.
Adam Davis

@AdamDavis는 대부분의 C 구현에서 모든 전역 변수가 0에서 시작합니다. 정의되지 않은 동작이므로 코드 골프에서만 사용됩니다.
NieDzejkob

1
@NieDzejkob 아, 맞아, 고마워! "ANSI-C는 초기화되지 않은 모든 정적 / 전역 변수를 0으로 초기화해야합니다."
Adam Davis

16

sh + bzip2, 2 * 364106 = 728212

2 * 381249 + 0 = 762498

dd if=$0 bs=1 skip=49|bunzip2&exec cat>/dev/null

첫 번째 바이트가없는 bzip2 압축 whale2.txt

입력을 무시합니다. 정답을 출력합니다. 이것은 한쪽 끝에 기준을 제공합니다. daniero는 다른 쪽 끝에 기준을 제공합니다.

빌더 스크립트 :

#!/bin/sh
if [ $# -ne 3 ]
then
    echo "Usage $0 gen.sh datafile output.sh"
    exit 1
fi

cat $1 > $3
dd ibs=1 if=$2 skip=1 | bzip2 -9 >> $3
chmod +x $3

I / O 테스트 하니스 (tcc; gcc의 첫 번째 줄 잘라 내기). 이 테스트 하네스는 읽기 / 쓰기 I / O를 기대하는 완전한 프로그램을 제출하는 적합한 플랫폼에있는 누구나 사용할 수 있습니다. 부정 행위를 피하기 위해 한 번에 바이트 I / O를 사용합니다. 자식 프로그램은 블로킹을 피하기 위해 매 바이트마다 출력을 플러시해야합니다.

#!/usr/bin/tcc -run
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
    volatile int result;
    int readfd[2];
    int writefd[2];
    int cppid;
    int bytecount;
    char c1, c2, c3;
    if (argc != 2) {
        printf("write X approximately -- service host\n");
        printf("Usage: %s serviceprocessbinary < source.txt\n", argv[0]);
        return 1;
    }
    /* Start service process */
    if (pipe(readfd)) {
        perror("pipe()");
        return 3;
    }
    if (pipe(writefd)) {
        perror("pipe()");
        return 3;
    }
    result = 0;
    if (!(cppid = vfork())) {
        char *argtable[3];
        argtable[0] = argv[1];
        argtable[1] = NULL;
        dup2(readfd[0], 0);
        dup2(writefd[1], 1);
        close(readfd[1]);
        close(writefd[0]);
        close(readfd[0]);
        close(writefd[1]);
        execvp(argv[1], argtable);
        if (errno == ENOEXEC) {
            argtable[0] = "/bin/sh";
            argtable[1] = argv[1];
            argtable[2] = NULL;
            /* old standard -- what isn't an executable
             * can be exec'd as a /bin/sh script */
            execvp("/bin/sh", argtable);
            result = ENOEXEC;
        } else {
            result = errno;
        }
        _exit(3);
    } else if (cppid < 0) {
        perror("vfork()");
        return 3;
    }
    if (result) {
        errno = result;
        perror("execvp()");
        return 3;
    }
    close(readfd[0]);
    close(writefd[1]);
    /* check results */
    read(0, &c2, 1);
    bytecount = 1;
    errno = 0;
    while (read(0, &c1, 1) > 0) {
        write(readfd[1], &c2, 1);
        if (read(writefd[0], &c3, 1) <= 0) {
            printf("%d errors (%d bytes)\n", result, bytecount);
            if (errno == 0)
                fprintf(stderr, "pipe: unexpected EOF\n");
            else
                perror("pipe");
            return 3;
        }
        if (c3 != c1)
            ++result;
        c2 = c1;
        ++bytecount;
    }
    printf("%d errors (%d bytes)\n", result, bytecount);
    return 0;
}

6
나는 그가 무엇을 요구하는지 생각한다 : 이것이 어떻게 but may not load any other external files, and your code may not access the whale.txt file in any way other than described above.조항을 위반하지 않는가?

8
@Rogem 압축 된 데이터는 여기에 표시된 것과 코드에 액세스합니다.
user202729

4
: 문제는 말한다 . 그것이 요구하는 경우 귀하의 제출이 프로그램 또는 여러 번 호출 또는 호출되는 함수 (등)이 될 것 " nth이의 n 번째 문자가 주어집니다 시간 whale.txt이나 whale2.txt그리고 그것은에 대한 출력의 추측을해야합니다 (n+1)th캐릭터." -이 요건은 어떻게 달성됩니까? 코드 whale.txt는 실행될 때마다 전체 텍스트를 표시합니다 .
axiac

1
@axiac "프로그램이 다음 바이트의 입력을 받기 전에 항상 1 바이트의 출력을 제공하는 한 아무 문제가 없습니다."
user202729

5
@axiac은 테스트 장치를 제공했기 때문에 STDIN에서 1 바이트의 프로그램을 "호출 또는 호출"로 보내는 것을 기쁘게 생각합니다. 중요한 것은 프로그램이 테스트 하네스를 통해 실행될 때 각 바이트 입력 후에 실제로 1 바이트의 출력을 반환한다는 것입니다. 질문에 따르면, "다음 바이트 입력을 받기 전에 프로그램이 항상 1 바이트 출력을 제공하는 한 아무 문제가 없습니다."
Nathaniel

13

파이썬 3 , 879766

F=[[0]*123for _ in range(123)]
P=32
def f(C):global P;C=ord(C);F[P][C]+=1;P=C;return chr(max(enumerate(F[C]),key=lambda x:x[1])[0])

온라인으로 사용해보십시오!


... ///공백을 인쇄하는 대답은 10 upvotes를 얻는 반면 내 코드는 3을 얻을 수 있습니다 ...

설명:

각 캐릭터에 대해 프로그램 :

  • 증가하다 frequency[prev][char]
  • 에서 가장 많이 등장하는 캐릭터 찾기 frequency[char]
  • 출력합니다.

  • TIO 링크의 ungolfed 코드가 주석 처리되었습니다.
  • 코드는 131 바이트입니다.
  • 내 컴퓨터에서 코드가 실행됩니다.
879504 / 1215235
Time: 62.01348257784468

총점은

2*131 + 879504 = 879766

큰 파일을 TIO에 업로드 할 방법이 없기 때문에 (Dennis 요청 제외) TIO 링크에서 실행되는 예제는 텍스트의 작은 부분에 대해서만 프로그램을 실행합니다.

이전 답변과 비교 하여이 문자에는 362 개의 잘못된 문자가 있지만 코드는 255 바이트 짧습니다. 멀티 플라이어를 사용하면 제출 점수가 낮아집니다.


13

C #, 378 * 2 + 569279 = 570035

using System.Collections.Generic;using System.Linq;class P{Dictionary<string,Dictionary<char,int>>m=new
Dictionary<string,Dictionary<char,int>>();string b="";public char N(char
c){if(!m.ContainsKey(b))m[b]=new Dictionary<char,int>();if(!m[b].ContainsKey(c))m[b][c]=0;m[b][c]++;b+=c;if(b.Length>4)b=b.Remove(0,1);return
m.ContainsKey(b)?m[b].OrderBy(k=>k.Value).Last().Key:' ';}}

이 방법은 조회 테이블을 사용하여 주어진 문자열 다음에 가장 일반적인 문자를 학습합니다. 룩업 테이블의 키는 최대 4 자이므로이 함수는 먼저 룩업 테이블을 현재 문자로 업데이트 한 다음 현재 문자를 포함하여 이전 4 개의 문자 다음에 발생할 가능성이 가장 높은 문자 만 확인합니다. . 조회 테이블에 해당 4자가 없으면 공백이 인쇄됩니다.

이 버전은 whale2.txt성공적인 추측 횟수를 크게 향상시키기 때문에 파일을 사용합니다 .

다음은 클래스를 테스트하는 데 사용되는 코드입니다.

using System;
using System.IO;
using System.Text;

public class Program
{
    public static void Main(string[] args)
    {
        var contents = File.OpenText("whale2.txt").ReadToEnd();
        var predictor = new P();

        var errors = 0;
        var generated = new StringBuilder();
        var guessed = new StringBuilder();
        for (var i = 0; i < contents.Length - 1; i++)
        {
            var predicted = predictor.N(contents[i]);
            generated.Append(predicted);
            if (contents[i + 1] == predicted)
                guessed.Append(predicted);
            else
            {
                guessed.Append('_');
                errors++;
            }
        }

        Console.WriteLine("Errors/total: {0}/{1}", errors, contents.Length);
        File.WriteAllText("predicted-whale.txt", generated.ToString());
        File.WriteAllText("guessed-whale.txt", guessed.ToString());

        Console.ReadKey();
    }
}

코드는 거의 2 초 안에 실행됩니다. 레코드의 경우 조회 테이블의 키 크기를 수정하면 얻을 수있는 결과입니다 (모델을 재설정하지 않고 두 번째 실행 결과 포함).

Size   Errors   Errors(2)
-------------------------
1      866162   865850
2      734762   731533
3      621019   604613
4      569279   515744
5      579446   454052
6      629829   396855
7      696912   335034
8      765346   271275
9      826821   210552
10     876471   158263

이 알고리즘에서 키 크기가 4자인 이유를 아는 것이 흥미로울 것입니다.

텍스트 비교

기발한:

"And did none of ye see it before?" cried Ahab, hailing the perched men all around him.

"I saw him almost that same instant, sir, that Captain Ahab did, and I cried out," said Tashtego.

"Not the same instant; not the same--no, the doubloon is mine, Fate reserved the doubloon for me. I only; none of ye could have raised the White Whale first. There she blows!--there she blows!--there she blows! There again!--there again!"

재현 :

"Tnd tes note of to seamtn we ore  
sried thab  wedleng the srriead te  a l tneund tes  
"T day tim t lost shet toie tn tand  aor, ahet taptain thab sid  tnd t waued tnt   said teshtego  
"To, ahe shme tn tand  aot the shme whot nhe sewbteodsan tagd  althsteatnved the sewbteodsaor te, I hncy  aote of to sanld bave beised the shate Whale iorst  Bhe e ati boaos  -the   ati boaos  -the   ati boaos  the e anains -ahe   anains 

추측 :

"_nd ___ no_e of __ se____ _e_ore____ried _hab_ ___l_ng the __r___d _e_ a_l ___und _____
"_ _a_ _im ___ost _h_t ___e _n_tan__ __r, _h_t _aptain _hab _id_ _nd _ ___ed __t__ said __shtego__
"_o_ _he s_me _n_tan__ _ot the s_me___o_ _he ___b__o____ _____ __t___e___ved the ___b__o___or _e_ I _n_y_ _o_e of __ ___ld _ave __ised the _h_te Whale __rst_ _he_e ___ b___s__-the__ ___ b___s__-the__ ___ b___s_ _he_e a_ain__-_he__ a_ain__

변경 로그

  • 569279-whale2.txt 최적화로 변경 하여 제거했습니다.
  • 577366- 줄 바꿈을 언제 반환할지 추측하는 코드로 최적화되었습니다.
  • 590354- 원본 버전.

4
키 크기와 열 임계 값을 변경할 때 차이를 표시해 주셔서 감사합니다!
Jeremy Weirich

텍스트가 줄 바꿈되지 않은 파일 버전으로 질문을 업데이트했습니다.이를 사용하여 일부 포인트를 저장할 수 있습니다.
Nathaniel

@Nathaniel 그것은 실제로 않습니다. 답변을 업데이트했습니다.
Charlie

유형을 선언하는 대신 var를 사용하여 일부 바이트를 저장할 수 있습니다.
Ed T

1
키 크기가 커짐에 따라 적중 횟수 미스 수는 줄어 듭니다. 따라서 짧은 키로 정확한 문자를 추측했을 때 더 많은 공간이 출력됩니다. 키 크기가 작아짐에 따라 일치하는 세그먼트에 대한 개별 추측의 정확도가 떨어집니다. 나는 이것이 4의 길이가 최적 인 이유라고 생각합니다. 여러 길이의 키를 유지하고 더 긴 키를 사용할 수 없을 때 더 짧은 일치를 사용하면 더 긴 키 길이에서 적중률 (및 점수)이 크게 향상 될 것으로 예상합니다.
Jeffrey L Whitledge

11

Java 7, 1995 자, (1995 * 2 + 525158) 529148

Java는 작은 프로그램 크기를 빨아들입니다. 어쨌든, 나는 놀랍도록 엉뚱한 결과를 만들어내는 매우 복잡하고 까다로운 몇 가지 방법을 시도했습니다. 나는 다시 돌아가서 간단한 접근 방식을 사용하여 더 작은 프로그램 크기와 더 나은 결과를 얻었습니다.

이 방법은 실제로 매우 간단합니다. 이전 x 문자 (해당 문자의 모든 하위 문자열과 함께)를 현재 문자에 ​​매핑 된 해시 테이블에 맹목적으로 공급합니다. 그런 다음 현재 문자를 가장 정확하게 예측하는 패턴을 추적합니다. 특정 문자 앞에있는 패턴이 여러 번 발생하면 해당 문자를 예측하는 데 성공합니다. 더 긴 문자열에 우선 순위를 부여하고 주어진 문자열에 가장 자주 따르는 문자에 우선 순위를 부여합니다. 이 알고리즘은 문서 유형이나 영어에 대해서는 전혀 모른다.

가능한 경우 9자를 사용하고 이전 9 자의 단어 전체를 일치 시키려고했습니다. 문자열 내에서 단어 일치를 시도하지 않으면 최적의 길이는 6 자이므로 수천 가지 이상의 잘못된 예측이 발생합니다.

흥미로운 한 가지 관찰은 20자를 사용하면 처음에는 나쁜 예측이되었지만 후속 패스에서 정확도는 99.9 %라는 것이 었습니다. 이 알고리즘은 기본적으로 20 바이트 청크를 겹쳐서 책을 기억할 수 있었으며 책 전체를 한 번에 한 문자 씩 불러 낼 수있을 정도로 독특했습니다.

  • (1950 * 2 + 532919) 536819
  • (2406 * 2 + 526233) 531045 더 나은 추측을 위해 구두점 검사
  • (1995 * 2 + 525158) 529148 더 많은 조정, 더 많은 언어를 골라냅니다

package mobydick; import java.util.HashMap; public class BlindRankedPatternMatcher { String previousChars = ""; int FRAGLENGTH = 9; HashMap > patternPredictor = new HashMap<>(); void addWordInfo(String key, String prediction) { HashMap predictions = patternPredictor.get(key); if (predictions == null) { predictions = new HashMap(); patternPredictor.put(key, predictions); } WordInfo info = predictions.get(prediction); if (info == null) { info = new WordInfo(prediction); predictions.put(prediction, info); } info.freq++; } String getTopGuess (String pattern) { if (patternPredictor.get(pattern) != null) { java.util.List predictions = new java.util.ArrayList<>(); predictions.addAll(patternPredictor.get(pattern).values()); java.util.Collections.sort(predictions); return predictions.get(0).word; } return null; 
} String mainGuess() { 
if (trimGuess(",") != null) return trimGuess(","); if (trimGuess(";") != null) return trimGuess(";"); 
if (trimGuess(":") != null) return trimGuess(":"); 
if (trimGuess(".") != null) return trimGuess("."); if (trimGuess("!") != null) return trimGuess("!"); if (trimGuess("?") != null) return trimGuess("?"); if (trimGuess(" ") != null) return trimGuess(" "); for (int x = 0;x< previousChars.length();x++) { String tg = getTopGuess(previousChars.substring(x)); if (tg != null) { return tg; } } return "\n"; } String trimGuess(String c) { if (previousChars.contains(c)) { 
String test = previousChars.substring(previousChars.indexOf(c)); return getTopGuess(test); } return null; } public String predictNext(String newChar) { if (previousChars.length() < FRAGLENGTH) { previousChars+= newChar; } else { for (int x = 0; x addWordInfo(previousChars.substring(x), newChar); } previousChars = previousChars.substring(1) + newChar; } return mainGuess(); 
} class WordInfo implements Comparable { public WordInfo (String text) { this.word = text; } 
String word; int freq = 0; @Override public int compareTo(WordInfo arg0) { return Integer.compare(arg0.freq, this.freq); }

그런 장황한 언어에는 꽤 좋은 점수입니다.
DJMcMayhem

1
파일 크기가 프로그램 크기에 비해 개선의 여지가 많기 때문에 촬영할 가치가 있다고 생각했습니다.
Jim W

3
이것은 Java 7 (또는 가치가있는 Java 버전)에서는 컴파일 할 수 없습니다. 코드를 수정 하시겠습니까? 완료되면 점수를 높이기 위해 기꺼이 골프를칩니다.
Olivier Grégoire

테스트를 거치지 않았지만 950 바이트 와 동일한 코드를 사용해야 합니다 . 현재 코드에는 꽤 많은 오류가 포함되어 있으므로 모든 것을 올바르게 입력했는지 확실하지 않습니다. 다시 한 번 테스트를 거치지 않았으므로 버전을 비교하여 변경 / 개조 한 사항을 확인하고 모든 것이 여전히 원래 코드와 동일한 지 확인하십시오. 그래도 확실히 더 골프를 칠 수 있습니다.
Kevin Cruijssen

Crap, 나는 내 오래된 직장에서 지루한 동안이 작업을 수행했으며 코드를 가져 가지 않았습니다. 오타가 어디에 있는지 보려면 그것을 살펴 봐야합니다.
짐 W

10

파이썬 3, 2 × 497 + 619608 = 620602 2 × 496 + 619608 = 620600

import operator as o
l=''
w=''
d={}
p={}
s=0
def z(x,y):
 return sorted([(k,v) for k,v in x.items() if k.startswith(y)],key=o.itemgetter(1))
def f(c):
 global l,w,d,p,s
 r=' '
 if c in' \n':
  s+=1
  if w in d:d[w]+=1
  else:d[w]=1
  if w:
   if l:
    t=l+' '+w
    if t in p:p[t]+=1
    else:p[t]=1
   n=z(p,w+' ')
   if n:g=n[-1];l=w;w='';r=g[0][len(l)+1]
   else:l=w;w='';r='t'
 else:
  w=w+c;m=z(p,w)
  if m:
   g=m[-1]
   if g[0]==w:
    if s>12:s=0;r='\n'
   else:r=g[0][len(w)]
 return r

나는 이것을 독립적으로 시도했지만 결국 마이클 호머의 대답보다 열등한 버전으로 끝났습니다. 나는 그것이 내 대답이 완전히 쓸모 없게되기를 바랍니다.

시간이 지남에 따라 단어 사전 (조종 적으로 또는로 종료 \n, 대소 문자 구분 및 구두점 포함으로 정의 됨 )을 작성합니다. 그런 다음이 사전에서 현재 단어에 대해 지금까지 알고있는 단어로 시작하여 결과 빈도를 발생 빈도별로 정렬하고 (느리게), 다음 문자가 가장 일반적으로 일치하는 단어에서 다음 문자 인 것으로 추측합니다. 가장 일치하는 단어가 이미 있거나 더 이상 일치하는 단어가 없으면를 반환합니다 .

또한 역 겹게 비효율적 인 단어 쌍 사전을 작성합니다. 단어 경계에 도달하면 다음 문자가 가장 일반적인 일치하는 단어 쌍에서 두 번째 단어의 첫 글자이거나 t일치하지 않는 것으로 추측합니다 . 그러나 매우 영리하지는 않습니다. 다음 Moby프로그램은 다음 문자가 올바르게 추측 D되지만 문맥에 대한 모든 것을 잊어 버리고 일반적으로 고래 "모비 덕"이라고 부릅니다 (텍스트의 전반부에서 "네덜란드어"라는 단어가 더 자주 나타납니다) ). 개별 단어보다 단어 쌍의 우선 순위를 지정 하여이 문제를 쉽게 해결할 수는 있지만 이득은 거의 없을 것으로 예상합니다 (일반적으로 세 번째 문자부터 정확하고 단어 쌍은 처음에는 그다지 도움이되지 않기 때문에).

제공된 텍스트와 더 잘 일치하도록 이것을 조정할 수는 있지만 입력에 대한 사전 지식을 기반으로 알고리즘을 수동으로 조정하는 것이 실제로 게임의 정신에 있다고 생각하지 않습니다. 그리고 아마 그렇게하지 않아야합니다)), 나는 그것을 피했습니다. 필자는 입력 파일의 알려진 줄 길이를 무시하고 대신 \n13 공백마다 삽입했습니다. 이것은 거의 확실히 일치하지 않습니다. 주된 목적은 입력과 일치하지 않고 줄 길이를 합리적으로 유지하는 것이 었습니다.

코드는 빠르지 않지만 (내 컴퓨터에서 약 2 시간), 전체적으로 문자의 절반 정도 (49 %)를 얻습니다. 에서 실행하면 점수가 조금 나아질 것으로 기대 whale2.txt하지만 그렇게하지 않았습니다.

출력 시작은 다음과 같습니다.

T t t t t t t t t L t t t tsher t t t ty t to t t te t t t t t tem t t t d b ta tnL te t tv tath a to tr t tl t l toe g to tf ahe gi te we th austitam ofd laammars, tn te to t tis nf tim oic t t th tn cindkth ae tf t d bh ao toe tr ai tat tnLiat tn to ay to tn hf to tex tfr toe tn toe kex te tia t l t l ti toe ke tf hhe kirl tou tu the tiach an taw th t t Wh tc t d t te the tnd tn tate tl te tf teu tl tn oan. HeAL. tn nn tf r t-H ta t WhALE.... S tn nort ts tlom rhe ka tnd Dr t t tALL th teuli th tis t-H taCTIONARY " t r t o t a t A t . t eALT t I t HLW t I t e t w t AO t t t AOLE, I T t t t ALE t w t t R t EK t T t R tSupplied by wnLw t t iit ty cce thet whe to tal ty tnd

하지만 결국에는 좀 더 비슷해 보입니다. 책 끝에서 가장 좋아하는 구절은

어느 것도 내 것이 될 수 없기 때문에 너를 쫓아 가면서도 너를 쫓아 다니면서 고래를 let 아 주겠다. "나는 창을 포기한다!"

로 나온다

I dhrnery oyay ooom the woc Ihal iiw chshtego -tit my ti ddohe bidmer Hh, ho sheee opdeprendera toetis of tygd ahesgapdo tnep tnd tf y arosl tinl ahesgaorsltoak, and tidlhty ai p, cnd telas taep toip syst ho she tachlhe tnd tith ut ay Rnet hor bf toom the wist tord oaeve of ty nsst toip recked,hontain th, tingly toadh af tingly tike 'h, tot a hoet ty oh ost sreat ess iik in ty oh ost sremf Hew hiw"aoom tnl tou oolthert tyand . taoneoo sot an ao syad tytlows of ty oii e oor hoi tike and th ohes if oaped uoueid tf ty ooadh Ih ards the t houle lhesganl p tyt tpdomsuera tiile ah the wist t hrenelidtith the Ioom ti p s di dd o hoinbtn the Ior tid toie o hoetefy oist tyoakh on the Opr tnl toufin and tnl ti dd .mh tf ooueon gaor tnd todce tovther lon by tygd ait my the th aih tapce ciice toill moaneng she thesgh thmd th the thesgaoy d jiile YhE t hrve tpothe woerk "

그것은 칸의 분노를 훨씬 더 혼란스럽게 만들었을 것입니다. 그리고 "외로"→ "tingly"는 특히 만족스러운 치환이다.

편집 : 외부 공간을 삭제하여 1 바이트를 저장했습니다 .

채점

#! /usr/bin/env python3
import sys
import os
import mobydick as moby


def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

total = 0
right = 0
real_char = ''
guess_char = 'T'
print('T',end='')
with open("whale.txt") as whale:
    while True:
        if real_char == guess_char:
            right += 1
        real_char = whale.read(1)
        if not real_char:
            eprint(str(right) + " / " + str(total) + " (" +
                str(right/total*100) + "%)")
            size = os.path.getsize("mobydick.py")
            eprint("Source size: " + str(size) + "B")
            eprint("Score: " + str(2*size + total - right))
            sys.exit(0)
        guess_char = moby.f(real_char)
        print(guess_char,end='')
        total += 1

Moby Dick의 텍스트 프로그램을 실행하고 "예측 된"텍스트를 표준 출력으로 출력하고 stderr를 악용하여 점수를 씁니다. 출력을 파일로 리디렉션하는 것이 좋습니다.


2
PPCG에 오신 것을 환영합니다!
Martin Ender

1
하지 않을까요 lambda i:i[1]처리보다 저렴 operator?
Draconis

@Draconis 거의 확실합니다.
georgewatson

9

C ++, 2 · 62829 + 318786 = 444444

이 프로그램을 실행하려면 이 파일이 필요 합니다 (여기서 이름을 지정해야 함) C.

이 프로그램은 이전 답변 과 동일한 Markov 모델 조합을 사용합니다 . 이전과 마찬가지로,이 조합은 본질적 으로 user2699의 답변에 대한 모델 이지만 약간의 수정이 있습니다.

이 답변이 이전과 정확히 동일한 모델을 사용하는 방식을 보면 개선이 더 나은 정보 이론 메커니즘입니다. 앞에서 설명한 "되감기"메커니즘보다 입니다. 이것은 더 작은 결합 길이를 가지면서도 오류를 줄입니다. 이 프로그램 자체는 점수에 크게 기여하지 않기 때문에 크게 골프를 치지 않습니다.

프로그램의 길이는 2167 바이트이며 (들여 쓰기 및 기타 불필요한 문자가 많지만 테스트 코드 이전의 모든 탭 포함) 이진 파일의 C길이는 60661 바이트이므로 여러 파일의 점수 를 매기는 규칙에L 따라 2167 + 60661 + 1 = 62829.

이 프로그램은 m5.4xlargeAmazon EC2 의 인스턴스에서 실행하는 데 약 8 분이 걸리며 16GB가 넘는 메모리를 사용합니다. (이 과도한 메모리 사용은 필요하지 않습니다. 우리는 그 중 하나만 최적화하지 않았습니다.)

#include <map>
#include <queue>
#include <vector>
using namespace std;

FILE *in;
unsigned int a, b = -1, c, d;
string s, t;
double l, h = 1, x[128][129], y[129], m[128];
map<string, int> N;
map<string, double[128]> M;
int G, S;

int f(int C)
{
    int i, j;
    for (i = 0; i <= 20 && i <= S; i++) {
        t = s.substr(S - i);
        N[t]++;
        M[t][C]++;
    }
    s += C;
    S++;

    for (i = 0; i < 128; i++)
        m[i] = 0;

    int E = 0;
    for (i = 20; i >= 0; i--) {
        if (i > S)
            continue;
        t = s.substr(S - i);
        if (i <= 2 && E >= 100 && (i == 0 || t[0] != ' '))
            break;
        if (M.find(t) == M.end())
            continue;
        for (j = 0; j < 128; j++) {
            m[j] += M[t][j] / N[t];
        }
        E += N[t];
    }

    double r = 0;
    for (i = 0; i < 128; i++)
        r += m[i];
    for (i = 0; i < 128; i++)
        m[i] = m[i] / r;

    if (!in) {
        in = fopen("C", "r");
        for (i = 0; i < 4; i++)
            c = c << 8 | getc(in);
    } else {
        l = x[C][G]
            + (l - y[G]) * (x[C][G + 1] - x[C][G]) / (y[G + 1] - y[G]);
        h = x[C][G]
            + (h - y[G]) * (x[C][G + 1] - x[C][G]) / (y[G + 1] - y[G]);
    }

    priority_queue<pair<double, int>> q;
    for (i = 0; i < 128; i++) {
        q.push(make_pair(m[i], i));
    }

    int n = 0;
    double s = 0;
    while (q.size()) {
        i = q.top().second;
        q.pop();
        if (m[i] < s / (n + 15))
            break;
        s += m[i];
        n++;
    }

    r = 0;
    for (i = 0; i < 128; i++) {
        y[i + 1] = m[i] - s / (n + 15);
        if (y[i + 1] < 0)
            y[i + 1] = 0;
        r += y[i + 1];
    }
    for (i = 0; i < 128; i++)
        y[i + 1] /= r;

    for (i = 0; i < 128; i++) {
        r = 0;
        for (j = 0; j < 128; j++) {
            x[i][j + 1] = y[j + 1];
            if (i == j)
                x[i][j + 1] *= 16;
            r += x[i][j + 1];
        }
        for (j = 0; j < 128; j++)
            x[i][j + 1] /= r;
        x[i][0] = 0;
        for (j = 0; j < 128; j++)
            x[i][j + 1] += x[i][j];
    }

    y[0] = 0;
    for (i = 0; i < 128; i++)
        y[i + 1] += y[i];

    for (G = 0; G < 128; G++) {
        if (y[G + 1] <= l)
            continue;
        if (y[G + 1] < h) {
            d = a + (b - a) * ((h - y[G + 1]) / (h - l));
            if (c <= d) {
                b = d;
                l = y[G + 1];
            } else {
                a = d + 1;
                h = y[G + 1];
            }
            while ((a ^ b) < (1 << 24)) {
                a = a << 8;
                b = b << 8 | 255;
                c = c << 8 | getc(in);
            }
        }
        if (h <= y[G + 1])
            return G;
    }
}
// End submission here.  Test code follows.
int main()
{
    FILE *moby = fopen("whale2.txt", "r");

    int E = 0;
    int c = getc(moby);
    while (c != EOF) {
        int guess = f(c);
        c = getc(moby);
        if (c != guess)
            E++;
    }

    printf("E=\t%d\n", E);

    return 0;
}

7

파이썬 3, 526640

274 바이트, 526092 오류 (사용 whale2.txt) 이를 통해 추가 개선이 가능하지만 "게시하기에 충분한"단계에 도달했습니다.

from collections import*
D=defaultdict
M=[D(lambda:D(int))for i in range(10)]
X=""
def f(c):
 global X;G=D(int)
 for L in range(10):
  M[L][X[:L]][c]+=1;N=M[L][(c+X)[:L]]
  if N:g=max(N,key=lambda k:(N[k],k));G[g]+=N[g]*L**8
 X=(c+X)[:10]
 return max(G,key=lambda k:(G[k],k))

아이디어는 2, 3, 4, ..., 10 자의 모든 실행 빈도를 저장하는 것입니다. 이러한 각 길이 L에 대해 가장 최근의 L-1 문자가 저장된 패턴과 일치하는지 확인합니다. 그렇다면 우리의 추측 g L 은 그 패턴에 이어 가장 빈번한 다음 문자입니다. 이러한 방식으로 최대 9 개의 추측을 수집합니다. 사용할 추측을 결정하기 위해 각 패턴의 주파수를 길이에 따라 8 제곱으로 가중합니다. 가중 주파수의 합이 가장 큰 추측이 선택됩니다. 일치하는 패턴이 없으면 공간을 추측합니다.

(최대 패턴 길이와 가중 지수는 시행 착오에 의해 선택되어 가장 적은 잘못된 추측을 제공합니다.)

내 골퍼가없는 진행중인 버전은 다음과 같습니다.

from collections import defaultdict

PATTERN_MAX_LEN = 10
prev_chars = ""
patterns = [defaultdict(lambda:defaultdict(int))
            for i in range(PATTERN_MAX_LEN)]
# A pattern dictionary has entries like {" wh": {"i": 5, "a": 9}}

def next_char(c):
    global prev_chars
    guesses = defaultdict(int)
    for pattern_len in range(PATTERN_MAX_LEN):
        # Update patterns dictionary based on pattern and c
        pattern = prev_chars[:pattern_len]
        patterns[pattern_len][pattern][c] += 1
        # Make a guess at the next letter based on pattern (including c)
        pattern = (c + prev_chars)[:pattern_len]
        if pattern in patterns[pattern_len]:
            potential_next_chars = patterns[pattern_len][pattern]
            guess = max(potential_next_chars,
                        key=lambda k:(potential_next_chars[k], k))
            frequency = potential_next_chars[guess]
            # Exact formula TBD--long patterns need to be heavily
            # advantaged, but not too heavily
            weight = frequency * pattern_len ** 8
            guesses[guess] += weight
    # Update prev_chars with the current character
    prev_chars = (c + prev_chars)[:PATTERN_MAX_LEN]
    # Return the highest-weighted guess
    return max(guesses, key=lambda k:(guesses[k], k))

그리고 테스트 장치 :

from textPredictorGolfed import f as next_char
# OR:
# from textPredictor import next_char

total = 0
correct = 0
incorrect = 0

with open("whale2.txt") as file:
    character = file.read(1)
    while character != "":
        guess = next_char(character)
        character = file.read(1)
        if guess == character:
            correct += 1
        else:
            incorrect += 1
        total += 1

print("Errors:", incorrect, "({:.2f}%)".format(100 * incorrect / total))

다음은 텍스트 시작 부분의 샘플 출력입니다. 이미 우리가 그들의 첫 글자를 본 후 일반적인 단어를 마무리 할 수있는 능력을보기 시작 ( in, to, and, by, 또한 분명히, school).

 you take in hand to school others, and to teach them by what name a whale-fish
xU wshhlnrwn cindkgo dooool)tfhe -; wnd bo so rhoaoe ioy aienisotmhwnqiatl t n 

끝 부분에는 여전히 많은 실수가 있지만 매우 좋은 순서도 많이 있습니다 ( shmage seashawks예 :).

savage sea-hawks sailed with sheathed beaks. On the second day, a sail drew near
shmage seashawks wtidod oith tua dh   tyfr.  Tn the shaond tay, wnltiloloaa niar

실수 중 일부를보고 알고리즘이 "예상 한"단어를 추측하는 것이 흥미 롭습니다. 예를 들어, 후 sail두 시간 예측 프로그램 o--for는 sailor, 나는 추정. 또는 다시 , a예상 n되는 경우-가 일반적으로 발생하기 때문일 수 , and있습니다.


변경 로그:

  • 274 * 2 + 526092 = 526640 몇 가지 추가 오류가 발생하면서 알고리즘을 골프화했습니다.
  • 306 * 2 + 526089 = 526701 원본 버전

6

파이썬 2, 점수 : 2 * (407 + 56574) + 562262 = 676224

목록에서 이전 문자와 일치하는 단어를 검색  하는 모든  텍스트에 사용되는 대부분의 단어는, 그 발생 횟수 기준으로 정렬.

암호:

import zlib
f=open("d","rb")
l=zlib.decompress(f.read()).split()
w=""
def f(c):
 global w
 if c.isalpha():
  w+=c
  try:n=next(x for x in l if x.startswith(w))
  except StopIteration:return" "
  if len(n)>len(w):
   return list(n)[len(w)]
  return" "
 w="";
 n=ord(c)
 if n>31:
  return list("t \n 2  sS \n  -  08........       huaoRooe oioaoheu thpih eEA \n   neo    enueee neue hteht e")[n-32]
 return"\n"

데이터 : https://www.dropbox.com/s/etmzi6i26lso8xj/d?dl=0

테스트 스위트 :

incorrect = 0

with open("whale2.txt") as file:
    p_ch = ch = file.read(1)
    while True:
        ch = file.read(1)
        if not ch:
            break
        f_ch = f(p_ch)
        if f_ch != ch:
            incorrect += 1
        p_ch = ch

print incorrect

편집 :를 사용 whale2.txt하면 점수가 높아집니다.


5

C ++ (GCC), 725 × 2 + 527076 = 528526

또 다른 접두사 빈도 제출. 에서 달리고 whale2.txt다른 사람과 비슷한 점수를 얻습니다.

#import<bits/stdc++.h>
char*T="\n !\"$&'()*,-.0123456789:;?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz";
int I[124];std::string P(7,0);struct D{int V=0;std::array<int,81>X{{0}};};std::vector<D>L(1);D
init(){for(int i=81;i--;)I[T[i]]=i;}int
f(int c){P=P.substr(1)+(char)I[c];for(int i=7;i--;){int D=0;for(char
c:P.substr(i)){if(!L[D].X[c]){L[D].X[c]=L.size();L.push_back({});}D=L[D].X[c];}++L[D].V;}std::vector<int>C(81);for(int
i=81;i--;)C[i]=i;for(int
i=0;i<7;++i){int D=0;for(char c:P.substr(i)){D=L[D].X[c];if(!D)break;}if(!D)continue;int M=0;for(int
x:C)M=std::max(M,L[L[D].X[x]].V);C.erase(std::remove_if(C.begin(),C.end(),[&](int
x){return L[L[D].X[x]].V!=M;}),C.end());if(C.size()<2)break;}return T[C[0]];}

이것은 탐욕스럽게 역사의 접미사로 시작하는 가장 긴 문자열을 찾고, 후보가 여러 명인 경우 짧은 문자열로 타이 브레이크합니다.

예를 들어 지난 7 개 문자가있는 경우 abcdefgh, 그리고 문자열 abcdefghiabcdefghj형식의 모든 문자열에서 가장 큰 주파수 표시 abcdefgh*, 출력이 될 것입니다 i또는 j짧은 접미사 (와 타이 브레이크 bcdefgh, cdefgh...).

알 수없는 이유로, 7 개 이상의 컴퓨터에는 RAM이 부족하여 실행할 수 없습니다. 7을 사용하더라도 모든 웹 브라우저를 닫아 실행해야합니다.


테스트 코드 :

int main() {
    init(); 

    std::cout << "Start ---\n";
    std::time_t start = std::clock();

    std::ifstream file {"whale2.txt"};
    // std::ofstream file_guess {"whale_guess.txt"};
    std::ofstream file_diff {"whale_diff.txt"};
    if (!file.is_open()) {
        std::cout << "File doesn't exist\n";
        return 0;
    }

    char p_ch, ch;
    file >> std::noskipws >> p_ch;
    int incorrect = 0, total = 0;
    // file_diff << p_ch;

    int constexpr line_len = 80;
    std::string correct, guess_diff;
    correct += p_ch;
    guess_diff += '~';

    while (file >> ch) {
        char guess = f(p_ch);

        // file_guess << guess;
/*        if (guess != ch) {
            if (ch == '\n') {
                file_diff << "$";
            } else if (ch == ' ') {
                file_diff << '_';
            } else {
                file_diff << '~';
            }
        } else {
            file_diff << ch;
        }*/
        incorrect += (guess != ch);
        total += 1;
        p_ch = ch;

        if (guess == '\n') guess = '/';
        if (ch == '\n') ch = '/';
        correct += ch; guess_diff += (ch == guess ? ch == ' ' ? ' ' : '~' : guess);
        if (correct.length() == line_len) {
            file_diff << guess_diff << '\n' << correct << "\n\n";
            guess_diff.clear();
            correct.clear();
        }
    }

    file_diff << guess_diff << '\n' << correct << "\n\n";

    file.close();
    file_diff.close();

    std::cout << (std::clock() - start) 
    / double(CLOCKS_PER_SEC) << " seconds, "
    "score = " << incorrect << " / " << total << '\n';
}

언 골프 드 :

size_t constexpr N = 7;

int constexpr NCHAR = 81;

std::array<int, NCHAR> const charset = {{
'\n', ' ', '!', '"', '$', '&', '\'', '(', ')', '*', ',', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', ']', '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
}}; // this actually contains a lot of information, may want to golf it
// (may take the idea of using AndersKaseorg's algorithm, late acceptance hill climbing)

std::array<int, 'z' + 1> const char_index = [](){
    std::array<int, 'z' + 1> char_index;
    for (size_t i = NCHAR; i --> 0;) 
        char_index[charset[i]] = i;
    return char_index;
}(); // IIFE ?

std::string past (N, 0); 
// modifying this may improve the score by a few units

struct node {
    int value = 0;
    std::array<size_t, NCHAR> child_index {{0}};
};
std::vector<node> node_pool (1); // root

int f(int c) {
    past = past.substr(1) + (char) char_index[c];

    for (size_t i = 0; i < N; ++i) {
        // add past.substr(i) to the string
        size_t node = 0;
        for (char c : past.substr(i)) {
            if (node_pool[node].child_index[c] == 0) {
                node_pool[node].child_index[c] = node_pool.size();
                node_pool.emplace_back();
            }
            node = node_pool[node].child_index[c];
        }
        assert(node != 0); // the substring is non-empty
        ++node_pool[node].value;
    }

    std::vector<size_t> candidates (NCHAR);
    std::iota(candidates.begin(), candidates.end(), 0);
    for (size_t i = 0; i < N; ++i) {
        size_t node = 0;
        for (char c : past.substr(i)) {
            node = node_pool[node].child_index[c];
            if (node == 0) break;
        }
        if (node == 0) continue;

        assert(node_pool[0].value == 0);
        int max_value = 0;
        for (size_t x : candidates)
            max_value = std::max(max_value, node_pool[node_pool[node].child_index[x]].value);

        candidates.erase(
            std::remove_if(candidates.begin(), candidates.end(), [&](size_t x){
                return node_pool[node_pool[node].child_index[x]].value != max_value;
            }), candidates.end()
        );

        if (candidates.size() == 1) 
            break;
    }

    return charset[candidates[0]];
}

출력 예 :

~ ~s  ta~ hard ts tt~~~~~~~ ~doam ~~ ar~ ~ i~~~ ~~~ ~he~~~~,a~ t~~~~ t~ ho~si~  
n--as his wont at intervals--stepped forth from the scuttle in which he leaned, 

~~~ thr~ ~~ t~~ crp~~~~~~~~ a~ wap~~~~~ a~eo~~ h~~ o~~ s~~~ or~~y~ ~  boog~e~~ t
and went to his pivot-hole, he suddenly thrust out his face fiercely, snuffing u

~ a~~ ~h~ ~n~ onitn~oi~~~~~~ ~~a~ ~ cewsoat~  a~ tae~~~~ ~e~~t~~ te~~ ouc~s~i~~ 
p the sea air as a sagacious ship's dog will, in drawing nigh to some barbarous 

ct as I~ iisk~~~~ ~~e~ tls~~~~ i~~~ ~~ soe~e Ae ~ ~~e~ tar~~~~~ trd~  ot ~ h~~~ 
isle. He declared that a whale must be near. Soon that peculiar odor, sometimes 

이것은 텍스트의 끝 부분에 있습니다. 대부분의 긴 단어가 매우 정확하게 예측 ( intervals, pivot-hole, distance)

 au t  tf weu~i~ aor~ mre~g~~~ m~t~~ ~~~  ~"NC~X~t~ti~  ~~n~ SNsh A FNECnSERTR O
 on as it rolled five thousand years ago./////Epilogue//"AND I ONLY AM ESCAPED A

NL~~,S~ ~HR~ yO~ -/s~n "~A~~ laeu~ta Vew~, S~e s~~  s~ ~ ain~ t~d ~t~ oirept~~ ~
LONE TO TELL THEE" Job.//The drama's done. Why then here does any one step forth

대문자가 좋지 않습니다.


Trie는 내가 예상했던 것보다 더 많은 메모리를 소비하는 것 같습니다.
user202729

... 그리고 구현하기가 더 어렵습니다.
user202729

4

파이썬 2, 756837

Markov 체인 일 수있는 것을 사용합니까?

import zlib
a=eval(zlib.decompress('x\x9cM\x9cis\xda\xcc\xd2\x86\xff\x8a2\xf5\xd4\x81\xb8,\x977l\'\xf9\x90\x12 \x02f\x11G\x02c||*%@,a\x11a1\xe0S\xef\x7f\x7fC\x13\xf75\xdf\xda\xaaa4\xd3\xcb\xddw\xf7\x8c\xfc\xbf\xcc\x8f\xd7E\xe6\xab\x93if\xce\x9d\xcc\x8f\xefG\xd1\x11\xf1\x1b\xa2At\x8e\xa2\'\xe2\xc5Q\xfc,\xa2{\x14+"\x9e3\xf63b\x87\x9f\xb5\x8fb$b\xeb(\x96E\x8c\x18\x1b2\xb6{\x14/D\xfcq\x14\x03\x11}\xc6zG\xb1.b\xc0\xd3\x06\xcb\xa9\xf1\xb3\xcaQl\x88X>\x8a-\x11\xb7G1\x11q\x85\x98\x1c\xc5\x95\x88\xf1Q\xec\x89\x98\x1e\xc5\x81\x88\xa2\xb3X\xc4\x19\xe2\xe4(\xbe\x898\xd6\xc9F\xa8\xe4E\x16\x19\x8a\xc8r^|U\xc9\x8b\xc7\xd8\xfcQ\xf4\x8f\xe2\xbf\x1c\x06\xbc\xa8v6\xef\xba\xb2\x17V\xf6\x92\xe8r6\x07\x9d\xcc\x95EN\xe4\xe9FW\xb6\xd9\xea6M\xa2K\xdf\xact\x86\xf9\xc976Gy\xf2\xce\xef\x96G1\x15q\xf1\xf1\xd4\xcc3\xe6\x8f\xb8\x96\xdf}\xd27\xcf\x1d\x9da\x8e\x1f\xcd\xc5c\\\x11Q\xcf\xfc\x02Q\x9c\xe7\\\xd6\xbe;\x8acY\xe5\x8c\x17\xcfu9F\xc4\x83\xfc\x0c\x076\x0b\x1d;\xc7\x97\xe7_U\x9c\xacT\xfc\xc2\x1a\xbe\xb0\x06\x83\r7b\xd9\x85<\x9d\xe8\x86\xbe|Q\xff\xfc\xf2\xa0\xe2d\xa7?\xfbr\xc5\xbc\x97\x8c\xbd\xd1\xbd}\xb9f@\x8e\x01\xb7\x88\xf7\x88w*\xce\x13v1\xc1ZCv\x1c\xebz\xe7=]\xce\x1c\x9d\xcdg\xe8,U/\x98/\x18`\xed\xf8\x8d\xa7\xe21\'\x1bo\xd4,sk\x80\xb8\xc6L\xc45Oq\xa9M\xac\x9e8\xc7?k\xb8\x9fY\xe9\x80\x9a\x8c\x9d\x8a\x98\xea\xde\x8c\xcc\xbb\x94\xa7\x13\x06\xc8\xca\xfa"\x1e\x98\xa1\xa4\xe1R\xfb\xa1\xb1W+\xf2b\xc0\xa4\x96W\xac\xa8\x15\x10=\x8d\xd3ZC#\xb2F \xd7j\xccP\xd78\xadU\x8fbWD"\xbd\xd6Q\xb7\xaf\xb5\x98\x0cH\xac\x85\xfc\x0cH\xac5\x15(k\xdd\x8f\xa7\xa6&\xf1v\xfa\x19\x00Q\xc3\x7fkxuM\xe2\xad(\xa2D\xd6\xabX\xb6&\xfeyy\x14\x1d\xdc\xa4v\x8azY\xdbU\xa4P\xf9\xc4\xcc?\x0fj\x8d\x9f\x135\xf8O\xde\xf7\xd3Q?Ym\xf4\xe9\n\xefY\xe12\xab\x9d:\xc7\n`Y\xfd>\x8a[\x11\xf1\x88\xd5\x9a\xc9\xf6\xcc\x80#\xad\xde\xd5+W\x03\x9e\x12/\xab!\xf3\x8e\x98\x81xY\xf5\x18\xd0g2\xe2e5g\xb2\x05+\x13\x07\x9d\x8b8fCD\xd1j\xca\xcf,X]\x81X+\xb0i\xa5\x88\xf5\'\x1c\x14VW`\xe9\n\x84]\x19u\xaa\x15\x16X\x81\xb0+\x0c\xb7"\'\xbf.N\xab0\xa7?n\xd5\x13^\x179\xb5\xf9\xebB<\xe4\xe1$_[c\x04\xc3\x06\'\x99W\xbd.\xb2\x1ap\xaf\x8b\xb3\x8fy\xcc\x9fW\x19\xe6t\xacE\x18\x1d\xffoR\xf1\xeb\xa2k\xc9/\x96\xfc\x1fk\xfa\x96Z\xe7u\xd1VLx]<\xa9Q^\x17\x1dkL\xd3\x9a\xe7\xdfj\xe4\xd7Eh\x8d\x8fT\xc3\xaf\x8b\x9a5\xben\xc9\ru\xd2\xd7E\xa0\xf6}]\x94\xad1\x15k\x8b\x8f\xd6\xf8\xaa\xf5\xae\xa25\xde\xb7\xe6)Y\xe3\x7fX\xb2g\x8d\xc9[\xeb/(:\xfc[\xd4P9=>X?}\xb7\xe4\x8d\xa5\x92\xad5\xe5\x9b\xb5\x9c\x9d5Fbru\x92\x7f[\xaf]Y\xe3\xd7\x96\xdaf\xd6\x16\xe7\x1a\t\xaf\x8b\x85\xb5\x06\t\x96\xe1I\x1e[\xf3L\xac\xf5\xfc\xb2~;\xb5\x9e\x0f\xac\xf1\x12\xd7\xfb\x93<\xb4\xe6\x1fYk\x8e\xad\xdf\xf6\xac\xdf\xf6u\xfc\x80\x00\x19\x10A\x03\xdcz\xa0ac\x06\x84\xe3\x00>3 2\x07D\xe6\x80\xd8\x1e\x10\xdb\x03\xd8\xc8\xc0\x02\x82\x01\xb9w \xea\xd9\x89\x08\xee\x0c\xe6\xaa\xd8\x01\xba\x19L\xf9\x19\x9a\x1c\xa0\xc8\x01\x807\x00\xf0\x06hq\x00\xd9\x1d\xf4\xd0\x89\xa5\x9e\x985\x80\xb4\x837\xd6\x00\x82\x0f\xf0\xae\x01\x19y\x80\xaf\x0c@\xf0\xc1\xf2cCf\x87Vw\xe8o\x87Vw\x98h\x87]vXk\x07a\xdc\xa1\xf6\x1d\xba\xdea\x81K\x012aR\x977\x88\x97\no\x97W<\x85u]\n\x17;e\xceK(\xda%\xc4\xed\x12\x16x\t7\xdcYV\xbe\x94-I\xba\xbcd\xa3\x97\xec\xee\xf2\\W\xb1\xc3r;l\xb4\xc3r\xbb\xbe\xea}\xd7C\x14s\x9dt\t\xb5\xdb-\xd0\x04>\xb5#)\xed\xe0\xb5;\x12\xd8\x0e\x84\xd8Q8\xec0\xe2\x8e\xe4\xbc[2\x00?\xb9\xc4#\nl\xb3\x80\xe5\n\xa2\x12![\x05\x81G!\x1e\x05AP)\xed\n\x02\xac\x02\xfa\x85\x80\xa75\xc5\xba\x02t\xad  )\xc5l\x01jW\xe8"\x86\xbcB\xd0RrR\xa1\xc5+\x08\x9d\xc2X\xd5W \xbd\x17f\xba\xcd\x82\xa8Z\xd2N!Q\xf5\x15\xdeU}\x85\x83\xc6@a\xa5\x01U\x10\xa5\x9e\xd8\xee@\x9fN 4\x06,3#\xd5\xaf\x01\xc9\x0c$\xc5\x10\xa8\x13\xe0y\xb2\xd4\x1dO0\x96I\xd5\x16\x93\xadnh\x82\x85\xcc/f \x1f\x18\x06L\xc6\xba\x9c\t\xc8c\xc8\x17\x13j\x8c\xc9L}}\x92\xea\xd2\'\xe2\x88#\x11\xd9\xd0\x04\xaa5\xe9\xf1\xb3D]\xd9\x90\xce&#\xc6\x0e\xd9[\x11\x9d\xf9\xe8\x97dj\xc8\xa5\xc6\xd3\x080dRSP\xbb\x99\x1ac\xeb<%\xf3\x9b\x00\x9d\x91\xf7\ri\xdf<2/I\xdf\xc0Y\x0c\x94\xc5<1\x03\x84\xc5\xc0W\x0ct\xc5\x84,\x07\xb2b\xe0KO\xb2\xb7\x9ah\x07\xf43\xaf\x19uv\x039\x7f\x12MI\x1d\xf3$k/\xc8\x80\x0b\xc5.s\x06\xe6=\xc9\x9e\xa58\x99\xb8\xea\xd7\x13"yr\x81\xed\x01\xb7\x89\xbcN\xb2\xd9\xc4\xe8l\x7f\xcah\x85|\xc3:\x9fp\x89\'0\xefi\xa2\xa29\x81\xe9\xdf\x15\xa5j\xc7\xc9\xe9\xb9\xbc&Gc)\x87\xeb\xe6@\xe4\x1c8\x9d\xcb)\xde\xe6\xc0\xf4\x1cew\x8e\x04\x90#-\xe4.u\xc99RHN\x12\x8b$\xa1\x1cj\xc9\x01{9\xf8w\x19L*\xd3\xf2*S\xf5\x95\x9fxJ\xff\xac\xdcb\x00uc\xb9\x82\xd8`\x00Uj\xb9\xce\x0c@d\x19\x88,\x1f\xd4ve\xca\xb4\xf2\x04\x11RR\x8e\xd5\x1ce*\xab\xb2m\x992&-\x7fV\xfd\x94/\xac\x11(\xa8\xec\xaac\x95\xb5\x92\xfd\x13VZ\xdf\xfeG\xb4\xd2\x16Q;d&\xf3\xcd\xe8l\xaf\x19\xcb\xb52\xce\x87k\x99\x8c{\x14]\x11\xcf\xcd\xc7\x0b\x17$8\x8br.\x00\xbf\x05yqA\xb6\xb4\xe8\xec\x02\xb6v"\xb3\x12\x86\'\xaey\x12\xa1R\'\xa6y\x1aKM\xba@s\'\xea*\x00qb\xae\xa7\xa7{\x9e\x92N\x17$\x97/\x04\x96E\xd2-\x8enQ\xf4\x05I`AA\xbe \tX\xf4\x7f\xa1t\xcedv\xe6o\xf8\x98\xcc\x9b\xf9;\xc0d\xb6\xe6\xef6Mf\xf3\xa1T\x93Y#\xae\x18\xfb\xdb\xfc]\x8e\xc9,\x8d\xce{`\xc0\x88\xa7C\xf3Wg&\x93\x98\xbf+3\x7fx\xb6\xce\xdb?\x8a3\x11{\xcc\x1b36\xe5\xe9\xe2\x8fh2\xe6(\xce\x99a\xc6\x0c\x13\xf3\xd7\xf2&3f9\x1dv\xfc\xc4\xd3\x16O#\xdc\x08&\xba\xb8\xc0-\x9bFm\x01\x81]\x00\x88\x0b\xc3\xd8\xae\xbe\xe2T!\x9f\x94\xea\x1f\xc5\xbd\x88E\xb4S@\xcc\xb3M\xcf\xa8{~g\xde\x80\xf56\xf8Y\xfdc\xac\xc9\xd4\xcc_\xe72\x99\n\xda)\x7f\x8c\xcd|eo_\x1du\xb9\xaf\xf4\x1a\xbeZ\xe1\xfe\'Gj\xac\xd6\x8f\x1b\x15\xbdg\xea\x8e\xe6\x9c:\xd3\xd5\t\xfc:\xc8X\x07%\xea\xf0\xf7\xfa\xe9%\x1d\x91\xe9l\xd7\xc9\x12u\x89>\xe9\x82\xd7\x01\xab:\xb5G}\xc3\xc4+D"\xaa\x0e\x08\xd6i\xf6\xd5\x0b\x9a\x0e\xeb4\x06\xeb\x02\xa3\xc2\x1e\xeb5\x05\xad:8[o(\xce\xd6+\xec\xbe\xcd\xcf\x9a\ne\xf5\x88\xe5\x90\x0c\xce_9[X[\x95\xc3\x1aD]S\xca\xac\xd1\xd59f:G\xdb\xe7g\x0c \xf9\x9c\xd3\xeeYgu\x99k\xcc\xb1f\x865\xf6ZS\xf1\xae\xf1\xe7\xb5z\xb9Yg48\xce\x1f\xf4\x15\xdfu2\xf3\x9d\x01\xdfA\xec\xccwG\xcd\xbc\xc62k@kM\x07y\r\xc0\xad\xa98\xd6t\xdd\xd7\x18\x7f\r\xd6\xad\xa1\xab\xeb_\x8a\xcdk\xe0\x7f\r\xb5]\xc3\xf6\xd7\x00\xfd\x1a\xf8_\x93\x14\xd6}\x85\xdeu\x8f\xa7\xb4\xb9\xd7#\xd6\x0b\xd0\xaf\x81\xff55@H\xb9\x15&\xba\x86P&\x93f[\xc8\xca\xc2\xb1\xbe-\x94]\x08\xa7\x0e\xe1\x07!\xdd\xa0\xf0\tQ\xb8\x84\x90\xa3\xb0\xa9\x8e\x1dBAB(H\x88[\x86\xf4\xccC\x02&\xfc\xa1\x8e\x1dz\x1a0a^}<\xa49\x15R\xb0\x85\xb0\x91P\x02F\x90#\xa4\xb8\x0b\xe9\x99\x87\xd4\x84!\xce\x1e\x12\x02!\xbd\xd2\x10\x18\n\xc5\xa3\xaeD\xc4\x81C\xf1\xc4\xbc\x888{\x08\xf6\x84\xa7\x88\x93pH(e\x12J\x99$Us&\xd4\xd4\t\x0c5\xa1\r\x93L\x15\x91\x12|.I\xd4\xc8\t| !\xf3\'\x94\x7f\tT+\xe9+\x16$\x90\x8b\x84pI\xf6\x0c\xe0\xb0.\x81\xcd%DC\xb2C$\xf3\'\x84VB\x01\x99\x10\x86\tgf\xc9\xcf\xa3(\\7\x01,\x12t\x9d\xa0\xe0\x84\xfeY\x02\xedO\x80\x90\x84\x92$!\xc5$\xd8;\x01\xfd\x12L\x7fA\xa1\x92\x9c\x0c\'S\xec\xa1w\xfb\x89jjO3dO\t\xbf\'\xa8\xf7\xf0\xb4}\xac\x10\xb2O4\xf8\xf6\xa2\xebO"\x82<{\x94\xb6\xa7E\xb2\xdf\xaa\xc7\\\xd1\x1d\xdd\xa3\x93=\x9a\xda\x8b\xfe$\x87\xedE\x11R\xaf\xecU=f\x8f\xd2\xf6\xec~om\xf9\xeaR\xadqE=rE\xa3\xeb\x8a:\xe7\x8a:\xe7J\xea\x9c{\x11\xa9s\xae\xa8\x94\xae\x04\xc5\xafE$\xbf\\\xd1l\xbb\xa2_u\xc5\xe6\x8a\x12\xca\x82\xe7\xc5\x9a\xc6z\xb1\xae\xb8P$\xc0\x8b`H\xb1\xa8\x10Q\xf4\x15N\x8ad\xe5"\x80T\xa4<*\xb6\x15\xc7\x8a\x1c\xa0\x15#\x85\x93"\xed\x87\xe2D-[\x84P\x14c\x05\xd0"\xa7\x87\xc5\xad\x1a\xaeH\xfe)\x9e\xd4.(S\xb4\xb6\xac\xf64\xc5\x8cr\xb2"\x14\xa8\x88\xbb\x17\xf1\xe6\x8e\xaf\x88\xd4\xa1r\xefp\x9b\xa1C=\xd7\x81rt\xd0_\x87\xf6X\x87\xc2\xb7#\xbb\xff&"-\xafN\x131Q\x07\xed\xd01\xec\x80n\x1d\x1a\x82\x1d\x02\xaa\xa3\x8a0\x1d\xd0\xb6\xe3\xb02\xee\x85t\xb8\x17\xd2\xb1N\x1d;\xec~\xcb\x81\xdf/p\xeaZ\xbc2\'O\'\x1a\x1a\xbf\x12\xb5\xdc/Y\xb0T>\xbfR5\xd7\x1d\xfc\xe6\x8e\xe0\xba\xc3Dw\x04\xc9\x1d\xa5\xfc\x1dArG\xe8\xdc\x11$w9\x8d\x81;\t\x129\x0e\xbb\x93EJ\x82\xb9\xa3\x9dp\xf7E\xc3\xa1\xc5\xed\x8a;\xab\x81F\xeb\xbeb\xc5o\x05\x9dT@\xbd\n\xc0ZaG\x15vT\xc1\xa7*\n\xa1\xa6\x92\xf9(r2\x95g\xf4^\xe1\xeeH\xa5\xc9\xefH\xf7\x95\x10\xb1\xad\xc1S\xc1\xa9*O\xea>\x95\x8a\xee\xb9R\xd7\xf0\xabp\xdf\xa6\x12\xa8\x87V\xc4\x85\x7f\x88\xc8\x8d\x9dJ\x81\xc9\xf2\xea(\x15\xc8E\xa5\xc8\x80\x1f\xac\xa1\xc4S*\xe4\n9\xaaB\xa3\xb5B\xc2\xab\x08\xceK\xbb\xadB2\xaf\x88\xf7\x08\xa2WH\xe6\x15\x12Ae\xa4\xc8Q\xa1\xd7\x98\xa5\xb0\xce\xaeu\rY\x8a\xf0,\r\xd1,\xb6\xf7\xb0a\x16\x92\x90\x85\x82f9O\xce\x92\xad\xb2\x9c\xa8e\xa1$Y\xc8f\x96s\x80,\xa1\x9c\x85E\\\x8b\x01\xe4\xf8?\x0b\xad\xcc\x82\x0b\xd9H\x8d\x95m\xf26i;\n^g\xe9@e\xf1\x87lU\xed\x96-3\x96.h\x96r(+\xfe \x80\x9e\xad\xf1b\n\xaa,\x9d\xd8l\x81\x9fy\n\xb6\xd9\x92:W\x96\xcb\x1c\xd9"/\xf6\xd9\x85\xc4\xf71\xb1\x99\xe3!\xb3\xc6@jUT\x0b\xfbv\x13\xa7*\x9eL\xf8$\xa3\x89\xb4\x94PL1c\n\xb1I\xc9\xd1)Q\x99\xd2\x01H\x89\xeb\x94hO\xc9\xe7\xdf\xa8\xae\xbei\xae5\xdf\xa8\x98\xbeQ\xcb}\xb3\x96#\x9e"\x97`R|8\xc5SR\xf1\x1fa0)EP\xfa\x0b\x11\x0fL\xc7\x1a\x10)\xa7\x85)\xae\x9f\xd2\x92O!\xafi\x9f5\xd0\xbeOi\x87y\xa1z`\n7M\x0f\xea\xb8\xe9\x9e\xc9\xe0\xa6\xdf\xacb8%\x1b\xa7\xc4u\xca-\xa3\x14r\x9a\xc2\xc9R\x98Z\x83}6\xe8f6h&4\x92\x8f\xa7\xa6Erk\xf0\xe2\x06i\xb7\x81\xef7\xa08\r*\x9b\x06\xd7\x85\x1a\xa4\xf3\x06d\xa6Am\xd4\xa0\xbaj\xf8\xfc\xec\x07O\x9f\x11\xe1@\r\x9a\t\r\x88O\x03Do\xb4\x18@\x0f\xa2\x01\x8c7:\xec\xc2J\xd1\r\\\xbcA\xc9\xd4\xb0\xda\xb7\x0b\x92m\x03\x8e\xd3\x80\xb36,\x05\xe2\xee\x0bk\xe2\x93me\xff16\x88\x01\xdf\x18W\x8aa+1n\x17\xe3\xa2\xf1P\x8d\x14c\xe6x\xccX\\?\xc6\xf5c\xc2$&-\xc4\x80o\xbc\xd0\xe0\x89q\xaax\xc9\xdb\xc8<\xf1\x8a\xb1\xb0\x99\x18g\x8d9(\x8f\xa9\xbabJ\xb8\x983\xc0\x980\xb9\x82\xac,\x80\x8b\x05Zm\x9dTy#\xbf\x03|b(A\x0c:\xc5\x90\xf7\x98c\x9c\x18\xc3\xc4\xa0^\xcc;b\xe0+\xb6\x88\x8b\xebk`\xbb\x9c\xc0\xb9\x9c\xb5\xb9\x82\xda\x92O\\\xf1}I\x85.G\xb6n\x9e\xb1u\xc4\x1a?\xe3\xac\xcd%\xa6\\\xb2\x8c[\xe6gD\xa5\xfb\xc8+\xda\xea\x11.\'p.gm.w\x86\\\xce\xda\xdc&\xf3r\xd6\xe6\x86\xfa\xd4!\xc5\xba\x9c\xc09\xdc>q)\xf5]2\x8ck\r\xa0#\xe4\x12\x03.g\xba.\xa5\xbeK\xa9\xba\xd9\xf1\x94\xbb4.Wl\\b`\x83\x83\xba\xdc\xa3q9\xecp\xc5W\x85\x1a\xb9\x90\x95\r5\xb2\x8b\xaf\xba\xc4\x80\x0bww\xd7h\x12\xf6\xb5\xe1\xfe\xc2\x86\x1do\xe8vm8\xe1s9~\xdap\x14\xecr\xd8\xe1\xda\xa7K\x1b+s;\xd6\xd5f\x1a\xe0\xaev\xd33\x1bBf\x83;\xbbV\xf7\xd1u1.a\xe0f\x99\x98\x88\xd80`\xe3\xa2,x\xc0\x86H\xdb\x90\xd07\xf0\x80\r\x01\xea\xa0\xee\x11\x17\\G4\x17#\x16\x1c\xb1\x8d\x88P\x8ch]E\x16:G\xb24\xc92\x11\x0b\x8e\xe4\xcdB\x1a"\xbd\xc8o"\x80::\xe9\xb5$\xf2A\x8d\x13a\xf4\x88l\x1a\x01f\x11\x1d\xd7h\xc3\xd8\xa9*0\xa2=\x16QKF)K#\xcfG@r\x84\x0fF\x84D$\x81"\x146J\x18\x10)4DT\xb9Q\x07Q@@\xca\xeb\x88\xcb\xb7\x11\x17u#\x92{TV\x18\x89\xe8JF\xa0OTg\x00\xd9?\x82\xb7Fy\xe6\xf5\x18Ku3\xc4\x9eC\xac<\x14\xd3\xca\x9d\xcc!.3\xc4e\x86\xda\x1e3C<mH6\x1eb\xef!$q\x88\x07\x8f\xf0\x9e\xa1\x15GC\x02w\x08b\x0c\xe9h\r\xe9h\ri\xb6\x0fi\x97\x0ci\x9a\r\xb1\xcb\x10\xee8\x04\x94\x86\xdc\xe4\x1f\x02kC\xcd\xbbf\xc4\xe6\x1c\xa9\xb4\xa5\xfe>\xb0\xcf\x03\x9b;\xb0\xe5\x03\xfb<\xa0\xb4\x03\xaa<\xa0\xbf\x03\xaf8`\x81\x03v9\xa0\xa9\x11o\xbb\xa63p\xcd\xd5\xafk\xdag\x07K\xab\xd7\\\xfb\xbf&\x8b_\xd3r\xb8\xa6\xe5pM\x1b\xe1\x9a\x0e\xdc\xb5\xac]: \xd7\xec\xf3\xda\xda\'Z=PU\x1e\xe6\xfa\xb3\x03\x08y\xa0\xbds\xe0`\xe3@\xf7\xeb\x00\xf8\x1e\xc8<\x07\x0e+\x0e\xc0\xf7\x81\xabI\x07\xa0\xfe\xb0d\x06\xfc\xe8@\xff\xec\x00\xe8\x1d(\x93}\x0bz|\xd0\xcbg\xcb\xbe\x85o\xbe\xc2\x9e\xf1\x81/\x1f\x8b\xfb\xdc\x88\xf7Aa\x1f\x83\xfaX\xdc\xa7\x7f\xe1\x13\xcb~\xa0p\xe1K\xdcK\xe9\xea\x83\x11~Y\xd1\xc0\x87u\xf8\x12\xe1/"B\xea}>_\xf2\xa9b}j\x01\xbf\xc0\x0cy\x96\x0e\xd5\xf7\xa5\x00\x10\x92\xed\xbf\xf0bN{\xfc\x0e?\x83\xdf\xfb\x94\xf0>=\x1f\x9f\n\xc1\xa7\xe7\xe3\xd3"\xf1q\x19\x9f\xfbZ>\xc7L>W\xe3|\xf1\x08a\xbd\xbex\x84d.\x9fF\x84Oq\xe8\xe3S\xfe\x9e\xb7Au}\x9af>\xd0\xe3C@|r\x91\xbfd\x91\xe2i\xbfE\xa47\xf3|\xf2)1\xe73\x01\xf3\x8co<\x8b9\x9fE\xa4_\xf5La\xf6\x0c\xbd}~V\x13\xfd#\x88$\x14\xfa\x1f.\xc5?\x8b1\xa4)\xf1\x0c\xb3\x99Zh0\xe5lc\x8a\xafN9?\x9d\x02ISh\xfa\x94\xb5O\xc1\xa1)\xa11\xc5\x99\xa7\xc0\xd7\x14o\xbfg\x86{\x1a\xf6\xf7\xf4Y\xef\xef\xf4m\xf79]\xef=Pw\x0fN\xdd\x83^\xf7|\xe0t\x0f\xd2\xdd\x0bzIk\xf4\x1eL\x9bb\xfb)\x1f\xd5Ma\x86\xd3\xa1b\xc4\x14\xc0\x99\x02oS\xe0mJG\x7f\n\xeb\x9d\x92J\xa6P\x87)04\xe5\xb6\xea\x14\xef\x99\xc2d\xa6$\xb9)e\xd9c\xa0\x0e\xf1\xe8+L=J\xf8J[\xf3\x99\xf3\xd5GV\xf6(K\x17\xa2\xf2\x88C<ri\xf4\x11k>b\xa1,*1\x0c\xf8\xafM\x80?c\xf0\xcf\x18\xfc3\xa3?\xe3\x1c\x9f/x\xca\x8d\xa1\xcf\xa0\xe2\x92\x88Y\xa2\xaa%Lo\x89~\x96\x1bDBu\x89\xaa\x96\\D^\xd2\x96\xfcl/~I\xd5\xb4D-K\xd8\xe2\x12;/\xb1\xfe\x92\x84\xb5D\xc7K>\xbf\\b\xfd\x1b\xf2\xe7\xd2\x8a\xbf%j[\x12\x1cK\xd8\xc1\x92\xfe\xc5\x92P\\\xc2:\x96\x98i\x89\x8a\x97(\xfe\x86\xa7\x01c\x03W!\'\xb0\x06h\x88\x9b\x80,\x16\x80\x0c\x01\x9d\x95\xe0\xb4\r\xf1\xb6\x806_@\x9a\x0fh\xf3\x05c\x8d\xe6\x00\xfa\x15\xd0Y\t\xf8\x10"\xe0\x849\x80\xd6\x05 n@\xfb+ u\x07DR@\xc6\x0f$P\xaa"rn\x15\xd4\x11\xb9\x04\x10Ty\xca\xf5\xc5\xa0\xac0\x1cH\xd2\x14\n\x1d\x94\x18\xcb\xd7\xb2\x01\x07\x04A\x01M\xf1\xe1l\xe0\xf1TR\xa9\xa4\x82\xa0\xc3+\xc8\x94\x01\xb7\xc1\x03:\xdc\x01UE\x10\xaaO\x05Z`\x98\x1en\xd2\xe3\x10\xbb\x87\r{\xd8\xbb\x87\x9b\xf4\xf0\x8d\x1e\xde\xd5\x83\xfd\xf7\xbe2\x16\xaf\xed\xbd\x02v\xbd\x81Z\xa0\x07\\\xf6F\x0c\x80\x8f\xf7z\x0c\x00\x18{TZ=\x82\xab\x97j\x18\xf5\xc6LF \xf6h\x9f\xf56\n\x97=\xdc\xa4\xf7\xc6\xcap\xa9\x1e\x05F\x8f\xa6m\x0f\xe8\xb8\xb0Ab{\xfaC\xc0\xd3\xa13ra5)\xb7\x84\xf0\x05J\xbe@\xc9[\x14wA$]X7E/2\x1c\rl\xad\x1f2\xdd\x96\x8b}[\x8e\xd5\xb6\xd8w\x0b\xa6n\x7f\xf2\xbe\xba:\xcbE\x11\xd1G,!\xfe\x97=]p\'\xec\xa2\xa3\xe2\x16%m\x856\t\xff\xd9\nmz\x17\x91\x8b\x9c[\xda\x8d[\x94\xbf\xc5$\x17\t\xf3\x02\xf7[\x92\xc0\x16\x1e\xb8\x05S\xb6|c\xbe\xa5\'\xba\xe5\x90xK\x83uK\xf9\xb7\xa5\xed\xb5\xe5\xde\xfeVPI\x9aV\xdbX]hK\xf1\xb1\xed)\xae\xb5\x0e\xba\x9c\x16m/\xcf\xeaA\xb6V\xaa\x93{\x0b\xed[\xb4\x17Zd\x94\x16I\xb9ES\xb9\x05]\xf5\x08\xe3\x960\xedc\xef\xdbx\x1c\xc3\xb4\xba\x8a\t-\xb1\x91\x90\xf9\x96\x80\x86\xd4\x0b-\x81\x12\xa9\x17<q*\xb9l\xdd\x82t{\xe2T\xc2*[\xfc\xb3\x82\x16\xa7\x04-N\xc8Z\x94\x19\xad\no\xa3\xa0hq\x87\xbf\x05qm\t\xf4\xc9)\x96WPP\xf6\xf2\xac\xc1\xfa\x19q\xe2q\x19\xc3\x13\x0f\x15\xa6\xe3Uto\x1e\xb7\r<\xaa\x1e\x0f\x84\xf7X\xba\xc7\xb1c\xcb*\xde\xbc\xa6\xc6\xa2\x17\xb1`\xce\x19<\xa0\xd8\xa3\xc0\xf1:<}\xd2\xdd{\x94H\xde3O_P\x8f\xa3\x9e\xdf"j\xbd\xbeb\xa3\x07/\xf5\x06\n}\xde\x08\x91\xa3\x05\x0f\x14\xf4\xe8cyP\x97\x16\xf7\xe8<\xd0\xd5\xe3h\xc1#v<J\x19\x8f\xa3c\x8f\x98\xf4V,\x92\xf3\x04\x8f\x00\xf7 f\x1e\x9f\xe3y\xf4R=>\xfc\x1c1\xd6\xa1\x976\x82\xef\x8e\xacf$k\x18\x81\x0b\x0e\xa1\xec\xf0\xbd\xbeC#\xd9\xa1\xbd\xecp\x99\xd2Ag\x0e\xd9\xcb\xa1m=\x02\xdd\x1c(\xdc\x88\xb3\x9d\xd1P\xb53"\xd3\x8d\xe8D8\xb0\x15\x87\x96\xc2\x88;\x98\x0e-n\xc7R\t\xc7\xed#\x8c\xe5\xf0\xa5\xd1\x88\xa5\x8f\xc6\xea\x04\x0e\x07\xd5\x0e\x9f\x0c9\x1cn8|t\xe4p\x10\xe2p<\xe2\xf0\xb9\xaf\xc3\xd7\xc1\x0e\xdf\t9|S\xe4p\xce\xe1\xf0\xfd\x91\xc3\x99\x88\xc3\xb7J\x0e\xe7\'\x0e\xdf\t9\x9c]8|S\xe4p\xce\xe1p\xfa\xe1p&\xe2pR\xe2\xf0\xad\x92\xf3\xc2+\x9e\x99\x8c\xd3\x8f\x11\xe1\xe4H>\x94v\x80c\x14+\x1c>\xffv\xfe\xf5!\x1a\'ct\xb2\x7f\x8eO\xa5\xdf\xe7\xc8\x89\xb7\x90=\'\x8b\xc8\xb5\xbf\x11\xd5\x8fC\xfev\xa4B\x95km\x0eu\xab\xc3\xb7\xec\x8e\x94\xbbR\x04\x8f(\x84\x1c)w\x856;R\x04Ki<\x82\xaa9R\xcd~\x11\x91\nc\x04\x81\x1bY\xe9\xe7\x1d\xa2\xf5N\xbd\xf2N&z\xc7\xbb\xde\xb9d\xf8\x0e\x1f\x7f\x87\xa5\xbf\x13#\xef\xef\x1a\xb2\xef\x94`74\x9b\x1cB\xf6f\xa0;z\x87\xd3\xbc\xbb\xbc\xcd\xda\xdcZ\r\xf7\x0ef\xbe\x83\x99m\x0e|\x1c\xf0\xea\x86\n\xff\x06]\xdf\xd0#\xb8\xa1\xefyC\x8f\xe0\x86/\xacnh\x9d\xde\xd0P\xbd\xa1\xf7pC+\xe4\x86\xf5>nu\x17\x0eHZ\x12\xbf\x17\xe4/\xd1\xe5/\xd1\xfb/q\x03\xa9D7\xbeTR\xff,q\xd7\xa8D]R\xa23X\xe2\xba\x7f\tU\x97\xb0E\x89{\x0f%\x0c[\xe2\xf3\x84\x12Ek\x89\xa3\xe6\x92u ^\x82\xaf\x96\xc4\x02R\x14\x948\xed)\xb9\xcc\xc6\x8d\xbb.\xed\xc9.]\xcd\xae,X\x9a\x80]z\x16]v\xdf\xa5\x90\xea\xc2R\xba\xa2\xbfS\xce\xee\xd28\xee\xe2\xa0].\x83t\xed\xcfA\xce!K)\xd0|N\xa4u\t\x99\xae\xab\xf6\xe8\xe2\xa2]\x8b/t\xf5\x03a\xd3\xa5L\xeeBZ\xba\x14\x02c\x9e\xce\xa8|g\xe4\x92\x19\xb7\x07f\xe4\x92\x19]\x8bY_w:\xa3\xee\x98Q\x1f\xcd\xb8:2\x9b1\xc3\\\x83c\xcd\xe6f\x84\xf8\x0cE\xccH\xc53\x92\xf9\x0c\x7f\x9e\xe1V3R\xf1\x8c+\xd93:\xa63\x90\xe1\x9c/\xd8g\x00\x91\x99Q\xa2\xce0\xc1\x8c\xae\xc7\x8c\x18\x9f\x11_3\xac1\x03Zg\xd6\xe6P\xfb\x0c\x18\x9ea\x81\x07&{`\xb2\x07y\xb1$\x93\x87\x07\x9erq\xf2\xe1Zq\xfa\xe1F\x01\xf7\x81\xcd=\\\xf1\x14\xecx\x00Q\x1e\x04;$\x83<\x08\xa2H/\xb2\xea|\xc4\xb8\xa9\xe2GUb\xaaj9]\x95\x05W\xd9Q\xf5\xa4V\x89\xaaj\xacJ\xa9R\xefT\xb1x\x15\x86X%\xca\xab\x90\x8e*uK\xd5\xd7x\xaf\x12\xc3\xd5\x9a\x06n\x95\xb8\xac\x86\x8aUU\xae\xe5U\xb9\xb1Y\x85\x13\x9f\x91\xc4\xcf:\xfa\xe2\xb3\xa6\xae\xec\x0c\x1ap\x161\x00\xd2q\xc6\xbf$;\xcb\xeb\x80\xefv\xad~\x86{\x9cQ\r\x9f\xd9C.\xf1\x95\xdfh\xb6\x85\xf8\x9b\xff\xfe\xd2\xa4Q\xd0\xdc \xc2T\x9b\x07u\xdd&`\xd4\x14#\xc8\x19@\x13\xf6\xd9\x9c\xa8\xb75Sf\x00\x80\x9b\xdc\x82lF\xaa\xcd\xa6hH0\xbe\xd9A$\xa34\xf9\xf8\xb6\xd9U\xfcmr\xa2\xd3\xa4\xbejr7\xb2)\x8a\x95z\xb0I\x1ai\xd2\x15kr\x81\xac\xe9\xf06"\xa9\x89\xce\x9a\x94LM\xeb\xf8\xac\xcf\xc7\xab\xfd\x89j\xb5\xcfU\xa8>t\xa4\x0fI\xe9S\x15\xf4\xa9\xc9\xfb\x16HR\xe6\xf4\xb9\x98\xd1\x07\x7f\xfa`U\x1f\x04\xeb\x93\x9c\xfb\xd8\xb0\xbfa26\xd7\'\xab\xf5\xd9g\x1f|\xeaS\x9c\xf7\t\xcb>\xf0\xd3\xc7\xd1\xfaV\x8b\xe0\x8d\x1d\xbd\xd1s~#X\xdf\xf8\x94\xfc\x8d\xb5\xbf\xb1\xe07\xdd\xa7y\xcb\x18\xfd\x19k\xcfc\xf0<\xdfB\xe5\xa9\xb8\xf3T\xc6\xf9@a$O\xb8\xe7\xdb\xcc\x00\x8d\xc9\x13\xf9y\x02;O\xea\xcd\xd3\xe7\xcb\xe3\xd7y6\x94\xe7\x7ft\xe5\xe9\xd2\xe5\xe9\xe0\xe6\xb1\xe1F\x9b&&\x0fH\xe692\xcbc\x97\xbc\x85\x97yL\xd0fD\x1b\xf5\xb4\x15}3#,\xd7\xde\xe8z\\\x98q\x9b\xfbDm\xc9\xab\xc2\xfd\xda3\x1d\xdb\x06D7\xd6\xcf\xba\n\xa2m)S\xe4\x18\xb6M7\xb7\xcd1M\x9bo\xdf\xda(\xb8\r\x18\xb4\xeb\x1a\xa9m1\x9c\xb0\xc7\xb6\x18NZ\x1am\xba\x1bmxb\x9b\xeb\x9b\xed\xa2\x86r\xfb\x87"@\xdbS#\xb7i\xcc\xb4\xf3\x1a\xcac4\xf9\x89\x1c\xfd\xc9\xba\xaf4\xe6\x9e\xd3\'\x98\xd6\'2\xf3\'\xeb\xbf6|\x02\x9c\xc7\xf0\xe81\x86\x19c\xae\xb15\x96W\x8f9\x14\x19C%>\xd9\xf0>\xb6\x0fY\x80\xe41~5\x06\xd4\xc7\xc0\xc4\x98\x92b\x0cL\x8c\xe1Gc\xf8\xd1\x98o#\xc7\xf4\xa5\xc7\xb0\xea1\x1cm\x0c]\x1ds\x9bjLwaL\x95:\x86\xad\x8f\xb9\xc60\x16\xca(g\xdd\xe3\x01\x1b\x02\r7P\xc6[J\xa0[\xa11\xc2<n\xa1&\xb7P\x93[\xbe\xbc\xbd\xcd\xa99n\xf9\xc7\x11\xb7\x14Q\xb7\xfc\x93\x89[\x8a\xa8[Lw\xcbY\xee\x85e\xf2[<~\x04t\x8e\xfeZ\xf4\xff\xfe\x1f\xfa\xddI\x97'))
global t
t=' '
def f(k):
 global t
 r=a[t+k]if t+k in a else'e';t=k
 return r

1
빠른 설명 : zlib.decompress('...')평가 {'G?':' ', 'G;':' ','G"':' ',.......}, 그리고 a이 문자 1 개 문자로 매핑하는 사전이다. Steadybox의 의 기본적으로 2 자 변형입니다 .
user202729

1
내가 볼 수 있듯이 리터럴은 17780 바이트입니다. 압축 해제 된 컨텐츠에서 공백을 제거하여 12619 바이트를 절약하여 11619 자로 줄이십시오. (정확하게 계산 된 경우) 또한 ... 16 진수 이스케이프 코드를 실제 원시 문자로 변환하면 더 많은 바이트를 절약 할 수 있습니다.
user202729

원시 바이트 인 경우 여기에 어떻게 게시합니까?
Skyler

1
xxd, hexdump, uuencode, 또는 유사한
피터 테일러

@ user202729 파이썬 코드는 실제 원시 NUL 바이트를 포함 할 수 없습니다.
mbomb007

4

하스켈, (1904 + 1621 + 208548 + 25646) * 2 + 371705 = 847143

{-# LANGUAGE FlexibleInstances, DeriveGeneric #-}

import Control.Arrow
import Control.Monad
import Control.Monad.Trans.State
import Data.List

import System.IO
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Char8 as BC8
import Data.Ord
import Data.Char
import Data.Monoid
import Data.Maybe (fromJust, catMaybes)
import Data.Function
import qualified Data.Map as Map

import Codec.Compression.Lzma

import Data.Flat

import GHC.Word

maxWordLen :: Integral n => n
maxWordLen = 20

wordSeqDictSize :: Integral n => n
wordSeqDictSize = 255

predict :: [Trie] -> Char -> State ([Either Char Int], String) Char
predict statDict c = do
   (nextChar:future, begunWord) <- get
   case nextChar of
     Left p -> do
       put (future, [])
       return p
     Right lw -> do
       let wpre = begunWord++[c]
       put (future, wpre)
       return $ trieLook (tail wpre) (case drop lw statDict of{(t:_)->t;_->Trie[]})

newtype Trie = Trie [(Char,Trie)] deriving (Show, Generic)
instance Flat Trie

trieLook :: String -> Trie -> Char
trieLook [] (Trie ((p,_):_)) = p
trieLook (c:cs) (Trie m)
 | Just t' <- lookup c m  = trieLook cs t'
trieLook _ _ = ' '

moby :: IO (String -> String)
moby = do
    approxWSeq <- BSL.unpack . decompress <$> BSL.readFile "wordsseq"
    Right fallbackTries <- unflat <$> BS.readFile "dicttries"
    seqWords <- read <$> readFile "seqwords"
    let rdict = Map.fromList $ zip [maxWordLen..wordSeqDictSize] seqWords
    return $ \orig ->
      let reconstructed = approxWSeq >>= \i
             -> if i<maxWordLen then let l = fromIntegral i+1
                                     in replicate l $ Right l
                                else Left <$> rdict Map.! i
      in (`evalState`(reconstructed, ""))
              $ mapM (predict fallbackTries) (' ':orig)

예:

Call me Ishmael. Some years ago--never mind how long precisely--having
 ap  me ,nhmael.  Hme ?ears |ce--never  usd how long .aacesely--|ubing
little or no money in my purse, and nothing particular to interest me on
little or no ?ivey in my ?efse, and ,uwhing .hrticular to Bdaenest me on
shore, I thought I would sail about a little and see the watery part of
?neae, I thought I would  cfl about a little and see the |rkers part of
the world. It is a way I have of driving off the spleen and regulating
the world. It is a way I have of ,uiving off the |kli   and .ia       
the circulation. Whenever I find myself growing grim about the mouth;
the Ca         . B        I  rtd |yself ,haoing  eom about the ?ivlh;
whenever it is a damp, drizzly November in my soul; whenever I find
Baieever it is a  'mp, ,uiv    Bar      in my  cfl; Baieever I  rtd

사전 계산 된 세 개의 보조 파일을 사용합니다.

  • seqwords 236 개의 가장 일반적인 단어가 포함되어 있습니다.
  • wordsseq 이 단어의 LZMA 압축 속편과 길이가 가장 일반적인 236 개가 아닌 모든 단어에 대해 포함됩니다.
  • dicttries각 단어 길이에 대해 나머지 단어가 모두 포함 된 의사 결정 트리를 포함합니다. 이러한 시도에서 항목이 선택됩니다.

이런 식으로, 우리는 다른 모든 손실 방식보다 훨씬 낮은 오류율을 달성합니다. 불행히도 wordsseq파일은 여전히 ​​경쟁하기에 너무 큽니다.

다음은 파일을 작성하고 분석을 수행하는 완성 된 버전입니다.

depunct :: String -> [String]
depunct (p:l) = (p:take lm1 wordr) : depunct (drop lm1 wordr ++ srcr)
 where lm1 = maxWordLen-1
       (wordr, srcr) = (`span`l) $ if isAlpha p
                 then \c -> isLetter c || c=='\''
                 else not . isAlpha
depunct []=[]

mhead :: Monoid a => [a] -> a
mhead (h:_) = h
mhead [] = mempty

limit :: [Int] -> [Int]
limit = go 0
 where go z (n:l) | z<100 = n : go (z+n) l
       go _ l = take 1 l

packStr :: String -> Integer
packStr = go 0
 where go n [] = n
       go n (c:cs)
        | c>='a' && c<='z'  = go (28*n + fromIntegral
                                   (1 + fromEnum c - fromEnum 'a')) cs
        | otherwise         = go (28*n) cs


mkTrie :: [String] -> Trie
mkTrie [] = Trie []
mkTrie strs = Trie [ (c, mkTrie . filter (not . null) $ tail<$>l)
                   | l@((c:_):_) <- sortBy (comparing length)
                                  . groupBy ((==)`on`head)
                                  $ sortBy (comparing head) strs ]

mkTries :: [String] -> [Trie]
mkTries rsrc = [ mkTrie $ filter ((==l) . length) rsrc
               | l <- [0..maximum (length<$>rsrc)] ]

main :: IO ()
main = do
    orig <- readFile "whale.txt"
    let wordchopped = depunct orig
        dictRes
          = take 5000
          . map mhead
          . sortBy (comparing $ negate . length)
          . group . sort
          $ wordchopped
        dict = Map.fromList $ zip dictRes [maxWordLen..wordSeqDictSize]
        rdict = Map.fromList $ zip [maxWordLen..wordSeqDictSize] dictRes
        approxWSeq = [ case Map.lookup w dict of
                        Just i -> i
                        Nothing -> fromIntegral (length w - 1) :: Word8
                     | w <- wordchopped ]
        fallbackTries = mkTries . drop (wordSeqDictSize-maxWordLen) $ dictRes
        reconstructed = approxWSeq >>= \i
             -> if i<maxWordLen then let l = fromIntegral i+1
                                     in replicate l $ Right l
                                else Left <$> rdict Map.! i
        predicted = (`evalState`(reconstructed, ""))
              $ mapM (predict fallbackTries) (' ':orig)
        incorrects = length . filter id $ zipWith (/=) orig predicted
    putStrLn $ "longest word: "++show(maximum $ length<$>wordchopped)
    putStrLn $ show incorrects++" errors / "++show (length orig)++" chars"
    BSL.writeFile "wordsseq" . compress $ BSL.pack approxWSeq
    BS.writeFile "dicttries" $ flat fallbackTries
    writeFile "seqwords" . show $ take (256-maxWordLen) dictRes
    writeFile "whale-approx.txt" . unlines $ coLines orig predicted

coLines :: String -> String -> [String]
coLines [] _ = [[],[]]
coLines ('\n':l) (_:m) = []:[]:coLines l m
coLines l ('\n':m) = coLines l ('|':m)
coLines (c:l) (d:m) = case coLines l m of
   (lt:mt:r) -> (c:lt):(d:mt):r

3

C ++ (WIP), 1923 * 2 + 1017344 = 1021190

#include <map>
#include <random>
#include <string>
#include <type_traits>
#include <vector>

using namespace std;

constexpr minstd_rand::result_type seed = 10087702;

template<typename T>
class discrete_mapped_distribution {
private:
    discrete_distribution<size_t> distr;
    vector<T> values;

public:
    discrete_mapped_distribution() :
            distr(), values() {
    }
    template<typename I, typename = typename enable_if<is_arithmetic<I>::value,
            I>::type>
    discrete_mapped_distribution(map<T, I> distribution) :
            values() {
        vector<I> counts;

        values.reserve(distribution.size());
        counts.reserve(distribution.size());

        for (typename map<T, I>::const_reference count : distribution) {
            values.push_back(count.first);
            counts.push_back(count.second);
        }

        distr = discrete_distribution<size_t>(counts.cbegin(), counts.cend());
    }

    discrete_mapped_distribution(const discrete_mapped_distribution&) = default;
    discrete_mapped_distribution& operator=(const discrete_mapped_distribution&) = default;

    template<typename URNG>
    T operator()(URNG& urng) {
        return values.at(distr(urng));
    }
};

class generator2 {
private:
    static map<char, discrete_mapped_distribution<char>> letters;

    minstd_rand rng;

public:
    static void initDistribution(const string& text) {
        map<char, map<char, uint64_t>> letterDistribution;

        string::const_iterator it = text.cbegin();
        char oldLetter = *it++;

        for (; it != text.cend();) {
            ++(letterDistribution[oldLetter][*it]);
            oldLetter = *it++;
        }

        generator2::letters = map<char, discrete_mapped_distribution<char>>();

        for (map<char, map<char, uint64_t>>::const_reference letter : letterDistribution) {
            generator2::letters[letter.first] = discrete_mapped_distribution<char>(letter.second);
        }
    }

    generator2() :
            rng(seed) {
    }

    char getNextChar(char in) {
        return letters.at(in)(rng);
    }
};

map<char, discrete_mapped_distribution<char>> generator2::letters;

이 솔루션은 WIP이므로 풀리지 않습니다. 또한 실제 코드 크기가 점수에 거의 영향을 미치지 않는다는 점을 고려하면 마이크로 최적화를 시작하기 전에 먼저 답변을 게시한다고 생각했습니다.
(전체 코드는 여기에 있습니다 : https://github.com/BrainStone/MobyDickRNG- 전체 프로그램 및 시드 검색 포함)

이 솔루션은 RNG를 기반으로합니다. 먼저 텍스트를 분석합니다. 연속 된 두 문자의 발생 횟수를 계산하는 맵을 만듭니다. 그런 다음 배포 맵을 만듭니다. 이것은 정적으로 수행되므로 규칙을 준수해야합니다.

그런 다음 텍스트를 인쇄하는 동안 조회를하고 가능한 임의의 문자를 가져옵니다. 이것은 일반적으로 가장 일반적인 다음 문자를 출력하는 것보다 더 나쁜 결과를 생성하지만 더 나은 결과를 얻을 수있는 신의 씨앗이있을 수 있습니다. 시드가 하드 코딩 된 이유입니다. 나는 현재 최고의 씨앗을 찾고 있습니다. 더 나은 씨앗을 찾으면이 답변을 업데이트하겠습니다. 계속 게시하십시오!

누군가가 씨앗을 직접 검색하거나 다른 RNG를 사용하려는 경우 자유롭게 리포지를 포크하십시오.

점수 계산에 사용 된 방법 : https://github.com/BrainStone/MobyDickRNG/blob/master/src/search.cpp#L15

총점은 현재 최악이지만 공간을 출력하는 오류 수를 능가합니다. 더 많은 씨앗을 확인하면 점수가 떨어질 가능성이 높습니다.

변경 로그

  • 2018/01/24 : 게시 된 초기 답변.
    확인 된 씨앗 : 0-50000. 점수 : 2305 * 2 + 1017754 = 1022364
  • 2018/01/24 : 최소한의 골프를 했어요. 점수 계산 방법에 대한 링크를 추가했습니다.
    확인 된 씨앗 : 0-80000. 점수 : 1920 * 2 + 1017754 = 1021594 (-770)
  • 2018/02/02 : New seed (10087702) (제출을 고칠 시간이 없었습니다)
    확인 된 seed : 0-32000000. 점수 : 1923 * 2 + 1017344 = 1021190 (-404)

점수를 평가하는 테스트 하네스를 답에 포함시킬 수 있습니까?
Nathaniel

@Nathaniel 점수 코드를 직접 연결했습니다. 저장소와 함께 이것을 충분히 고려 하시겠습니까?
BrainStone

규칙을 검토 한 결과 일부 규칙을 위반 한 것으로 나타났습니다. 문제를 해결하면 자연스럽게 답변을 업데이트하겠습니다.
BrainStone

그런 다음 텍스트를 임의의 시드로 인코딩합니다. 난해한 프로그래밍 언어 Seed를 참조하십시오 . MT19937 프로그램을 리버스 엔지니어링 하고이 답변을 이길 수 있습니다 (가능한 경우).
user202729

좋은 생각이지만 좋은 점수를 얻는 데 도움이되지 않습니다. 어쨌든 +1.
user202729

3

루비, 1164418 (ouch)

나는 다른 답변을 확인하지 않고 내가 얼마나 잘 할 수 있는지보고 싶었습니다.
파일 분석을 통해 생성 된 리터럴이 포함되어 있기 때문에 이것이 허용되는지 확실하지 않지만 파일이 아닌 경우에도 다른 사람을 때릴 위험이 없습니다.

x="\"ect,htabsdd,in,\\nodniwlrfydbulkm;f?ckgwvi0,.*pr;\\\"uz17klI\\n-c'WSpA\\nTwqu8.77!-BeWO5.4.CoP\\n\\\"UHEFu2.?-9.jo6.NI3.MaLYDOGoOAR'QUECziJoxp(\\nYa:\\nVI);K\\nUS*IZEX\\n&\\n$\\n_y[S\""
f=->n{(x.include? n)? x[x.index(n)+1] : ' '}

내가 생성 한 방법 x

먼저 a.txt다음과 같이 생성 했습니다.

grep -o ".." whale2.txt | sort | uniq -c|sort -bn>a.txt

그런 다음 생성했습니다 a.csv:

cat a.txt | awk '{ print $1","$2 }'|sort -n|tac>a.csv

그런 x다음 다음 Ruby 스크립트 로 파싱했습니다 .

f={}
File.open('./a.csv').each{|l|x=l.partition(',')
f[x.last[0..1]]=x.first}
n={}
r={}
f.each{|k,v|if((r.include? k[0]and v>n[k[0]])or not r.include? k[0])and not k[1].nil?
r[k[0]]=k[1]
n[k[0]]=v
end}
s=''
r.each{|k,v|s+=k+v}
puts s.inspect

내가 득점 한 방법

w=File.read('whale2.txt')
x="ect,htabsdd,in,\nodniwlrfydbulkm;f?ckgwvi0,.*pr;\"uz17klI\n-c'WSpA\nTwqu8.77!-BeWO5.4.CoP\n\"UHEFu2.?-9.jo6.NI3.MaLYDOGoOAR'QUECziJoxp(\nYa:\nVI);K\nUS*IZEX\n&\n$\n_y[S"
f=->n{(x.include? n)? x[x.index(n)+1] : ' '}

score = 235
w.each_line{|l|v=l[0];l[0..-3].each_char{|n|v+=f[n]};v.split(//).each_with_index{|c,i|if l[i]==c
print c
else
print '_'
score+=1

end}}

puts "FINAL SCORE: #{score}"

나는 그것이 허용된다고 확신한다. 파일 분석 했다면 잘 했어! 프로그램이 그렇게하는 경우에만 유효하지 않습니다.
아웃 골퍼 에릭

@EriktheOutgolfer> _> (제목에 "(비경쟁)"을 자동으로 슬라이드)
NO_BOOT_DEVICE

왜? 이것이 유효하다면, 많이 이길 수는 없지만 경쟁하고 있습니다. 유효하지 않은 경우 (즉, 솔루션 이 파일에서 읽고 리터럴 만 포함하지 않은 경우) 삭제해야합니다.
Outgolfer 에릭

흠. 솔루션만이 아니라 프로그램이 파일을 분석했는지 여부를 의미한다고 생각했습니다.
NO_BOOT_DEVICE

1
루비를 읽을 수 없지만 이것이 유효하다고 생각합니다. 프로그램 안에 리터럴을 사용하는 것은 완전히 문제가되지 않습니다.
Nathaniel

2

파이썬 3 , (146 * 2 + 879757) 880049 바이트

def f(c):return"\n                     t \n 2  sS \n  -  08........       huaoRooe oioaohue thpih eEA \n   neo    enueee neue hteht e"[ord(c)-10]

온라인으로 사용해보십시오!

매우 간단한 빈도 표. 문자열의 각 위치는 현재 문자의 ASCII 코드 (-10에서 0x0a = '\ n', 파일에서 가장 낮은 문자)에 해당하며 각 색인의 문자는 가장 빈번한 다음 문자입니다. 주파수를 올바르게 계산했다고 가정하면…

user202729의 테스트 코드로 테스트


def f(c):return(" ">c)*c or"t ... e"[ord(c)-32]? 를 사용하여 일부 바이트를 저장할 수 있습니까 ?
Neil

0

[파이썬 3] (644449 * 2 + 0) 1288898 포인트

에서 완벽한 정확성 에만 644,449 바이트

import zlib,base64 as s
t=enumerate(zlib.decompress(s.b64decode(b'###')).decode());a=lambda c:next(t)[1]

전체 코드는 답변에 적합하지 않으므로 여기에 넣고 답변 텍스트에서 큰 이진 문자열 리터럴을 b '###'로 바꿨습니다.

"modified.py"는 생성 된 파일이고 "cheatsheet.txt"는 두 번째 문자에서 시작하는 whale2.txt 파일입니다.

import zlib, base64
with open("modified.py","w") as writer:
    writer.write("import zlib,base64 as s\nt=enumerate(zlib.decompress(s.b64decode(")
    with open("cheatsheet.txt","rb") as source:
        text = source.read()
        writer.write(str(base64.b64encode(zlib.compress(text,9))))
    writer.write(')).decode());a=lambda c:next(t)[1]')

"modified.py"의 끝에 다음을 추가하여 코드를 실행할 수 있습니다. "whale2.txt"는 "modified.py"와 동일한 디렉토리에 있어야하며 출력은 "out.txt"에 작성됩니다.

with open("out.txt","w") as writer:
    with open("whale2.txt","r") as reader:
        text = reader.read()
        for b in text:
            c = a(b)
            writer.write(c)

이 답변은 whale.txt 또는 whale2.txt에 직접 액세스하지 않습니다. 규칙에 명시 적으로 허용 된대로 기존 표준 압축 라이브러리를 사용합니다.


거기에 "\ r \ n"이있을 수 있습니다. 제가 계산할 때 Windows에서 제거 할 수 없었습니다.
Legorhin September

2
네, 그것은 전파 된 오타였습니다
Legorhin September
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.