File Coverage

blib/lib/WWW/Facebook/Go/SGF.pm
Criterion Covered Total %
statement 45 45 100.0
branch 8 8 100.0
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 60 60 100.0


line stmt bran cond sub pod time code
1             # $Id: SGF.pm,v 1.2 2009/02/27 19:54:29 drhyde Exp $
2              
3 1     1   530 use strict;
  1         2  
  1         31  
4 1     1   5 use warnings;
  1         2  
  1         44  
5              
6             package WWW::Facebook::Go::SGF;
7              
8 1     1   5 use vars qw($VERSION @ISA @EXPORT_OK);
  1         4  
  1         85  
9              
10             require Exporter;
11              
12 1     1   1985 use LWP::Simple;
  1         267312  
  1         10  
13              
14             @ISA = qw(Exporter);
15             @EXPORT_OK = qw(facebook2sgf);
16             $VERSION = '1.0';
17              
18             =head1 NAME
19              
20             WWW::Facebook::Go::SGF - convert a game of Go on Facebook into SGF.
21              
22             =head1 SYNOPSIS
23              
24             use WWW::Facebook::Go::SGF qw(facebook2sgf);
25            
26             my $sgf = facebook2sgf($game_id);
27              
28             =head1 DESCRIPTION
29              
30             A simple tool to extract a game record from the GoTheGame application
31             on Facebook and convert it to SGF so that you can then manipulate it
32             using other tools.
33              
34             =head1 FUNCTIONS
35              
36             =head2 facebook2sgf
37              
38             This can be exported if you wish. It takes a game ID as its only
39             parameter, and returns a scalar representation of an SGF recording
40             of the game.
41              
42             You can get game IDs by visiting L
43             and clicking the "View Full Profile" link.
44              
45             =cut
46              
47             sub facebook2sgf {
48 4     4 1 3454 my $gameid = shift();
49 4         19 my @moves = split(/[\n\r]+/, _download($gameid));
50              
51 4         5832 (my $size = (grep { /^var board_size = '(9|13|19)'/ } @moves)[0])
  1858         2979  
52             =~ s/^var board_size = '(9|13|19)'.*/$1/;
53              
54 4         20 my $handicap = (grep { /HANDICAP/ } @moves)[0];
  1858         3367  
55 4         10 my @handicapstones = ();
56 4 100       19 if($handicap) {
57 3         23 $handicap =~ s/.*HANDICAP','([\d_,]+)'.*/$1/;
58 3         17 @handicapstones = split(',', $handicap);
59             }
60              
61 615         1872 @moves = map {
62 1858 100       7459 /new goMove\((\d+),'([BW])','([^']+)'/;
63 615         1063 [$1, $2, _fixcoords($3)];
64 4         16 } grep { /^moves\[\d+\] = new goMove/ && $_ !~ /START|HANDICAP/ } @moves;
65 4         169 @moves = @moves[0 .. $#moves - 1]; # lop off last NEGOTIATE
66              
67 4 100       51 my $komi = 0.5 + (@handicapstones ? 0 : 6); # 0.5 or 6.5
68 4         75 my $board = q{(;GM[1]FF[4]AP[}.__PACKAGE__.
69             qq{]ST[1]SZ[$size]HA[}.
70             (1+$#handicapstones).
71             qq{]KM[$komi]PW[White player]PB[Black player]}.
72             "\n\n";
73 4 100       14 if(@handicapstones) {
74 3         8 $board .= ';AB';
75 3         8 foreach my $stone (map { _fixcoords($_) } @handicapstones) {
  16         28  
76 16         24 $board .= "[$stone]";
77             }
78 3         8 $board .= "\n";
79             }
80              
81 4         10 foreach(@moves) {
82 611         1046 $board .= ';'.$_->[1].'['.$_->[2].']';
83             }
84 4         10 $board .= "\n)\n";
85              
86 4         219 return $board;
87             }
88              
89             sub _fixcoords {
90 631     631   968 my $fbcoord = shift;
91 631         1908 $fbcoord =~ s/(\d+)/substr('abcdefghijklmnopqrs', $1, 1)/eg;
  1234         3182  
92 631         987 $fbcoord =~ y/_//d;
93 631         760 $fbcoord =~ s/PASS|NEGOTIATE//;
94 631         2852 $fbcoord;
95             }
96              
97             # private function, wraps around LWP::Simple::get so we can mock it in
98             # testing
99             sub _download {
100             my $url = 'http://facebook3.wx3.com/go/go_iframe_spectate.php?game_id='.shift();
101             my $content = get($url) || die("Couldn't fetch $url\n");
102             return $content;
103             }
104              
105             =head1 BUGS/WARNINGS/LIMITATIONS
106              
107             This has only been tested on completed games. I assume that both players
108             correctly identified all dead groups after passing and that play didn't
109             have to resume. Please report any bugs that you find using
110             L. Obviously you will need to include the game id
111             in your bug report.
112              
113             =head1 FEEDBACK
114              
115             I welcome feedback about my code, including constructive criticism
116             and bug reports. The best bug reports include files that I can add
117             to the test suite, which fail with the current code in CVS and will
118             pass once I've fixed the bug.
119              
120             Feature requests are far more likely to get implemented if you submit
121             a patch yourself.
122              
123             =head1 CVS
124              
125             L
126              
127             =head1 AUTHOR, COPYRIGHT and LICENCE
128              
129             Copyright 2009 David Cantrell EFE
130              
131             This software is free-as-in-speech software, and may be used,
132             distributed, and modified under the terms of either the GNU
133             General Public Licence version 2 or the Artistic Licence. It's
134             up to you which one you use. The full text of the licences can
135             be found in the files GPL2.txt and ARTISTIC.txt, respectively.
136              
137             =head1 CONSPIRACY
138              
139             This module is also free-as-in-mason software.
140              
141             =cut
142              
143             1;