9 require Tree::Binary::Search;
11 require Time::Piece::ISO;
16 my $opt_dict=$ENV{"HOME"}."/priv/japan-lang/jfe_1-9.csv";
17 my $opt_log=$opt_dict.".log";
19 $Getopt::Long::ignorecase=0;
20 $Getopt::Long::bundling=1;
22 "d|debug+"=>\$opt_debug,
23 "c|dict=s"=>\$opt_dict,
24 "l|log=s" =>\$opt_log,
34 for my $result (@{$r->{"result"}}) {
35 my $age=time()-$result->{"time"};
37 # $age: 0.. big importance
38 # $age: big..small importance
43 # 1/log(2+$age): big.. big importance
44 # 1/log(2+$age): 0..small importance
45 $sum+=1/log(2+$age)*($result->{"ok"}?+1:-1);
48 if ($T->exists($sum)) {
49 $arr=$T->select($sum)->{"arr"};
52 splice @$arr,int(rand(@$arr+1)),0,$r;
53 $T->insert($sum=>{"key"=>$sum,"arr"=>$arr});
54 print STDERR "; schedule=$sum" if $opt_debug;
59 return if $T->isEmpty();
60 my $min=$T->min()->{"key"};
61 my $arr=$T->select($min)->{"arr"};
64 $T->insert($min=>{"key"=>$min,"arr"=>$arr}) if @$arr;
65 print STDERR "min=$min\n" if $opt_debug;
73 return join " ",map(($r->{$_}||"-"),qw(
84 open LOG_APPEND,">>".$opt_log or die "append \"$opt_log\": $!";
85 print LOG_APPEND Time::Piece::ISO::localtime().POSIX::strftime("%z",localtime())." ok=$ok: ".identify($r)."\n";
86 close LOG_APPEND or die "close \"$opt_log\": $!";
88 push @{$r->{"result"}},{
97 $T=Tree::Binary::Search->new();
98 $T->useNumericComparison();
100 open DICT,$opt_dict or die "open \"$opt_dict\": $!";
113 next if $r->{"written"} eq "";
114 die "Excessive argument: $rest" if defined $rest;
115 while ($r->{"meaning"}=~s/\s*<([-\w]+)>\s*//) {
117 $r->{"meaning_keyword"}{$keyword}=1;
118 $keyword{$keyword}=1;
120 $r->{"meaning"}!~/[<>]/ or warn "Meaning constains invalid characters: ".$r->{"meaning"};
123 close DICT or die "close \"$opt_dict\": $!";
125 my %identify=map((identify($_)=>$_),@R);
128 if (!open LOG_READ,$opt_log) {
129 warn "open \"$opt_log\": $!";
133 # 2002-04-25T21:17:52+0900 ok=1: identify($r)
134 my($year, $month, $day, $hour, $minute,$second,$zonepm,$zonehour,$zoneminute,$ok,$identify)=
135 /^(\d{4})-(\d{1,2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([+-])(\d{2})(\d{2}) ok=(\d+): (.+)$/
136 or do { warn "Unrecognized line: $_\n"; next; };
139 my $localtime=POSIX::mktime($second,$minute,$hour,$day,$month,$year);
140 $localtime or do { warn "Unparsable time at line: $_\n"; next; };
141 my $gmtime=$localtime-($zonepm."1")*($zonehour*60+$zoneminute);
142 my $r=$identify{$identify}
143 or do { warn "Word not found from line: $_\n"; next; };
144 push @{$r->{"result"}},{
149 close LOG_READ or die "close \"$opt_log\": $!";
153 local $opt_debug=0 if $opt_debug<2;
154 print STDERR $r->{"phonetic"}."\t".$r->{"meaning"} if $opt_debug;
156 print STDERR "\n" if $opt_debug;
160 "phonetic"=>"meaning",
161 "meaning"=>"phonetic",
163 my @exam=keys(%exam);
168 # Do not change $exam_from if $r remained the same:
169 my $exam_from=$exam_from_last;
170 if (!$r_last || $r ne $r_last) {
171 $exam_from=$exam[int rand @exam];
173 my $exam_to =$exam{$exam_from};
174 print $r->{$exam_from}.": ";
177 my $want=$r->{$exam_to};
178 print "-------> $want\n";
179 (my $got_chk =lc $got )=~s/\s//g;
180 (my $want_chk=lc $want)=~s/\s//g;
181 $got_chk=~s/\bto\b//g;
182 $want_chk=~s/\bto\b//g;
183 $want_chk=~s/[(][^)]*[)]//g;
184 warn "Parenthesis ('(',')') not supported in the user input: $got\n" if $got=~/[()]/;
185 warn "Comma (',') not well supported in the user input: $got\n" if $got=~/,/;
187 $ok=1 if $got_chk eq $want_chk; # incl. commas
188 for (split /,/,$want_chk) {
189 $ok=1 if $got_chk eq $_;
192 if ($exam_to eq "meaning" && $got=~/\S/ && $want=~/\Q$got\E/) {
195 print STDERR "Is your answer correct? [y/n] ";
198 Term::ReadKey::ReadMode(0);
200 local $SIG{"__DIE__"}=\&restore;
201 Term::ReadKey::ReadMode(4);
202 $key=Term::ReadKey::ReadKey(0);
203 print STDERR "\n"; # no echo
205 $ok=1 if $key eq "y";
206 $ok=0 if $key eq "n";
207 } while (!defined $ok);
211 print STDERR "result: ".($ok ? "ok" : "WRONG");
215 $exam_from_last=$exam_from;