How did you learn web development?

In general, to write programs and learn programming languages, understanding EBNF is not strictly necessary, but it could be a helpful tool. In the vast majority of cases, people learn the syntax and structure of language through other means, such as by rules informally stated in other natural languages and/or even just through enough examples.

EBNF is a means to formally and precisely define syntax rules, which can be quite concise and remove ambiguities. It does so by specifying (production) rules on how valid examples of a language may be constructed. Since EBNF is itself a language, it can even be used to specify its own syntax. However, this sort of recursive approach is unlikely to be an effective teaching method. Instead, let me try to give an example.

Here is an example of how it might be used to specify a very simple and limited language. The lines beginning with “//” are comments:

// A sentence is one or more words, with spaces in between,
// and period at the end
sentence = word , { " " , word } , "."

// A word is one or more letters
word = letter , { letter }

// A letter is either "a" or "b" or "c"
letter = "a" | "b" | "c"

In the above example, the expressions "a", "b", "c", " ", and "." are giving the lowest-level of available building blocks in this language, which are known as “terminal strings”. The other building blocks introduced, sentence, word, and letter are examples of “non-terminal symbols”, since there built up of other blocks, specified by “production rules” (the equations describing how they are formed. In these rules, the comma , means concatenation, the brackets { ... } means zero or more repetitions of what is inside, and the pipe | means “or” (i.e., a choice among options on either side).

This is an overly simplified example, since only five characters (three letters and two punctuation) are allowed, but we could have specified more. Here are example of valid sentences according the above syntax rules:

abc.
b c aa b.
a.
c cc a.
cab.

Here are examples of invalid sentences, with comments explaining why:

// Contains invalid letters
d.
A.
cat.
hello.

// Missing period at end
a b c
aa

// Too many spaces between words, or spaces at beginning/end
  a.
a    b.
c b a .

Edit: I wasn’t originally intending to write such a long, pedantic post about linguistics, yet here we are. I guess no one should be surprised.

6 Likes

Not very convincing. :wink:

@Gooplet, if you just want to write a small program that turns simple SGF into JSON, there’s no need to get into grammar and that stuff. If you want to cover most edge cases things are different. But I think a good starting point would be to just convert an SGF from an OGS game, without any variations.

9 Likes

No.

Especially, understanding a description of EBNF itself is totally not necessary. All the technical terms you quoted would only be needed by a person writing a compiler or other highly technical tools.

For the specific task you want to do, which is “reading SGF” - it would be helpful to be able to read EBNF, because then you can read “what you might expect to find in SGF”.

_Reading_ EBNF is pretty easy though, right?

The SGF Specification says

  Collection = GameTree { GameTree }
  GameTree   = "(" Sequence { GameTree } ")"
  Sequence   = Node { Node }
  Node       = ";" { Property }
  Property   = PropIdent PropValue { PropValue }
  PropIdent  = UcLetter { UcLetter }
  PropValue  = "[" CValueType "]"
  CValueType = (ValueType | Compose)
  ValueType  = (None | Number | Real | Double | Color | SimpleText |
		Text | Point  | Move | Stone)

"

  • A collection is one GameTree, followed maybe by more of them
  • A GameTree starts with open paren, then has a Sequence, followed maybe by more GameTrees, then a close paren
  • A sequence is one or more Nodes
  • A Node is a semicolon followed maybe by some Properties
  • A Propery consists of a PropIdent and one or more ProValues

    "
    etc

IF you were intending to write a “proper tool covering all SGF”, you would read the SGF spec to scope out everything you might encounter.

I certainly wouldn’t do that myself, for this task though.

I’d start with “Gee, I wonder what the SGFs I care about look like” and work from there.

You’re learning to program, not learning to write a compiler (one of the “ultimate tasks” of a programmer, which they teach (or used to) in advanced university courses).

8 Likes

image
:thinking:

In all seriousness though, this was quite helpful, thanks :smiley:

I wound up focused on understanding this and then getting distracted by vimtutor for all of my programming time today…

But my goal for tomorrow is to take @GreenAsJade’s and @Jon_Ko’s suggestion - pick a few SGF’s an run with it. If I wanna add greater specificity later, I can ^^

6 Likes

Neither the first nor the last person to set out with the goal of learning programming only to wind up down the rabbit hole of learning Vim :rofl::heart:

7 Likes

Soooo i’m working on my SGF parser and i have (non-urgent) questions :melting_face:

Namely, how do I go about seeing how OGS actually stores games? Is that something I find by exploring the API, or is that something I’ll find in the source code on GitHub?

Also, does anybody have any insight into why OGS SGF’s with a single outer game tree and no variations format each move as a nested game tree? And why are demo boards different?

For example, a test demo board I made

demo board contents
CA[UTF-8]
GM[1]
GN[testing \] c[an (; escaped \\[ chars confuse]
PC[https://online-go.com/review/1337389]
PB[Gooplfet]
PW[Paige]
BR[2k]
WR[1d]
OT[Error: time control missing]
RE[?]
SZ[19]
RU[Japanese]

;B[pd]
;W[pq]C[this [\] \] test \\\] is ; (; tryn something]
;B[dc]C[

-- chat --
Gooplet: testsejeslkfdsajflkdsj ; (; \]
]
)```

This is basically what I’d expect; it is formatted the same as an SGF I grabbed from Fox:

SGF contents
SZ[19]
GN[]
DT[2024-09-17]
PB[gooplet]
PW[太阁殿下]
BR[3段]
WR[3段]
KM[375]HA[0]RU[Chinese]AP[GNU Go:3.8]RN[3]RE[W+R]TM[300]TC[3]TT[30]AP[foxwq]RL[0]
;B[pd];W[dd];B[qp];W[cq];B[np];W[nc];B[qf];W[pb];B[qc];W[kc];B[cf];W[ch];B[cc];W[dc];B[cd];W[de];B[cb];W[ce];B[be];W[df];B[bf];W[db];B[dg];W[cg];B[eg];W[ck];B[hg];W[ca];B[ba];W[da];B[ab];W[he];B[ff];W[fe];B[dn];W[cn];B[co];W[cm];B[dp];W[dq];B[eq];W[bo];B[ep];W[cp];B[jq];W[do];B[pj];W[qm];B[qk];W[om];B[po];W[mm];B[jo];W[eo];B[gp];W[nj];B[fo];W[fn];B[gn];W[gm];B[en];W[fm];B[co];W[hn];B[go];W[gf];B[gg];W[fh];B[fg];W[kg];B[ie];W[if];B[hf];W[ge];B[jg];W[ig];B[ih];W[jf];B[jh];W[hh];B[kf];W[je];B[ke];W[jd];B[gh];W[hi];B[gi];W[ii];B[ji];W[jj];B[hj];W[ij];B[gk];W[ki];B[el];W[em];B[dm];W[dl];B[dk];W[cl];B[fl];W[hl];B[hk];W[ik];B[il];W[im];B[jl];W[jm];B[jk];W[kh];B[km];W[kl];B[kk];W[ll];B[bi];W[ci];B[cj];W[dj];B[bj];W[ek];B[di];W[fj];B[gl];W[hm];B[gj];W[bk];B[bh];W[nf];B[lk];W[kn];B[ml];W[lm];B[nk];W[nl];B[mk];W[ok];B[pl];W[ol];B[pm];W[pn];B[on];W[pk];B[ql];W[nn];B[qn];W[oj];B[nd];W[oc];B[md];W[od];B[oe];W[ne];B[mc];W[of];B[pe];W[mb];B[lb];W[nb];B[lc];W[kb];B[mg];W[oh];B[nh];W[ng];B[mj];W[mh];B[lh];W[ni];B[mi];W[nh];B[pi];W[qg];B[pg];W[ph];B[qh];W[rg];B[rh];W[pf];B[rf];W[sg];B[sh];W[og];B[sf];W[pg];B[no];W[mo];B[lo];W[mp];B[ln];W[mn];B[mq];W[lp];B[ko];W[lq];B[jn];W[km];B[mr];W[lr];B[kr];W[ms];B[nr];W[ns];B[os];W[ls];B[oq];W[lg])```

Whereas, this is a game from OGS, where every single move is formatted in a way I’d normally expect variations to be formatted:

buncha nested game trees
CA[UTF-8]
GM[1]
DT[2024-09-22]
PC[OGS: https://online-go.com/game/68012927]
GN[Friendly Match]
PB[danymaster52]
PW[Puleja]
BR[1d]
WR[2d]
TM[600]OT[5x30 byo-yomi]
RE[?]
SZ[19]
KM[6.5]
RU[Japanese]
C[Game chats will be available in SGF downloads once the game has finished.
]
;B[pd]
(;W[qp]
(;B[dd]
(;W[cp]
(;B[oq]
(;W[po]
(;B[lq]
(;W[qf]
(;B[nc]
(;W[cf]
(;B[fc]
(;W[cd]
(;B[cc]
(;W[bc]
(;B[ce]
(;W[bd]
(;B[de]
(;W[be]
(;B[df]
(;W[cg]
(;B[eq]
(;W[gp]
(;B[eo]
(;W[dn]
(;B[en]
(;W[dm]
))))))))))))))))))))))))))```

This is based on my understanding of the EBNF chart at red-bean
image

2 Likes

Yeah I wish it didn’t

I remember that using something like sabaki to view OGS game downloads, like with AI review variations was a headache, but I haven’t checked it recently probably for that reason :slight_smile:

3 Likes

It’s funny, I hadn’t even ever realized that this was abnormal until now. Most of the SGFs i’ve looked at before are from OGS, so I had thought it was a weird quirk that was just inherent to SGFs in general.

edit: removed apostrophes from ‘SGFs’. I hadn’t realized “SGF’s” bothered me until reading back over my last response :see_no_evil:

3 Likes

I don’t think you can see exactly how it’s stored (the database stuff is all closed source), but I think it’s pretty similar to what’s passed via the API. Namely, online-go.com/api/v1/games/<id>

Lol, no good reason - here’s the GitHub issue: SGF, excessive use of ( new variation token · Issue #2005 · online-go/online-go.com · GitHub

3 Likes

Oh actually, one file to check out would be online-go.com/src/models/games.d.ts at devel · online-go/online-go.com · GitHub which is the TypeScript types for the API

2 Likes

Really, this applies to a lot of coding, in general. Reminds me of these “fun” parts of JavaScript language design.

https://www.destroyallsoftware.com/talks/wat

7 Likes

the wat talk is classic :slight_smile: JavaScript seems to have an abundance of such oddities!


And one more code pointer, here is the OGS code that converts a move tree into an SGF string: goban/src/engine/MoveTree.ts at 072d6ce0e635a766c2ba5bf4d6272a9e40d8c4cd · online-go/goban · GitHub I haven’t looked closely, but I believe the trunk_next/"(" logic is what would need to be changed for a more standard output.

3 Likes

I learned some programming when I was a teenager, just experimenting with Delphi, writing programs such as calculating prime numbers, a converter between number systems of arbitrary base etc. In school we scratched on the surface of HTML, Javascript and PHP (a language most of my colleagues nowadays seem to dislike).
At Uni we had C++, R, and a symbolic Math engine where I can’t remember the name unfortunately.
When I started my job I had basically no experience in software development though, which is much more than only programming. I feel like one can learn about it for a lifetime.

For getting started with coding, generally I think a good balance is good, between consuming some learning materials, and experimenting on your own. I wouldn’t start with programming for an idea that requires a lot of work, because small achievements are great to stay motivated.
But as with many things, everybody has to find their own way. Whatever is fun is good :slightly_smiling_face:

6 Likes

There seem to be many programmers playing Go. I wonder why that is. Sure, it’s a game of patterns but there are many such games. Maybe it’s the ultimate game of patterns.

And how do I square that with the fact that, despite most of my friends being programmers, I can’t convince them to play Go? :frowning:

I first learned about programming from my uncle, notably a decent club chess player, who gave me a book about c++ for my 15th birthday. I started by trying to write a console-based chess engine in c++, this went rather poorly. Since then I’ve always had at least one unfinished hobby project going, usually more than two. Web development I always tried to stay away from because I really dislike Javascript, but it’s hard to get around these days.

Finished projects include a betting platform for Age of Empires 3 tournaments, a supporting app for the game Dominion (I wasn’t satisfied with existing ones), a chess variant, a digital board game based on AoE2, and finally something Go related: A website with full board problems from pro games, generated by AI (https://realgoproblems.com/).

Most recently a simple website to make predictions on world events for rating points, to use with friends. Figuring out a good rating system for this was much more difficult than I expected, therefore a fun puzzle.

I enjoy programming as a hobby. Unfortunately, over the years I’ve come to realize it’s not a rewarding career, at least not for me. Then again, maybe for me there is no such thing as a rewarding career :thinking:

6 Likes

It’s probably as much about how you found out about it as anything else. Why might a certain fraction of Go players like manga or anime? Maybe they found Go from Hikaru no Go. Why might there be so many people with a programming background - maybe they found out from a fellow programmer, found out from a university club, watched Alpha Go play Lee Sedol, or tried making simple games or ai for games.

We probably haven’t hit a high enough proportion of the population either knowing about or playing Go, to not have it that some interest they have also correlated with what led them to the game in the first place.

Not all programmers like Go and not all Go players like programming, probably. I think that’s just it.

I think people can also have a casual interest in something and not really actively do it themselves, like watching sports but not playing it.

I like to watch chess videos and tournament streams, keep up with the odd bit of news, but I don’t play very often.

6 Likes

Maybe it’s not unusually many programmers who play go, but unusually few non-programmers who play go (in the West).

I wonder if programmers are similarly over-represented in Asia. If not, then maybe the way the game is presented to beginners in the West tends to scare away non-programmers.

3 Likes

There is an unusual proportion but I don’t think they re like a majority at all. I’m no more so active but I 'd say that another category may even be bigger: teachers/professors (math/philo/geo/…computing :rofl:) From my experience there could be even less in China although it’s a bit hard to be firm on this. Most said “I’m in business”. I’m still even wondering if I met a programmer, players had various jobs anyway when we talked about that (not always). A key parameter is free time and children to care. One difference is that there are more strong ones teaching their game, and like here there are some apparently not that rich but very regular to come and play.

The main difference is more cultural as anything else. There everyone knows about what is weiqi even if most never played (or just a little bit at school long ago).

4 Likes

It’s possible that the Group A is over-represented among members of Group B, but still the members of Group B form a small fraction of those within Group A.

Here’s a caricature of what might be the situation:

The overall square represents the global population. The red circle represents the programmers, while the blue circle represents those that play (or would be potentially interested in) Go. This hypothetical diagram shows programmers being over-represented among Go players, while the Go players are still a small fraction of programmers. By making the blue circle smaller, and overlapping more with the red circle, we can make this discrepancy even larger.

6 Likes

Hmmm have any of you seen any examples of SGF properties that have multiple values for a single identifier? According to the EBNF definition, this is allowed:

Property   = PropIdent PropValue { PropValue }
PropIdent  = UcLetter { UcLetter }
PropValue  = "[" CValueType "]"

But I cannot find a single instance of this happening, and I can’t think of any time that this would be useful. I can’t find any further mention of this on the SGF specification page, either :face_with_monocle:

3 Likes

Adding multiple setup stones and/or markup should be done with a list of property values like this.

For example, a node setting 3 black stones might include:

AB[bf][ce][cg]

However, a common mistake in SGF generation is writing multiple properties, like this:

AB[bf]AB[ce]AB[cg]

This technically does not conform to the standard, but some software still mistakenly does this. BesoGo will parse this and other non-standard SGF files, but aims to generate conforming SGF output.

Note that OGS, when adding set stones, via the demo board GUI, puts them into separate nodes, like this:

;AB[bf];AB[ce];AB[cg]

This is not technically wrong, but maybe bad style to (by default) split setup stones across multiple nodes (since putting them all in one node might be desired).

Also, when adding multiple markup symbols (with an OGS demo board), it will incorrectly generate SGF like this:

TR[dm]TR[gm]TR[jp]

On the page specifying properties SGF properties (FF[4]), you find cases where the Propertytype is specified as “list of …”. Those are cases where this pattern should be used.

5 Likes