循环未到达流的末尾
Loop doesn't reach end of stream
我正在开发一个程序来分析国际象棋问题——尤其是残局问题——使用开源国际象棋引擎的 .exe 版本 Stockfish 9。
这是(非常简化的)EndgameAnalyzer
class:
class EndgameAnalyzer
{
private StockfishOracle oracle = new StockfishOracle();
public void AnalyzeByFEN(string fen)
{
var evaluation = oracle.GetEvaluation(fen);
Console.WriteLine($"{fen}\t{evaluation}");
}
}
AnalyzeByFEN
方法接收一个 FEN(表示国际象棋位置的字符串)并记下该位置的引擎评估。
StockfishOracle
是用来和引擎沟通的class(就像神谕是用来和神沟通的:)),使用UCI protocol。本题相关UCI命令为:
uci
: Enter uci mode.
position fen //followed by a FEN
: Set a position to analyze.
go depth 1
: Analyze the position one ply ("move") deep.
这里是(再次,非常简化)StockfishOracle
class:
class StockfishOracle
{
private Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo()
{
FileName = @"C:\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.Start();
SendUCICommand("uci");
}
public string GetEvaluation(string fen)
{
SendUCICommand($"position fen {fen}");
SendUCICommand("go depth 1");
string result = string.Empty;
while (!process.StandardOutput.EndOfStream)
{
result = process.StandardOutput.ReadLine();
}
return result;
}
private void SendUCICommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
使用 FEN 调用 AnalyzeByFEN
方法时,控制台中未显示任何输出。仔细调查后发现循环 while (!process.StandardOutput.EndOfStream)
将永远持续下去,因此永远不会返回输出。我对流程很陌生,所以我很确定我的代码中存在一些基本错误。如何解决这个问题?
谢谢!
看起来stockfish returns "uciok" 在结束他的工作。
您可以尝试以下代码来确定它何时完成(参见 if (line == "uciok")
):
class Program
{
class StockfishOracle
{
private readonly Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo
{
FileName = @"D:\stockfish-9-win\Windows\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.Start();
SendUciCommand("uci");
}
public IEnumerable<string> GetEvaluation(string fen)
{
SendUciCommand($"position fen {fen}");
SendUciCommand("go depth 1");
while (!process.StandardOutput.EndOfStream)
{
var line = process.StandardOutput.ReadLine();
yield return line;
if (line == "uciok")
{
break;
}
}
}
private void SendUciCommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
static void Main(string[] args)
{
var s = new StockfishOracle();
foreach (var @out in s.GetEvaluation(""))
{
Console.WriteLine(@out);
}
}
}
好吧,这对我来说是个不错的谜语。
让我们考虑另一种方法并尝试与国际象棋 oracle 异步通信:
class Program
{
class StockfishOracle
{
private readonly Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo
{
FileName = @"D:\stockfish-9-win\Windows\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.OutputDataReceived += (sender, args) => this.DataReceived.Invoke(sender, args);
}
public event DataReceivedEventHandler DataReceived = (sender, args) => {};
public void Start()
{
process.Start();
process.BeginOutputReadLine();
}
public void Wait(int millisecond)
{
this.process.WaitForExit(millisecond);
}
public void SendUciCommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
static void Main()
{
var oracle = new StockfishOracle();
// this will contain all the output of the oracle
var output = new ObservableCollection<string>();
// in this way we redirect output from oracle to stdout of the main process
output.CollectionChanged += (sender, eventArgs) => Console.WriteLine(eventArgs.NewItems[0]);
// in this way collect all the output from oracle
oracle.DataReceived += (sender, eventArgs) => output.Add(eventArgs.Data);
oracle.Start();
oracle.SendUciCommand("position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
oracle.SendUciCommand("position startpos moves e2e4");
oracle.SendUciCommand("go depth 20");
oracle.Wait(5000); // if output does not contain bestmove after given time, you can wait more
var bestMove = output.Last();
Console.WriteLine("Oracle says that the best move is: " + bestMove);
}
}
据我了解,您正在寻找最佳着法的预测。现在您可以等到它出现在输出中。同样使用相同的事件处理程序,您可以分析 oracle 写入输出的每个字符串,直到您看到所需的字符串。
我正在开发一个程序来分析国际象棋问题——尤其是残局问题——使用开源国际象棋引擎的 .exe 版本 Stockfish 9。
这是(非常简化的)EndgameAnalyzer
class:
class EndgameAnalyzer
{
private StockfishOracle oracle = new StockfishOracle();
public void AnalyzeByFEN(string fen)
{
var evaluation = oracle.GetEvaluation(fen);
Console.WriteLine($"{fen}\t{evaluation}");
}
}
AnalyzeByFEN
方法接收一个 FEN(表示国际象棋位置的字符串)并记下该位置的引擎评估。
StockfishOracle
是用来和引擎沟通的class(就像神谕是用来和神沟通的:)),使用UCI protocol。本题相关UCI命令为:
uci
: Enter uci mode.
position fen //followed by a FEN
: Set a position to analyze.
go depth 1
: Analyze the position one ply ("move") deep.
这里是(再次,非常简化)StockfishOracle
class:
class StockfishOracle
{
private Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo()
{
FileName = @"C:\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.Start();
SendUCICommand("uci");
}
public string GetEvaluation(string fen)
{
SendUCICommand($"position fen {fen}");
SendUCICommand("go depth 1");
string result = string.Empty;
while (!process.StandardOutput.EndOfStream)
{
result = process.StandardOutput.ReadLine();
}
return result;
}
private void SendUCICommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
使用 FEN 调用 AnalyzeByFEN
方法时,控制台中未显示任何输出。仔细调查后发现循环 while (!process.StandardOutput.EndOfStream)
将永远持续下去,因此永远不会返回输出。我对流程很陌生,所以我很确定我的代码中存在一些基本错误。如何解决这个问题?
谢谢!
看起来stockfish returns "uciok" 在结束他的工作。
您可以尝试以下代码来确定它何时完成(参见 if (line == "uciok")
):
class Program
{
class StockfishOracle
{
private readonly Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo
{
FileName = @"D:\stockfish-9-win\Windows\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.Start();
SendUciCommand("uci");
}
public IEnumerable<string> GetEvaluation(string fen)
{
SendUciCommand($"position fen {fen}");
SendUciCommand("go depth 1");
while (!process.StandardOutput.EndOfStream)
{
var line = process.StandardOutput.ReadLine();
yield return line;
if (line == "uciok")
{
break;
}
}
}
private void SendUciCommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
static void Main(string[] args)
{
var s = new StockfishOracle();
foreach (var @out in s.GetEvaluation(""))
{
Console.WriteLine(@out);
}
}
}
好吧,这对我来说是个不错的谜语。 让我们考虑另一种方法并尝试与国际象棋 oracle 异步通信:
class Program
{
class StockfishOracle
{
private readonly Process process = new Process();
public StockfishOracle()
{
process.StartInfo = new ProcessStartInfo
{
FileName = @"D:\stockfish-9-win\Windows\stockfish_9_x64.exe",
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
process.OutputDataReceived += (sender, args) => this.DataReceived.Invoke(sender, args);
}
public event DataReceivedEventHandler DataReceived = (sender, args) => {};
public void Start()
{
process.Start();
process.BeginOutputReadLine();
}
public void Wait(int millisecond)
{
this.process.WaitForExit(millisecond);
}
public void SendUciCommand(string command)
{
process.StandardInput.WriteLine(command);
process.StandardInput.Flush();
}
}
static void Main()
{
var oracle = new StockfishOracle();
// this will contain all the output of the oracle
var output = new ObservableCollection<string>();
// in this way we redirect output from oracle to stdout of the main process
output.CollectionChanged += (sender, eventArgs) => Console.WriteLine(eventArgs.NewItems[0]);
// in this way collect all the output from oracle
oracle.DataReceived += (sender, eventArgs) => output.Add(eventArgs.Data);
oracle.Start();
oracle.SendUciCommand("position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
oracle.SendUciCommand("position startpos moves e2e4");
oracle.SendUciCommand("go depth 20");
oracle.Wait(5000); // if output does not contain bestmove after given time, you can wait more
var bestMove = output.Last();
Console.WriteLine("Oracle says that the best move is: " + bestMove);
}
}
据我了解,您正在寻找最佳着法的预测。现在您可以等到它出现在输出中。同样使用相同的事件处理程序,您可以分析 oracle 写入输出的每个字符串,直到您看到所需的字符串。