diff --git a/example/example.md b/example/example.md new file mode 100644 index 0000000..c3544ba --- /dev/null +++ b/example/example.md @@ -0,0 +1,237 @@ +Example reused from [stockfish_chess_engine](https://github.com/loloof64/StockfishChessEngineFlutter). + +```dart +import 'dart:async'; + +import 'package:clipboard/clipboard.dart'; +import 'package:flutter/material.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:chess/chess.dart' as chess_lib; +import 'package:window_manager/window_manager.dart'; + +import 'package:flutter_stockfish_plugin/stockfish.dart'; +import 'package:flutter_stockfish_plugin/stockfish_state.dart'; + +void main() { + runApp(const MaterialApp( + home: MyApp(), + )); +} + +class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + + @override + MyAppState createState() => MyAppState(); +} + +class MyAppState extends State with WindowListener { + late Stockfish _stockfish; + final _fenController = TextEditingController( + text: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'); + late StreamSubscription _stockfishOutputSubsciption; + var _timeMs = 1000.0; + var _nextMove = ''; + var _stockfishOutputText = ''; + + @override + void initState() { + windowManager.addListener(this); + _overrideDefaultCloseHandler(); + _doStartStockfish(); + super.initState(); + } + + Future _overrideDefaultCloseHandler() async { + await windowManager.setPreventClose(true); + setState(() {}); + } + + @override + void dispose() { + _stopStockfish(); + super.dispose(); + } + + @override + void onWindowClose() async { + _stopStockfish(); + await Future.delayed(const Duration(milliseconds: 200)); + await windowManager.destroy(); + } + + void _readStockfishOutput(String output) { + // At least now, stockfish is ready : update UI. + setState(() { + _stockfishOutputText += "$output\n"; + }); + if (output.startsWith('bestmove')) { + final parts = output.split(' '); + setState(() { + _nextMove = parts[1]; + }); + } + } + + void _pasteFen() { + FlutterClipboard.paste().then((value) { + setState(() { + _fenController.text = value; + }); + }); + } + + void _updateThinkingTime(double newValue) { + setState(() { + _timeMs = newValue; + }); + } + + bool _validPosition() { + final chess = chess_lib.Chess(); + return chess.load(_fenController.text.trim()); + } + + void _computeNextMove() { + if (!_validPosition()) { + final message = "Illegal position: '${_fenController.text.trim()}' !\n"; + setState(() { + _stockfishOutputText = message; + }); + return; + } + setState(() { + _stockfishOutputText = ''; + }); + _stockfish.stdin = 'position fen ${_fenController.text.trim()}'; + _stockfish.stdin = 'go movetime ${_timeMs.toInt()}'; + } + + void _stopStockfish() async { + if (_stockfish.state.value == StockfishState.disposed || + _stockfish.state.value == StockfishState.error) { + return; + } + _stockfishOutputSubsciption.cancel(); + _stockfish.stdin = 'quit'; + await Future.delayed(const Duration(milliseconds: 200)); + setState(() {}); + } + + void _doStartStockfish() async { + _stockfish = Stockfish(); + _stockfishOutputSubsciption = + _stockfish.stdout.listen(_readStockfishOutput); + setState(() { + _stockfishOutputText = ''; + }); + await Future.delayed(const Duration(milliseconds: 1100)); + _stockfish.stdin = 'uci'; + await Future.delayed(const Duration(milliseconds: 3000)); + _stockfish.stdin = 'isready'; + } + + void _startStockfishIfNecessary() { + setState(() { + if (_stockfish.state.value == StockfishState.ready || + _stockfish.state.value == StockfishState.starting) { + return; + } + _doStartStockfish(); + }); + } + + Icon _getStockfishStatusIcon() { + Color color; + switch (_stockfish.state.value) { + case StockfishState.ready: + color = Colors.green; + break; + case StockfishState.disposed: + case StockfishState.error: + color = Colors.red; + break; + case StockfishState.starting: + color = Colors.orange; + } + return Icon(MdiIcons.circle, color: color); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Stockfish Chess Engine example"), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextField( + controller: _fenController, + decoration: const InputDecoration( + hintText: 'Position FEN value', + border: OutlineInputBorder(), + ), + ), + ElevatedButton( + onPressed: _pasteFen, + child: const Text('Coller FEN'), + ), + Slider( + value: _timeMs, + onChanged: _updateThinkingTime, + min: 500, + max: 3000, + ), + Text('Thinking time : ${_timeMs.toInt()} millis'), + ElevatedButton( + onPressed: _computeNextMove, + child: const Text('Search next move'), + ), + Text('Best move: $_nextMove'), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _getStockfishStatusIcon(), + ElevatedButton( + onPressed: _startStockfishIfNecessary, + child: const Text('Start Stockfish'), + ), + ElevatedButton( + onPressed: _stopStockfish, + child: const Text('Stop Stockfish'), + ), + ], + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + width: 850.0, + height: 300.0, + decoration: BoxDecoration( + border: Border.all( + width: 2.0, + ), + borderRadius: const BorderRadius.all( + Radius.circular(8.0), + ), + ), + child: SingleChildScrollView( + child: Text( + _stockfishOutputText, + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} +``` \ No newline at end of file