这可能是一个愚蠢的问题,我暂时找不到答案。
基本上:我有一个方法创建一个调用一个调用递归的方法的线程,....这个递归运行吗?因为我得到的是垃圾...... 我用c#代码为unity3d编写代码。我想在单独的线程上运行的脚本不包含统一api方法。
这就是我所拥有的:
方法GetPCNextTurn
创建如下的线程:
Thread myThread = new Thread(() => CompPlayTurn(MinMaxBoard, weights));
myThread.Start();
然后CompPlayTurn
应该开始吧?
CompPlayTurn
调用ScoreBoard
,返回一个值。
然后在一些条件CompPlayTurn
调用递归后,再次调用ScoreBoard
我会假设此时它会在线程起始行之后返回第一个方法吗?
似乎并没有像我希望的那样发生。有人可以用线程和递归的行为来启发我吗?
我需要1个线程进行此递归,我需要的是将它与主线程分开。
这是代码: 这是脚本中的主要方法:
public int GetPCNextTurn(int[][] board, int height, int width, int sequence)
{
this.done = false;
this.height = height;
this.width = width;
this.sequence = sequence;
int[][] MinMaxBoard = CopyBoard(board);
weights = GetWeights(sequence);
Thread myThread = new Thread(() => CompPlayTurn(MinMaxBoard, weights));
myThread.Start();
return ans;
}
public void CompPlayTurn(int[][] MinMaxBoard, int[] weights)
{
int scoreOrig = ScoreBoard(MinMaxBoard);
if (scoreOrig == orangeWins) winner = (int)Winner.pc;
// Debug.Log("I win\n");
else if (scoreOrig == yellowWins) winner = (int)Winner.player;
// Debug.Log("You win\n");
else
{
int move, score;
Minimax(true, (int)Mycell.Orange, maxDepth, MinMaxBoard, out move, out score);
ans = move;
if (move != -1)
{
ans = move;
// dropDisk(board, move, (int)Mycell.Orange);
scoreOrig = ScoreBoard(MinMaxBoard);
if (scoreOrig == orangeWins) { winner = (int)Winner.pc; }//Debug.Log("I win\n"); }
else if (scoreOrig == yellowWins) { winner = (int)Winner.player; }//Debug.Log("You win\n"); }
}
else winner = (int)Winner.draw;
}
}
public int ScoreBoard(int[][] scores)
{
int[] counters;
int x, y, count = 0, size = (2 * sequence + 1);
counters = new int[size];
Array.Clear(counters, 0, counters.Length); //needed?
// Horizontal spans
for (y = 0; y < height; y++)
{
int score = 0;
for (int i = 0; i <= sequence - 2; i++)
score += scores[y][i];
for (x = (sequence - 1); x < width; x++)
{
score += scores[y][x];
counters[score + sequence]++;
score -= scores[y][x - (sequence - 1)];
}
}
// Vertical spans
for (x = 0; x < width; x++)
{
int score = 0;
for (int i = 0; i <= sequence - 2; i++)
score += scores[i][x];
for (y = (sequence - 1); y < height; y++)
{
score += scores[y][x];
counters[score + sequence]++;
score -= scores[y - (sequence - 1)][x];
}
}
// Down-right (and up-left) diagonals
for (y = 0; y < height - (sequence - 1); y++)
{
for (x = 0; x < width - (sequence - 1); x++)
{
int score = 0, idx = 0;
for (idx = 0; idx < sequence; idx++)
{
score += scores[y + idx][x + idx];
}
counters[(score + sequence)]++;
}
}
// up-right (and down-left) diagonals
for (y = (sequence - 1); y < height; y++)
{
for (x = 0; x < width - (sequence - 1); x++)
{
int score = 0, idx = 0;
for (idx = 0; idx < sequence; idx++)
{
score += scores[y - idx][x + idx];
}
counters[(score + sequence)]++;
}
}
if (counters[0] != 0)
return yellowWins;
else if (counters[(sequence * 2)] != 0)
return orangeWins;
else
{
for (int i = 1; i < size - 1; i++)
{ count += weights[i] * counters[i]; }
return count;
}
}
public void Minimax(bool maximizeOrMinimize, int color, int depth, int[][] MinMaxBoard, out int move, out int score)
{
if (0 == depth)
{
move = -1;
score = ScoreBoard(MinMaxBoard);
}
else
{
int bestScore = maximizeOrMinimize ? -10000000 : 10000000;
int bestMove = -1;
for (int column = 0; column < width; column++)
{
if (MinMaxBoard[0][column] != (int)Mycell.Barren)
continue;
int rowFilled = dropDisk(MinMaxBoard, column, color); // damage the state
if (rowFilled == -1)
continue;
int s = ScoreBoard(MinMaxBoard);
if (s == (maximizeOrMinimize ? orangeWins : yellowWins))
{
bestMove = column;
bestScore = s;
MinMaxBoard[rowFilled][column] = (int)Mycell.Barren;
break;
}
int moveInner, scoreInner;
Minimax(!maximizeOrMinimize, color == (int)Mycell.Orange ? (int)Mycell.Yellow : (int)Mycell.Orange,
depth - 1, MinMaxBoard, out moveInner, out scoreInner);
MinMaxBoard[rowFilled][column] = (int)Mycell.Barren; // Undo the damage
// No need for lists and sorting - just keep the best value you meet.
if (maximizeOrMinimize)
{
if (scoreInner >= bestScore)
{
bestScore = scoreInner;
bestMove = column;
}
}
else
{
if (scoreInner <= bestScore)
{
bestScore = scoreInner;
bestMove = column;
}
}
}
move = bestMove;
score = bestScore;
}
}
public int dropDisk(int[][] MinMaxBoard, int column, int color)
{
int y;
for (y = height - 1; y >= 0; y--)
if (MinMaxBoard[y][column] == (int)Mycell.Barren)
{
MinMaxBoard[y][column] = color;
return y;
}
return -1;
}
我尝试添加一个方法来判断线程是否已完成运行:
public bool TryGetValue(out int val)
{
val = ans;
this.done = false;
if (done==true)
return true;
return false;
}
线程有一个公共bool变量,它在CompPlayTurn
中被初始化,所以线程第一次用false初始化它
只是为了测试它,我在CompPlayTurn
内将其值设置为true,这是它做的第一件事(在递归和所有内容之前,就在方法签名之后)。
对于我添加的主线程:
while (!(minimaxscript.TryGetValue(out column)))
{ StartCoroutine(wait(count)); }
和
public IEnumerator wait(int count)
{
Debug.Log("not done yet");
count++;
if (count == 7)
{
Application.Quit();
yield break;
}
yield return new WaitForSeconds(3f);
}
我开始使用yield return new WaitForEndOfFrame();
然后返回new waitforseconds
,最后我添加了Application.Quit()
它冻结....我不认为这是线索,因为他没有称之为追索权......可以是主线程逻辑吗?它运行时没有线程递归ai就好了。
我甚至尝试在创建线程(done=true
)后立即将bool变量更新为:after the thread.start
,因此它应该是在离开脚本之前更新变量的主线程,但它仍然会冻结。好像变量永远不会被设置....但是如果没有这种保护,我会得到价值,它们从何而来呢?。
Nvm只是缺乏睡眠 - .-我很蠢......
这是我想写的方法,当我写下我做的事情时,不知道是什么让我想到了:
public bool TryGetValue(out int val)
{
val = ans;
return done;
编辑: 我将done = false更改为thead所做的第一件事(调用方法中的第一行)和done = false,结束时。
然后主线程调用waitforseconds(1f)和调试消息以确保它等待。
使用:
bool ok = (minimaxscript.TryGetValue(out column));
while (ok == false)
{
ok = (minimaxscript.TryGetValue(out column));
StartCoroutine( wait());
}
它冻结了......
添加轮询并保护方法不被调用但没有完成但似乎解决了问题。
问题最终是团结一致,我一次又一次地调用这个方法。 我正在检查它是否已完成并对其进行协调,但无论是通过更新方法中调用的方法都保持调用它,所以我没有注意到。
答案 0 :(得分:1)
要回答你的问题,是的,你可以递归调用一个函数,它将保留在你刚创建的线程中。一旦启动该线程,无论你调用什么函数,它都将保留在该线程上,直到它不再有任何代码要执行。
但是,您似乎要在public function login($username, $password){
session_start();
if (!empty($username) && !empty($password)) {
$stmt = $this->db->prepare("SELECT * FROM user WHERE username=? and password=?");
$stmt->bindParam(1, $username);
$stmt->bindParam(2, $password);
$stmt->execute();
if ($stmt->rowCount() == 1) {
$_SESSION['login'] = true;
$_SESSION['username'] = $username;
} else {
echo "Wrong username or password";
}
} else {
echo "Please enter username and password";
}
}
函数中为“ans”分配值,然后从CompPlayTurn
问题是你不能保证在你从那个函数返回之前会分配ans(并且很可能不会)。当您创建新线程时,您无法保证每个线程何时完成工作。这意味着可以在返回函数之前或之后设置ans,从而使返回值不再有效。
如果您希望能够从单独的线程返回值,则需要将委托传递给该函数,或者创建一个单独的函数以在设置该值时进行轮询。但是要注意,任何特定于统一的东西只能在主线程中使用,所以我建议使用轮询函数来返回值
GetPCNextTurn
这是一个非常粗略的实现,因为对于任何多线程,您都希望使其更加强大,我主要是写这个来向您展示概念