Start parsing data into a GameTree
This commit is contained in:
parent
10f4743f82
commit
bc1f4395e5
|
@ -69,11 +69,11 @@
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
bytes::complete::{tag, take_until},
|
bytes::complete::{tag, take_until},
|
||||||
character::complete::{alpha1, anychar, multispace0},
|
character::complete::{alpha1, anychar, digit1, multispace0},
|
||||||
combinator::eof,
|
combinator::eof,
|
||||||
multi::{many0, many1, many_till},
|
multi::{many0, many1, many_till, separated_list1},
|
||||||
sequence::{delimited, terminated},
|
sequence::{delimited, terminated},
|
||||||
IResult, Parser,
|
Finish, IResult, Parser,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -85,6 +85,12 @@ pub enum ParseError {
|
||||||
UnknownError,
|
UnknownError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<nom::error::Error<&str>> for ParseError {
|
||||||
|
fn from(_: nom::error::Error<&str>) -> Self {
|
||||||
|
Self::UnknownError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo: support ST root node
|
// todo: support ST root node
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GameTree {
|
pub struct GameTree {
|
||||||
|
@ -181,6 +187,37 @@ enum PropValue {
|
||||||
Stone,
|
Stone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_sgf(input: &str) -> Result<GameTree, ParseError> {
|
||||||
|
let (_, tree) = parse_tree(input).finish()?;
|
||||||
|
|
||||||
|
let file_format = match tree.sequence[0].find_prop("FF") {
|
||||||
|
Some(prop) => prop.values[0].parse::<i8>().unwrap(),
|
||||||
|
None => 4,
|
||||||
|
};
|
||||||
|
let app = tree.sequence[0]
|
||||||
|
.find_prop("AP")
|
||||||
|
.map(|prop| prop.values[0].clone());
|
||||||
|
let board_size = match tree.sequence[0].find_prop("SZ") {
|
||||||
|
Some(prop) => {
|
||||||
|
let (_, size) = parse_size(prop.values[0].as_str()).finish()?;
|
||||||
|
size
|
||||||
|
}
|
||||||
|
None => Size {
|
||||||
|
width: 19,
|
||||||
|
height: 19,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(GameTree {
|
||||||
|
file_format,
|
||||||
|
|
||||||
|
app,
|
||||||
|
game_type: GameType::Go,
|
||||||
|
board_size,
|
||||||
|
text: input.to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
struct Tree {
|
struct Tree {
|
||||||
sequence: Vec<Node>,
|
sequence: Vec<Node>,
|
||||||
|
@ -219,7 +256,16 @@ impl ToString for Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
impl Node {
|
||||||
|
fn find_prop(&self, ident: &str) -> Option<Property> {
|
||||||
|
self.properties
|
||||||
|
.iter()
|
||||||
|
.find(|prop| prop.ident == ident)
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
struct Property {
|
struct Property {
|
||||||
ident: String,
|
ident: String,
|
||||||
values: Vec<String>,
|
values: Vec<String>,
|
||||||
|
@ -239,13 +285,6 @@ impl ToString for Property {
|
||||||
// note: must preserve unknown properties
|
// note: must preserve unknown properties
|
||||||
// note: must fix or preserve illegally formatted game-info properties
|
// note: must fix or preserve illegally formatted game-info properties
|
||||||
// note: must correct or delete illegally foramtted properties, but display a warning
|
// note: must correct or delete illegally foramtted properties, but display a warning
|
||||||
/*
|
|
||||||
pub fn parse_sgf(input: &str) -> Result<(GameTree, Vec<Warning>), ParseError> {
|
|
||||||
let (_, gameinfo) = parse_gametree(input).unwrap();
|
|
||||||
Ok((gameinfo, vec![]))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn parse_tree(input: &str) -> IResult<&str, Tree> {
|
fn parse_tree(input: &str) -> IResult<&str, Tree> {
|
||||||
println!("parse_tree: {}", input);
|
println!("parse_tree: {}", input);
|
||||||
let (input, _) = multispace0(input)?;
|
let (input, _) = multispace0(input)?;
|
||||||
|
@ -277,6 +316,7 @@ fn parse_node(input: &str) -> IResult<&str, Node> {
|
||||||
|
|
||||||
fn parse_property(input: &str) -> IResult<&str, Property> {
|
fn parse_property(input: &str) -> IResult<&str, Property> {
|
||||||
println!("parse_property: {}", input);
|
println!("parse_property: {}", input);
|
||||||
|
let (input, _) = multispace0(input)?;
|
||||||
let (input, ident) = alpha1(input)?;
|
let (input, ident) = alpha1(input)?;
|
||||||
let (input, values) = many1(delimited(tag("["), take_until("]"), tag("]")))(input)?;
|
let (input, values) = many1(delimited(tag("["), take_until("]"), tag("]")))(input)?;
|
||||||
|
|
||||||
|
@ -293,49 +333,30 @@ fn parse_property(input: &str) -> IResult<&str, Property> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
fn parse_size(input: &str) -> IResult<&str, Size> {
|
||||||
fn parse_gametree(input: &str) -> IResult<&str, GameTree> {
|
let (input, dimensions) = separated_list1(tag(":"), digit1)(input)?;
|
||||||
let (input, _) = tag("(;")(input)?;
|
let (width, height) = match dimensions.as_slice() {
|
||||||
let (input, properties) = many1(parse_property)(input)?;
|
[width] => (width.parse::<i32>().unwrap(), width.parse::<i32>().unwrap()),
|
||||||
let (input, _) = tag(")")(input)?;
|
[width, height] => (
|
||||||
println!("properties: {:?}", properties);
|
width.parse::<i32>().unwrap(),
|
||||||
Ok((input, unimplemented!()))
|
height.parse::<i32>().unwrap(),
|
||||||
}
|
),
|
||||||
|
_ => (19, 19),
|
||||||
*/
|
};
|
||||||
|
Ok((input, Size { width, height }))
|
||||||
pub fn add(left: usize, right: usize) -> usize {
|
|
||||||
left + right
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const EXAMPLE_1: &'static str = "(;FF[4]C[root](;C[a];C[b](;C[c])
|
const EXAMPLE: &'static str = "(;FF[4]C[root](;C[a];C[b](;C[c])
|
||||||
(;C[d];C[e]))
|
(;C[d];C[e]))
|
||||||
(;C[f](;C[g];C[h];C[i])
|
(;C[f](;C[g];C[h];C[i])
|
||||||
(;C[j])))";
|
(;C[j])))";
|
||||||
|
|
||||||
const EXAMPLE_2: &'static str = "(;FF[4]GM[1]SZ[19]AP[SGFC:1.13b]
|
|
||||||
|
|
||||||
PB[troy]BR[12k*]
|
|
||||||
PW[john]WR[11k*]
|
|
||||||
KM[0.5]RE[W+12.5]
|
|
||||||
DT[1998-06-15]
|
|
||||||
TM[600]
|
|
||||||
|
|
||||||
;B[pd];W[dp];B[pq];W[dd];B[qk];W[jd];B[fq];W[dj];B[jp];W[jj]
|
|
||||||
;B[cn]LB[dn:A][po:B]C[dada: other ideas are 'A' (d6) or 'B' (q5)]
|
|
||||||
;W[eo](;B[dl]C[dada: hm - looks troublesome.
|
|
||||||
Usually B plays the 3,3 invasion - see variation];W[qo];B[qp]
|
|
||||||
...
|
|
||||||
;W[sr];B[sk];W[sg];B[pa];W[gc];B[pi];W[ph];B[de];W[ed];B[kn]
|
|
||||||
;W[dh];B[eh];W[se];B[sd];W[af];B[ie];W[id];B[hf];W[hd];B[if]
|
|
||||||
;W[fp];B[gq];W[qj];B[sj];W[rh];B[sn];W[so];B[sm];W[ep];B[mn])
|
|
||||||
...
|
|
||||||
(;W[dq]N[wrong direction];B[qo];W[qp]))";
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_can_parse_properties() {
|
fn it_can_parse_properties() {
|
||||||
let (_, prop) = parse_property("C[a]").unwrap();
|
let (_, prop) = parse_property("C[a]").unwrap();
|
||||||
|
@ -479,7 +500,7 @@ Usually B plays the 3,3 invasion - see variation];W[qo];B[qp]
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_can_parse_example_1() {
|
fn it_can_parse_example_1() {
|
||||||
let (_, ex_tree) = parse_tree(EXAMPLE_1).unwrap();
|
let (_, ex_tree) = parse_tree(EXAMPLE).unwrap();
|
||||||
assert_eq!(ex_tree.sequence.len(), 1);
|
assert_eq!(ex_tree.sequence.len(), 1);
|
||||||
|
|
||||||
assert_eq!(ex_tree.sequence[0].properties.len(), 2);
|
assert_eq!(ex_tree.sequence[0].properties.len(), 2);
|
||||||
|
@ -515,7 +536,7 @@ Usually B plays the 3,3 invasion - see variation];W[qo];B[qp]
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_can_regenerate_the_tree() {
|
fn it_can_regenerate_the_tree() {
|
||||||
let (_, tree1) = parse_tree(EXAMPLE_1).unwrap();
|
let (_, tree1) = parse_tree(EXAMPLE).unwrap();
|
||||||
println!("{}", tree1.to_string());
|
println!("{}", tree1.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tree1.to_string(),
|
tree1.to_string(),
|
||||||
|
@ -525,41 +546,44 @@ Usually B plays the 3,3 invasion - see variation];W[qo];B[qp]
|
||||||
assert_eq!(tree1, tree2);
|
assert_eq!(tree1, tree2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
fn with_text(text: &str, f: impl FnOnce(GameTree)) {
|
||||||
fn with_examples(f: impl FnOnce(GameTree, GameTree)) {
|
f(parse_sgf(text).unwrap());
|
||||||
let (example_1, _) = parse_sgf(EXAMPLE_1).unwrap();
|
}
|
||||||
let (example_2, _) = parse_sgf(EXAMPLE_2).unwrap();
|
|
||||||
|
|
||||||
f(example_1, example_2);
|
fn with_file(path: &std::path::Path, f: impl FnOnce(GameTree)) {
|
||||||
|
let mut file = File::open(path).unwrap();
|
||||||
|
let mut text = String::new();
|
||||||
|
let _ = file.read_to_string(&mut text);
|
||||||
|
with_text(&text, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_parses_game_root() {
|
fn it_parses_game_root() {
|
||||||
with_examples(|ex_1, ex_2| {
|
with_text(EXAMPLE, |tree| {
|
||||||
assert_eq!(ex_1.file_format, 4);
|
assert_eq!(tree.file_format, 4);
|
||||||
assert_eq!(ex_1.app, None);
|
assert_eq!(tree.app, None);
|
||||||
assert_eq!(ex_1.game_type, GameType::Go);
|
assert_eq!(tree.game_type, GameType::Go);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ex_1.board_size,
|
tree.board_size,
|
||||||
Size {
|
Size {
|
||||||
width: 19,
|
width: 19,
|
||||||
height: 19
|
height: 19
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(ex_1.text, EXAMPLE_1.to_owned());
|
assert_eq!(tree.text, EXAMPLE.to_owned());
|
||||||
|
});
|
||||||
|
|
||||||
assert_eq!(ex_2.file_format, 4);
|
with_file(std::path::Path::new("test_data/print1.sgf"), |tree| {
|
||||||
assert_eq!(ex_2.app, Some("SGFC:1.13b".to_owned()));
|
assert_eq!(tree.file_format, 4);
|
||||||
assert_eq!(ex_2.game_type, GameType::Go);
|
assert_eq!(tree.app, None);
|
||||||
|
assert_eq!(tree.game_type, GameType::Go);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ex_2.board_size,
|
tree.board_size,
|
||||||
Size {
|
Size {
|
||||||
width: 19,
|
width: 19,
|
||||||
height: 19
|
height: 19
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(ex_2.text, EXAMPLE_2.to_owned());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
(;FF[4]AP[Primiview:3.1]GM[1]SZ[19]GN[Gametree 1: properties]US[Arno Hollosi]
|
||||||
|
|
||||||
|
(;B[pd]N[Moves, comments, annotations]
|
||||||
|
C[Nodename set to: "Moves, comments, annotations"];W[dp]GW[1]
|
||||||
|
C[Marked as "Good for White"];B[pp]GB[2]
|
||||||
|
C[Marked as "Very good for Black"];W[dc]GW[2]
|
||||||
|
C[Marked as "Very good for White"];B[pj]DM[1]
|
||||||
|
C[Marked as "Even position"];W[ci]UC[1]
|
||||||
|
C[Marked as "Unclear position"];B[jd]TE[1]
|
||||||
|
C[Marked as "Tesuji" or "Good move"];W[jp]BM[2]
|
||||||
|
C[Marked as "Very bad move"];B[gd]DO[]
|
||||||
|
C[Marked as "Doubtful move"];W[de]IT[]
|
||||||
|
C[Marked as "Interesting move"];B[jj];
|
||||||
|
C[White "Pass" move]W[];
|
||||||
|
C[Black "Pass" move]B[tt])
|
||||||
|
|
||||||
|
(;AB[dd][de][df][dg][do:gq]
|
||||||
|
AW[jd][je][jf][jg][kn:lq][pn:pq]
|
||||||
|
N[Setup]C[Black & white stones at the top are added as single stones.
|
||||||
|
|
||||||
|
Black & white stones at the bottom are added using compressed point lists.]
|
||||||
|
;AE[ep][fp][kn][lo][lq][pn:pq]
|
||||||
|
C[AddEmpty
|
||||||
|
|
||||||
|
Black stones & stones of left white group are erased in FF[3\] way.
|
||||||
|
|
||||||
|
White stones at bottom right were erased using compressed point list.]
|
||||||
|
;AB[pd]AW[pp]PL[B]C[Added two stones.
|
||||||
|
|
||||||
|
Node marked with "Black to play".];PL[W]
|
||||||
|
C[Node marked with "White to play"])
|
||||||
|
|
||||||
|
(;AB[dd][de][df][dg][dh][di][dj][nj][ni][nh][nf][ne][nd][ij][ii][ih][hq]
|
||||||
|
[gq][fq][eq][dr][ds][dq][dp][cp][bp][ap][iq][ir][is][bo][bn][an][ms][mr]
|
||||||
|
AW[pd][pe][pf][pg][ph][pi][pj][fd][fe][ff][fh][fi][fj][kh][ki][kj][os][or]
|
||||||
|
[oq][op][pp][qp][rp][sp][ro][rn][sn][nq][mq][lq][kq][kr][ks][fs][gs][gr]
|
||||||
|
[er]N[Markup]C[Position set up without compressed point lists.]
|
||||||
|
|
||||||
|
;TR[dd][de][df][ed][ee][ef][fd:ff]
|
||||||
|
MA[dh][di][dj][ej][ei][eh][fh:fj]
|
||||||
|
CR[nd][ne][nf][od][oe][of][pd:pf]
|
||||||
|
SQ[nh][ni][nj][oh][oi][oj][ph:pj]
|
||||||
|
SL[ih][ii][ij][jj][ji][jh][kh:kj]
|
||||||
|
TW[pq:ss][so][lr:ns]
|
||||||
|
TB[aq:cs][er:hs][ao]
|
||||||
|
C[Markup at top partially using compressed point lists (for markup on white stones); listed clockwise, starting at upper left:
|
||||||
|
- TR (triangle)
|
||||||
|
- CR (circle)
|
||||||
|
- SQ (square)
|
||||||
|
- SL (selected points)
|
||||||
|
- MA ('X')
|
||||||
|
|
||||||
|
Markup at bottom: black & white territory (using compressed point lists)]
|
||||||
|
;LB[dc:1][fc:2][nc:3][pc:4][dj:a][fj:b][nj:c]
|
||||||
|
[pj:d][gs:ABCDEFGH][gr:ABCDEFG][gq:ABCDEF][gp:ABCDE][go:ABCD][gn:ABC][gm:AB]
|
||||||
|
[mm:12][mn:123][mo:1234][mp:12345][mq:123456][mr:1234567][ms:12345678]
|
||||||
|
C[Label (LB property)
|
||||||
|
|
||||||
|
Top: 8 single char labels (1-4, a-d)
|
||||||
|
|
||||||
|
Bottom: Labels up to 8 char length.]
|
||||||
|
|
||||||
|
;DD[kq:os][dq:hs]
|
||||||
|
AR[aa:sc][sa:ac][aa:sa][aa:ac][cd:cj]
|
||||||
|
[gd:md][fh:ij][kj:nh]
|
||||||
|
LN[pj:pd][nf:ff][ih:fj][kh:nj]
|
||||||
|
C[Arrows, lines and dimmed points.])
|
||||||
|
|
||||||
|
(;B[qd]N[Style & text type]
|
||||||
|
C[There are hard linebreaks & soft linebreaks.
|
||||||
|
Soft linebreaks are linebreaks preceeded by '\\' like this one >o\
|
||||||
|
k<. Hard line breaks are all other linebreaks.
|
||||||
|
Soft linebreaks are converted to >nothing<, i.e. removed.
|
||||||
|
|
||||||
|
Note that linebreaks are coded differently on different systems.
|
||||||
|
|
||||||
|
Examples (>ok< shouldn't be split):
|
||||||
|
|
||||||
|
linebreak 1 "\\n": >o\
|
||||||
|
k<
|
||||||
|
linebreak 2 "\\n\\r": >o\
|
||||||
|
k<
|
||||||
|
linebreak 3 "\\r\\n": >o\
|
||||||
|
k<
|
||||||
|
linebreak 4 "\\r": >o\
k<]
|
||||||
|
|
||||||
|
(;W[dd]N[W d16]C[Variation C is better.](;B[pp]N[B q4])
|
||||||
|
(;B[dp]N[B d4])
|
||||||
|
(;B[pq]N[B q3])
|
||||||
|
(;B[oq]N[B p3])
|
||||||
|
)
|
||||||
|
(;W[dp]N[W d4])
|
||||||
|
(;W[pp]N[W q4])
|
||||||
|
(;W[cc]N[W c17])
|
||||||
|
(;W[cq]N[W c3])
|
||||||
|
(;W[qq]N[W r3])
|
||||||
|
)
|
||||||
|
|
||||||
|
(;B[qr]N[Time limits, captures & move numbers]
|
||||||
|
BL[120.0]C[Black time left: 120 sec];W[rr]
|
||||||
|
WL[300]C[White time left: 300 sec];B[rq]
|
||||||
|
BL[105.6]OB[10]C[Black time left: 105.6 sec
|
||||||
|
Black stones left (in this byo-yomi period): 10];W[qq]
|
||||||
|
WL[200]OW[2]C[White time left: 200 sec
|
||||||
|
White stones left: 2];B[sr]
|
||||||
|
BL[87.00]OB[9]C[Black time left: 87 sec
|
||||||
|
Black stones left: 9];W[qs]
|
||||||
|
WL[13.20]OW[1]C[White time left: 13.2 sec
|
||||||
|
White stones left: 1];B[rs]
|
||||||
|
C[One white stone at s2 captured];W[ps];B[pr];W[or]
|
||||||
|
MN[2]C[Set move number to 2];B[os]
|
||||||
|
C[Two white stones captured
|
||||||
|
(at q1 & r1)]
|
||||||
|
;MN[112]W[pq]C[Set move number to 112];B[sq];W[rp];B[ps]
|
||||||
|
;W[ns];B[ss];W[nr]
|
||||||
|
;B[rr];W[sp];B[qs]C[Suicide move
|
||||||
|
(all B stones get captured)])
|
||||||
|
)
|
||||||
|
|
||||||
|
(;FF[4]AP[Primiview:3.1]GM[1]SZ[19]C[Gametree 2: game-info
|
||||||
|
|
||||||
|
Game-info properties are usually stored in the root node.
|
||||||
|
If games are merged into a single game-tree, they are stored in the node\
|
||||||
|
where the game first becomes distinguishable from all other games in\
|
||||||
|
the tree.]
|
||||||
|
;B[pd]
|
||||||
|
(;PW[W. Hite]WR[6d]RO[2]RE[W+3.5]
|
||||||
|
PB[B. Lack]BR[5d]PC[London]EV[Go Congress]W[dp]
|
||||||
|
C[Game-info:
|
||||||
|
Black: B. Lack, 5d
|
||||||
|
White: W. Hite, 6d
|
||||||
|
Place: London
|
||||||
|
Event: Go Congress
|
||||||
|
Round: 2
|
||||||
|
Result: White wins by 3.5])
|
||||||
|
(;PW[T. Suji]WR[7d]RO[1]RE[W+Resign]
|
||||||
|
PB[B. Lack]BR[5d]PC[London]EV[Go Congress]W[cp]
|
||||||
|
C[Game-info:
|
||||||
|
Black: B. Lack, 5d
|
||||||
|
White: T. Suji, 7d
|
||||||
|
Place: London
|
||||||
|
Event: Go Congress
|
||||||
|
Round: 1
|
||||||
|
Result: White wins by resignation])
|
||||||
|
(;W[ep];B[pp]
|
||||||
|
(;PW[S. Abaki]WR[1d]RO[3]RE[B+63.5]
|
||||||
|
PB[B. Lack]BR[5d]PC[London]EV[Go Congress]W[ed]
|
||||||
|
C[Game-info:
|
||||||
|
Black: B. Lack, 5d
|
||||||
|
White: S. Abaki, 1d
|
||||||
|
Place: London
|
||||||
|
Event: Go Congress
|
||||||
|
Round: 3
|
||||||
|
Result: Balck wins by 63.5])
|
||||||
|
(;PW[A. Tari]WR[12k]KM[-59.5]RO[4]RE[B+R]
|
||||||
|
PB[B. Lack]BR[5d]PC[London]EV[Go Congress]W[cd]
|
||||||
|
C[Game-info:
|
||||||
|
Black: B. Lack, 5d
|
||||||
|
White: A. Tari, 12k
|
||||||
|
Place: London
|
||||||
|
Event: Go Congress
|
||||||
|
Round: 4
|
||||||
|
Komi: -59.5 points
|
||||||
|
Result: Black wins by resignation])
|
||||||
|
))
|
|
@ -0,0 +1,35 @@
|
||||||
|
(;FF[4]GM[1]SZ[19]FG[257:Figure 1]PM[1]
|
||||||
|
PB[Takemiya Masaki]BR[9 dan]PW[Cho Chikun]
|
||||||
|
WR[9 dan]RE[W+Resign]KM[5.5]TM[28800]DT[1996-10-18,19]
|
||||||
|
EV[21st Meijin]RO[2 (final)]SO[Go World #78]US[Arno Hollosi]
|
||||||
|
;B[pd];W[dp];B[pp];W[dd];B[pj];W[nc];B[oe];W[qc];B[pc];W[qd]
|
||||||
|
(;B[qf];W[rf];B[rg];W[re];B[qg];W[pb];B[ob];W[qb]
|
||||||
|
(;B[mp];W[fq];B[ci];W[cg];B[dl];W[cn];B[qo];W[ec];B[jp];W[jd]
|
||||||
|
;B[ei];W[eg];B[kk]LB[qq:a][dj:b][ck:c][qp:d]N[Figure 1]
|
||||||
|
|
||||||
|
;W[me]FG[257:Figure 2];B[kf];W[ke];B[lf];W[jf];B[jg]
|
||||||
|
(;W[mf];B[if];W[je];B[ig];W[mg];B[mj];W[mq];B[lq];W[nq]
|
||||||
|
(;B[lr];W[qq];B[pq];W[pr];B[rq];W[rr];B[rp];W[oq];B[mr];W[oo];B[mn]
|
||||||
|
(;W[nr];B[qp]LB[kd:a][kh:b]N[Figure 2]
|
||||||
|
|
||||||
|
;W[pk]FG[257:Figure 3];B[pm];W[oj];B[ok];W[qr];B[os];W[ol];B[nk];W[qj]
|
||||||
|
;B[pi];W[pl];B[qm];W[ns];B[sr];W[om];B[op];W[qi];B[oi]
|
||||||
|
(;W[rl];B[qh];W[rm];B[rn];W[ri];B[ql];W[qk];B[sm];W[sk];B[sh];W[og]
|
||||||
|
;B[oh];W[np];B[no];W[mm];B[nn];W[lp];B[kp];W[lo];B[ln];W[ko];B[mo]
|
||||||
|
;W[jo];B[km]N[Figure 3])
|
||||||
|
|
||||||
|
(;W[ql]VW[ja:ss]FG[257:Dia. 6]MN[1];B[rm];W[ph];B[oh];W[pg];B[og];W[pf]
|
||||||
|
;B[qh];W[qe];B[sh];W[of];B[sj]TR[oe][pd][pc][ob]LB[pe:a][sg:b][si:c]
|
||||||
|
N[Diagram 6]))
|
||||||
|
|
||||||
|
(;W[no]VW[jj:ss]FG[257:Dia. 5]MN[1];B[pn]N[Diagram 5]))
|
||||||
|
|
||||||
|
(;B[pr]FG[257:Dia. 4]MN[1];W[kq];B[lp];W[lr];B[jq];W[jr];B[kp];W[kr];B[ir]
|
||||||
|
;W[hr]LB[is:a][js:b][or:c]N[Diagram 4]))
|
||||||
|
|
||||||
|
(;W[if]FG[257:Dia. 3]MN[1];B[mf];W[ig];B[jh]LB[ki:a]N[Diagram 3]))
|
||||||
|
|
||||||
|
(;W[oc]VW[aa:sk]FG[257:Dia. 2]MN[1];B[md];W[mc];B[ld]N[Diagram 2]))
|
||||||
|
|
||||||
|
(;B[qe]VW[aa:sj]FG[257:Dia. 1]MN[1];W[re];B[qf];W[rf];B[qg];W[pb];B[ob]
|
||||||
|
;W[qb]LB[rg:a]N[Diagram 1]))
|
|
@ -0,0 +1,50 @@
|
||||||
|
(;FF[4]GM[1]SZ[19]FG[257:Figure 1]PM[2]
|
||||||
|
PB[Cho Chikun]BR[9 dan]PW[Ryu Shikun]WR[9 dan]RE[W+2.5]KM[5.5]
|
||||||
|
DT[1996-08]EV[51st Honinbo]RO[5 (final)]SO[Go World #78]US[Arno Hollosi]
|
||||||
|
;B[qd];W[dd];B[fc];W[df];B[pp];W[dq];B[kc];W[cn];B[pj];W[jp];B[lq];W[oe]
|
||||||
|
;B[pf];W[ke];B[id];W[lc];B[lb];W[kb];B[jb];W[kd];B[ka];W[jc];B[ic];W[kb]
|
||||||
|
;B[mc];W[qc]N[Figure 1]
|
||||||
|
|
||||||
|
;B[pd]FG[257:Figure 2];W[pc];B[od];W[oc];B[kc];W[nd];B[nc];W[kb];B[rd];W[pe]
|
||||||
|
(;B[rf];W[md];B[kc];W[qe];B[re];W[kb];B[mb];W[qf];B[qg];W[pg];B[qh];W[kc]
|
||||||
|
;B[hb];W[nf];B[ch];W[cj];B[eh];W[ob]
|
||||||
|
(;B[cc];W[dc];B[db];W[bf];B[bb]
|
||||||
|
;W[bh]LB[of:a][mf:b][rc:c][di:d][ja:e]N[Figure 2]
|
||||||
|
|
||||||
|
;B[qp]FG[257:Figure 3];W[lo];B[ej];W[oq]
|
||||||
|
(;B[np];W[mq];B[mp];W[lp]
|
||||||
|
(;B[kq];W[nq];B[op];W[jq];B[mr];W[nr];B[lr];W[qr];B[jr];W[ir];B[hr];W[iq]
|
||||||
|
;B[is];W[ks];B[js];W[gq];B[gr];W[fq];B[pq];W[pr];B[ns];W[or];B[rq];W[hq]
|
||||||
|
;B[rr];W[cl];B[cg];W[bg];B[og];W[ng]
|
||||||
|
(;B[ci];W[bi];B[dj];W[dk];B[mm];W[gk];B[gi];W[mn];B[nm];W[kl];B[nh];W[mh]
|
||||||
|
;B[mi];W[li];B[lh];W[mg];B[ek];W[el];B[ik]LB[kr:a]N[Figure 3]
|
||||||
|
|
||||||
|
;W[ki]FG[257:Figure 4];B[fl];W[fk];B[gl];W[hk];B[hl];W[hj];B[jl];W[kk];B[km]
|
||||||
|
;W[lm];B[ll];W[jm];B[jj];W[ji];B[kj];W[lj];B[ij];W[hi];B[em];W[dl];B[ii]
|
||||||
|
;W[hh];B[ih];W[hg];B[ln];W[kn];B[lm];W[im];B[il];W[fg];B[lk];W[ni];B[ef]
|
||||||
|
;W[eg];B[dg];W[ff];B[oh];W[of];B[oj];W[ph];B[oi];W[mj];B[ee];W[fe];B[de]
|
||||||
|
;W[ed];B[ce];W[cf];B[rb];W[rc];B[sc];W[qb];B[sb];W[la];B[ma];W[na];B[ja]
|
||||||
|
;W[nb];B[la];W[pa];B[be];W[fd];B[bj];W[ck];B[ec];W[hs];B[gs];W[fr];B[os]
|
||||||
|
;W[ps];B[ms];W[nk];B[ok];W[kp];B[fo];W[fs];B[qq];W[hs];B[do];W[co];B[ig]
|
||||||
|
;W[gc];B[gb];W[jf];B[di];W[fi];B[hf];W[gf];B[af];W[mo];B[he];W[kr];B[qs]
|
||||||
|
;W[no];B[oo];W[nn];B[on];W[nl];B[ol];W[gn];B[fn];W[in];B[nj];W[mk];B[jg]
|
||||||
|
;W[kg];B[mi];W[jh];B[ag];W[bk];B[ah];W[aj];B[fh];W[fj];B[gd];W[ra];B[dp]
|
||||||
|
;W[cp];B[go];W[gm];B[fm];W[sd];B[se];W[ho];B[hm];W[hn];B[ep];W[eq];B[cd]
|
||||||
|
;W[ei];B[dn];W[gp];B[pi];W[pf];B[dm];W[cm];B[je];W[jd];B[if];W[ie];B[ko]
|
||||||
|
;W[jo];B[je];W[kf];B[ni];W[dh];B[ge];W[ie];B[rg];W[je]N[Figure 4])
|
||||||
|
|
||||||
|
(;B[dk]FG[257:Dia. 6]MN[1];W[ck];B[gk]N[Diagram 6]))
|
||||||
|
|
||||||
|
(;B[nq]VW[ai:ss]FG[257:Dia. 5]MN[1];W[mr];B[nr];W[lr]TR[oq]N[Diagram 5]))
|
||||||
|
|
||||||
|
(;B[mp]VW[ai:ss]FG[257:Dia. 4]MN[1];W[op];B[oo];W[no];B[mo];W[on];B[po]
|
||||||
|
;W[mn];B[np];W[nn];B[or]N[Diagram 4]))
|
||||||
|
|
||||||
|
(;B[rc]VW[aa:sj]FG[257:Dia. 2]MN[1];W[rb];B[sb];W[la];B[ma];W[na];B[ja]
|
||||||
|
;W[pa]N[Diagram 2])
|
||||||
|
|
||||||
|
(;B[rb]VW[aa:sj]FG[257:Dia. 3]MN[1];W[rc];B[sc];W[qb];B[pa];W[sb];B[sa]
|
||||||
|
;W[sd];B[qa]N[Diagram 3]))
|
||||||
|
|
||||||
|
(;B[qf]VW[aa:sj]FG[257:Dia. 1]MN[1];W[mb];B[kc];W[qe];B[ne];W[kb];B[md]
|
||||||
|
;W[la];B[nb];W[eb]LB[ob:a][na:b][rc:c][sd:d]N[Diagram 1]))
|
Loading…
Reference in New Issue