Code Examples
A repository of 155 code examples for BeepBeep
WhiteVsBlack.java
1 /*
2  BeepBeep, an event stream processor
3  Copyright (C) 2008-2023 Sylvain HallĂ©
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published
7  by the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 package chess;
19 
20 import static ca.uqac.lif.cep.Connector.BOTTOM;
21 import static ca.uqac.lif.cep.Connector.connect;
22 import static ca.uqac.lif.cep.Connector.INPUT;
23 import static ca.uqac.lif.cep.Connector.OUTPUT;
24 import static ca.uqac.lif.cep.Connector.TOP;
25 
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 
30 import ca.uqac.lif.cep.GroupProcessor;
31 import ca.uqac.lif.cep.Processor;
32 import ca.uqac.lif.cep.functions.ApplyFunction;
33 import ca.uqac.lif.cep.functions.Constant;
34 import ca.uqac.lif.cep.functions.Cumulate;
35 import ca.uqac.lif.cep.functions.CumulativeFunction;
36 import ca.uqac.lif.cep.functions.FunctionTree;
37 import ca.uqac.lif.cep.functions.IdentityFunction;
38 import ca.uqac.lif.cep.functions.StreamVariable;
39 import ca.uqac.lif.cep.functions.TurnInto;
40 import ca.uqac.lif.cep.io.Print.Println;
41 import ca.uqac.lif.cep.io.ReadLines;
42 import ca.uqac.lif.cep.tmf.Filter;
43 import ca.uqac.lif.cep.tmf.Fork;
44 import ca.uqac.lif.cep.tmf.KeepLast;
45 import ca.uqac.lif.cep.tmf.Pump;
46 import ca.uqac.lif.cep.tmf.Slice;
47 import ca.uqac.lif.cep.util.Numbers;
48 import ca.uqac.lif.cep.util.Strings;
49 
50 /**
51  * Process a database of chess games to calculate the number of white wins
52  * vs.<!-- --> black wins. This example is a follow-up to a
53  * <a href="https://web.archive.org/web/20140119221101/https://tomhayden3.com/2013/12/27/chess-mr-job/">2013
54  * post by Tom Hayden</a>, who performed the same calculation as a MapReduce
55  * job for <a href="https://hadoop.apache.org/">Hadoop</a>. The original input
56  * file, called the <em><a href="https://web.archive.org/web/20140119221101/http://www.top-5000.nl/pgn.htm">millionbase
57  * archive</a></em>, is 1.74 GB big and contains about 2 million chess games.
58  * <p>
59  * The surprising finding about this example is that, while the Hadoop job
60  * reportedly takes <strong>26 minutes</strong> to terminate, the BeepBeep
61  * pipeline takes a mere <strong>35 seconds</strong> to compute the same
62  * result.
63  * <p>
64  * The program calculates the number of occurrences of each possible outcome:
65  * <ol>
66  * <li>1-0 (White wins)</li>
67  * <li>&half;-&half; (draw)</li>
68  * <li>0-1 (Black wins)</li>
69  * <li>unknown (marked as a "*" in the database)</li>
70  * </ol>
71  * It does so with the following processor chain:
72  * <p>
73  * <img src="./doc-files/chess/WhiteVsBlack.png" alt="Pipeline"/>
74  * <p>
75  * Running the program should produce the output:
76  * <pre>
77  * {[Result "*"]=221.0, [Result "1-0"]=852305.0, [Result "1/2-1/2"]=690934.0, [Result "0-1"]=653728.0}
78  * Total time: 37629 ms
79  * </pre>
80  * <strong>Note:</strong> the example deliberately makes use of multiple
81  * syntactical shortcuts to reduce the size of the code as much as possible
82  * (at the price of some legibility).
83  *
84  * @author Sylvain HallĂ©
85  */
86 public class WhiteVsBlack
87 {
88 
89  public static void main(String[] args) throws IOException
90  {
91  /* The path to the "millionbase" archive. The examples repository does
92  * *not* contain the file due to its size, but it can be downloaded from
93  * the URL provided in the Javadoc above. Alternatively, any file in the
94  * PGN format can be used in its place. */
95  String filename = "millionbase-2.22.pgn";
96 
97  /* Pump lines from the local PGN file. */
98  Pump pump = (Pump) connect(new ReadLines(
99  new FileInputStream(new File(filename))), new Pump());
100 
101  /* Retain only lines that start with the string "[Result" */
102  Processor fork = connect(pump, new Fork());
103  Processor filter = connect(fork, TOP, new Filter(), TOP);
104  Processor result = connect(fork, BOTTOM,
105  new ApplyFunction(new FunctionTree(Strings.startsWith, StreamVariable.X, new Constant("[Result"))), INPUT);
106  connect(result, OUTPUT, filter, BOTTOM);
107 
108  /* Pipe the output to a slice that increments a counter for each outcome. */
109  Processor slice = connect(filter, new Slice(
110  new IdentityFunction(1), new GroupProcessor(1, 1) {
111  {
112  TurnInto one = new TurnInto(1);
113  Processor sum = connect(one,
114  new Cumulate(new CumulativeFunction<Number>(Numbers.addition)));
115  addProcessors(one, sum).associateInput(one).associateOutput(sum);
116  }
117  }));
118 
119  /* Keep only the last event of the pipeline and print it. */
120  connect(slice, new KeepLast(), new Println());
121 
122  /* Start the pump to process the file, and count the time it takes. */
123  long start = System.currentTimeMillis();
124  pump.run();
125  long stop = System.currentTimeMillis();
126  System.out.println("Total time: " + (stop - start) + " ms");
127  }
128 
129 }
Process a database of chess games to calculate the number of white wins vs.