2

好的,所以这是一种通用程序。我正在尝试编写一个扑克程序,用户可以在其中与计算机玩家互动。但是,为了简化它,我正在使用一个更简单的程序进行测试,其中两个玩家试图从计算机中猜测一个数字。一个是人类玩家,另一个是电脑玩家。

在游戏中,玩家轮流猜测程序设置的蜜蜂数量。电脑播放器只是随机化数字,用户应该输入一个数字并按下猜测按钮(或者可以选择退出)。

我的问题是,当人类玩家轮流行动时,我如何暂停游戏的执行,以便人类通过按下按钮或输入文本来做出响应?

我尝试过使用 Timer 并启动它并等待线程结束,但似乎它仍然冻结了 gui。

我还尝试从后台工作线程发送消息以更新 gui,但这给了我一个错误,即无法从另一个线程访问 gui 元素。

有没有人对如何实现这一点有任何建议?

请注意,这不是一个完整的程序,因为我只是为了了解如何在执行过程中与 gui 交互。

猜数字类:

public class NumberGuesser {

    public Player HumanPlayer { get; private set; }

    public Player ComputerPlayer { get; private set;}

    private Player[] _players = new Player[2];

    private int _maxNumber = 20;

    private bool _done = false;

    private Random random;

    public NumberGuesser() {

        HumanPlayer = new HumanPlayer("Me");

        ComputerPlayer = new ComputerPlayer("HAL9000");

        _players[0] = HumanPlayer;
        _players[1] = ComputerPlayer;

        random = new Random((int) DateTime.Now.Ticks);

    }

    public void Play() {

        var myNumber = random.Next(_maxNumber);
        var index = 0;
        while (!_done) {

            var currentPlayer = _players[index];

            var guess = currentPlayer.Act(_maxNumber);
            if (guess == myNumber) {
                currentPlayer.Score++;
            }

            index = (1 + index)%2;
        }

    }
}

电脑玩家:

public class ComputerPlayer : Player {

    private readonly Random _random = new Random((int)DateTime.Now.Ticks);

    public ComputerPlayer(string name) : base(name) {
    }

    public override int Act(int max) {

        return _random.Next(max);

    }
}

人类玩家:

public class HumanPlayer : Player {

    public HumanPlayer(string name) : base(name) {

    }

    public override int Act(int max) {

        return UserGuess();

    }

    private int UserGuess() {


        return 0;

    }
}

玩家等级:

public class Player {
    public string Name { get; private set; }
    public int Score { get; set; }

    public Player(string name) {
        Name = name;
    }


    public virtual int Act(int max) {
        // How should the human enter the guess here???
        return 0;
    }
}

我的主窗口:

<Window x:Class="GuessMyNumber.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="395" Width="728">
<Grid>
    <Label Content="Guess my number!" Height="28" HorizontalAlignment="Left" Margin="122,58,0,0" Name="label1" VerticalAlignment="Top" />
    <Grid Height="174" HorizontalAlignment="Left" Margin="31,170,0,0" Name="grid1" VerticalAlignment="Top" Width="272" DataContext="{Binding Path=HumanPlayer}">
        <Label Content="Human player" Height="28" HorizontalAlignment="Left" Margin="6,6,0,0" Name="label2" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="55,92,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" 
                 Text="{Binding Path=HumanGuess, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Content="Guess" Height="23" HorizontalAlignment="Left" Margin="79,130,0,0" Name="button1" VerticalAlignment="Top" Width="75"
                Command="{Binding Path=GuessCommand}"/>
        <Label Content="{Binding Path=Name}" Height="28" HorizontalAlignment="Left" Margin="96,6,0,0" Name="label3" VerticalAlignment="Top" />
        <Label Content="Score" Height="28" HorizontalAlignment="Left" Margin="6,40,0,0" Name="label4" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="55,42,0,0" Name="textBox2" VerticalAlignment="Top" Width="75" Text="{Binding Path=Score, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
        <Button Content="Quit" Height="23" HorizontalAlignment="Left" Margin="182,130,0,0" Name="buttonQuit" VerticalAlignment="Top" Width="75" Command="{Binding Path=QuitCommand}" />
    </Grid>
    <Grid Height="174" HorizontalAlignment="Left" Margin="328,170,0,0" Name="grid2" VerticalAlignment="Top" Width="270" DataContext="{Binding Path=ComputerPlayer}" >

        <Label Content="Computer player" Height="28" HorizontalAlignment="Left" Margin="6,6,0,0"  VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="55,92,0,0"  VerticalAlignment="Top" Width="120" Text="{Binding Path=HumanGuess, UpdateSourceTrigger=PropertyChanged}"/>

        <Label Content="{Binding Path=Name}" Height="28" HorizontalAlignment="Left" Margin="111,6,0,0" VerticalAlignment="Top" />
        <Label Content="Score" Height="28" HorizontalAlignment="Left" Margin="6,40,0,0" VerticalAlignment="Top" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="55,42,0,0"  VerticalAlignment="Top" Width="75" Text="{Binding Path=Score, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
    </Grid>
    <Button Content="Start Playing" Height="23" HorizontalAlignment="Left" Margin="254,59,0,0" Name="buttonStartPlay" VerticalAlignment="Top" Width="75" Click="buttonStartPlay_Click" />
</Grid>

以及背后的代码:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {

    private readonly NumberGuesser _numberGuesser;

    public MainWindow() {
        InitializeComponent();
        _numberGuesser = new NumberGuesser();
        DataContext = _numberGuesser;

    }

    private void buttonStartPlay_Click(object sender, RoutedEventArgs e) {

        _numberGuesser.Play();

    }

}
4

2 回答 2

2

你必须从不同的角度来处理问题。与要求用户采取行动的同步运行的方法不同,就像您可能与本地计算机进行交互一样,您需要请求它,然后异步等待某事(例如事件)告诉您用户已完成。(更类似于请求远程计算机的某些东西)

这里有一些东西可以帮助你开始:

public abstract class Player
{
    public string Name { get; private set; }
    public int Score { get; set; }

    public Player(string name)
    {
        Name = name;
    }

    public abstract void ActAsync(int max);

    public virtual event EventHandler<ActEventArgs> ActComplete;
}
public class ActEventArgs : EventArgs
{
    public int Result { get; private set; }
    public ActEventArgs(int result)
    {
        this.Result = result;
    }
}
public class HumanPlayer : Player
{
    public HumanPlayer(string name)
        : base(name)
    {
    }

    public override void ActAsync(int max)
    {
        // button1 should be the user's guess button; anything else you need to do to allow them to interact should be done here
        button1.IsEnabled = true;
        // this will result in a handler being added each time the user is asked to act; you'll actually want to attach just once
        button1.Click += (s, e) =>
            {
                button1.IsEnabled = false;
                if (ActComplete != null)
                    ActComplete(this, new ActEventArgs(int.Parse(data.HumanGuess))); // data.HumanGuess is their input, as a string
            };
    }

    public override event EventHandler<ActEventArgs> ActComplete;
}
public class ComputerPlayer : Player
{
    private readonly Random _random = new Random((int)DateTime.Now.Ticks);

    public ComputerPlayer(string name)
        : base(name)
    {
    }

    public override void ActAsync(int max)
    {
        if (ActComplete != null)
            ActComplete(this, new ActEventArgs(_random.Next(max)));
    }
    public override event EventHandler<ActEventArgs> ActComplete;
}

编辑:与 Jmyster 的解决方案(恕我直言)相比:他更适合简单的交互,即本地用户到本地计算机,但如果您打算将其扩展到多用户场景,事件会更好。

于 2012-05-14T21:51:50.177 回答
1

我不会使用那个 While 循环来玩游戏。我会做这样的事情:

private int numberToGuess = 0;

private void buttonStartPlay_Click(object sender, RoutedEventArgs e) 
{        
    numberToGuess = //Create Random Int;
}  

private void buttonHumanGuess_Click(object sender, RoutedEventArgs e) 
{        
    if(IsAnswerCorrect(//HumanGuess))
         //Human Wins
    else
        ComputerGuess();
        //Or
        MoveToNextPlayer();
}  

private void MoveToNextPlayer()
{
    //Do something to figure out who the next player is
}

private int ComputerGuess()
{
    //Do something to get computer answer
    if(IsAnswerCorrect(//ComputerGuess))
         //Computer Wins
}

private bool IsAnswerCorrect(int answer)
{
    if(answer == numberToGuess)
        return true;
    else
        return false;
}

这是非常通用的,但想法是让用户输入一些内容,然后单击猜测按钮。处理完答案后,运行计算机猜测。

编辑: @蒂姆。解决方案将处理更高级的方法。根据计时器是否是评分的一部分,您可能还需要使用线程。这些应该是您的起点。

于 2012-05-14T21:46:12.983 回答