第23章 控制臺(tái)局域網(wǎng)小游戲-猜數(shù)字

猜數(shù)字游戲是80后很多人在小時(shí)候經(jīng)常玩的一個(gè)邏輯游戲。這個(gè)游戲一般需要兩個(gè)參與者,每個(gè)人秘密聲明一個(gè)各個(gè)位值上數(shù)字不相同的四位數(shù)?;ハ嗖聹y(cè)對(duì)方的數(shù)字,如果猜測(cè)的數(shù)字中位置正確且數(shù)字正確,對(duì)方會(huì)給出一個(gè)A,如果猜測(cè)的數(shù)字中位置不正確但數(shù)字正確,對(duì)方會(huì)給出B。兩個(gè)參與者互相猜測(cè)多輪直至一方完全猜測(cè)出另一方的數(shù)字。
理論上8次就可以猜出對(duì)方的數(shù)字。
比如兩個(gè)玩家"趙四"和"劉能"

動(dòng)作 趙四 劉能
秘密聲明 1024 9102
猜測(cè)對(duì)方 1234(得到劉能答復(fù)0A2B) 1234(得到趙四答復(fù)2A1B)
猜測(cè)對(duì)方 5678(得到劉能答復(fù)0A0B) 5678(得到趙四答復(fù)0A0B)

在這個(gè)步驟:雙方都能排除對(duì)方不包含5678。趙四可以確定劉能的數(shù)字一定含有9和0
根據(jù)分析再次繼續(xù)猜測(cè)

動(dòng)作 趙四 劉能
猜測(cè)對(duì)方 9012(得到劉能答復(fù)2A2B) 1239(得到趙四答復(fù)1A1B)

在這個(gè)步驟:趙四可以確定劉能的四個(gè)數(shù)字,劉能可以確定9不是且4是A
根據(jù)分析再次繼續(xù)猜測(cè)

動(dòng)作 趙四 劉能
猜測(cè)對(duì)方 9102(得到劉能答復(fù)4A0B) 1204(得到趙四答復(fù)2A2B)

此時(shí)趙四猜中劉能的數(shù)字,獲勝。劉能也幾乎快要猜到趙四的數(shù)字。

現(xiàn)在通過所學(xué)的Java知識(shí)完成這樣的游戲設(shè)計(jì)
1. 客戶端首先需要使用賬號(hào)密碼登錄,服務(wù)器連接數(shù)據(jù)庫驗(yàn)證登錄
2. 客戶端若沒有賬號(hào)需要訪問服務(wù)器進(jìn)行注冊(cè),服務(wù)器在數(shù)據(jù)庫中保存賬號(hào)信息
3. 客戶端開始游戲,服務(wù)器生成數(shù)字
4. 客戶端猜測(cè)數(shù)字,服務(wù)器給出nAnB的回應(yīng)
5. 客戶端投降,服務(wù)器給出生成的數(shù)字
6. 客戶端猜中數(shù)字,服務(wù)器記錄用時(shí)并保存最好記錄
7. 客戶端可以查看當(dāng)前速度最快的前10名的排名

1. 數(shù)據(jù)庫

players表

players表

2. 服務(wù)器(GameServer)

DBConfig.properties
數(shù)據(jù)庫配置文件,請(qǐng)根據(jù)實(shí)際情況修改。

IPAdress=localhost
port=3306
database=mydb
username=root
password=root
timezone=GMT%2B8

DBUtil.java
數(shù)據(jù)庫連接工具類

public class DBUtil {
    private static String url;
    private static String username;
    private static String password;
    
    private DBUtil() {}
    
    static {
        // 1.加載驅(qū)動(dòng)
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //讀取配置文件,并完成連接字符串
        Properties p = new Properties();
        try {
            p.load(DBUtil.class.getResourceAsStream("DBConfig.properties"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        String ip = p.getProperty("IPAdress");
        String port = p.getProperty("port");
        String db = p.getProperty("database");
        String tz = p.getProperty("timezone");
        url = "jdbc:mysql://"+ip+":"+port+"/"+db+"?useUnicode=true&characterEncoding=utf-8&serverTimezone="+tz;
        username = p.getProperty("username");
        password = p.getProperty("password");
    }
    
    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return conn;
    }
    public static void close(Connection conn, Statement pst, ResultSet rs) {
        if(rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }   
        }
        if(pst != null) {
            try {
                pst.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }   
        }
        if(conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }   
        }
    }
    public static void close(Connection conn, Statement pst) {
        close(conn, pst, null);
    }   
    public static void close(Connection conn) {
        close(conn, null, null);
    }
}

Player.java
玩家pojo類,映射Players表

public class Player {
    
    private String account;
    private String apass;
    private long besttime;
    
    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    public String getApass() {
        return apass;
    }
    public void setApass(String apass) {
        this.apass = apass;
    }
    public long getBesttime() {
        return besttime;
    }
    public void setBesttime(long besttime) {
        this.besttime = besttime;
    }   
}

PlayerDAO.java
Player持久化類(含部分業(yè)務(wù)邏輯)

public class PlayerDAO {    
    /**
     * 登錄
     * @param p
     * @return
     */
    public boolean login(Player p) {
        Connection conn = DBUtil.getConnection();
        String sql = "select * from players where account = ? and apass = ?";
        PreparedStatement pst = null;
        ResultSet rs = null;
        boolean r = false;
        try {
            pst = conn.prepareStatement(sql);
            pst.setString(1, p.getAccount());
            pst.setString(2, p.getApass());
            rs = pst.executeQuery();
            if(rs.next()) {
                r = true;
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, pst, rs);
        }
        return r;
    }   
    /**
     * 注冊(cè)
     */
    public boolean regist(Player p) {
        Connection conn = DBUtil.getConnection();
        String sql = "insert into players values(?,?,?)";
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement(sql);
            pst.setString(1, p.getAccount());
            pst.setString(2, p.getApass());
            pst.setLong(3, p.getBesttime());
            pst.executeUpdate();
        } catch (SQLException e) {
            return false;
        } finally {
            DBUtil.close(conn, pst);
        }
        return true;
    }
    /**
     * 取得當(dāng)前記錄
     */
    public long getBestTime(String account) {
        Connection conn = DBUtil.getConnection();
        String sql = "select besttime from players where account = ?";
        PreparedStatement pst = null;
        ResultSet rs = null;
        long r = 0;
        try {
            pst = conn.prepareStatement(sql);
            pst.setString(1, account);
            rs = pst.executeQuery();
            while(rs.next()) {
                r = rs.getLong("besttime");
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, pst, rs);
        }
        return r;
    }
    /**
     * 更新記錄
     */
    public boolean updateTime(Player p) {
        Connection conn = DBUtil.getConnection();
        String sql = "update players set besttime = ? where account = ?";
        PreparedStatement pst = null;
        try {
            pst = conn.prepareStatement(sql);
            pst.setLong(1, p.getBesttime());
            pst.setString(2, p.getAccount());
            pst.executeUpdate();
        } catch (SQLException e) {
            return false;
        } finally {
            DBUtil.close(conn, pst);
        }
        return true;
    }
    
    /**
     * 查詢記錄
     */
    public String getList() {
        Connection conn = DBUtil.getConnection();
        String sql = "select account, besttime from players "
                + "where besttime <> 0 order by besttime asc limit 0,10";
        PreparedStatement pst = null;
        ResultSet rs = null;
        StringBuffer sb = new StringBuffer();
        try {
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
            while(rs.next()) {
                sb.append(rs.getString("account"));
                sb.append(",");
                sb.append(rs.getLong("besttime"));
                sb.append(";");
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            DBUtil.close(conn, pst, rs);
        }
        return sb.toString();
    }
}

UserThread.java
核心業(yè)務(wù)處理類,每個(gè)訪問服務(wù)器的對(duì)象都利用該類的對(duì)象創(chuàng)建線程對(duì)應(yīng)處理

public class UserThread extends Thread{
    
    private Socket s;
    
    public UserThread(Socket s) {
        this.s = s;
    }
    
    @Override
    public void run() {
        
        PlayerDAO dao = new PlayerDAO();
        int number = 0;
        long l1 = 0;
        long l2 = 0;
        String ac = null; //記錄線程屬于哪個(gè)用戶
        
        while(true) {
            //通過輸入流獲取客戶端發(fā)來信息
            try {
                DataInputStream dis = new DataInputStream(s.getInputStream());//處理輸入流
                DataOutputStream dos = new DataOutputStream(s.getOutputStream());//處理輸出流
                
                //操作dis就可獲得客戶端的消息,這也是一個(gè)阻塞事件
                String str = dis.readUTF(); 
                String rec = null; //回應(yīng)的消息
                String[] ss = str.split(",");
                //解析暗號(hào)
                int signal = Integer.parseInt(ss[0]);  //將字符串轉(zhuǎn)換成數(shù)字
                
                if(signal == 100) {
                    //登錄
                    String account = ss[1];
                    String apass = ss[2];
                    
                    Player p = new Player();
                    p.setAccount(account);
                    p.setApass(apass);
                    
                    boolean b = dao.login(p);
                    if(b) {
                        rec = "OK";
                        ac = account; //登錄成功的時(shí)候設(shè)置線程擁有者
                    }else {
                        rec = "NG";
                    }
                    
                }else if(signal == 101) {
                    //注冊(cè)
                    String account = ss[1];
                    String apass = ss[2];
                    
                    Player p = new Player();
                    p.setAccount(account);
                    p.setApass(apass);
                    p.setBesttime(0);
                    
                    boolean b = dao.regist(p);
                    if(b) {
                        rec = "OK";
                    }else {
                        rec = "NG";
                    }
                    
                }else if(signal == 102) {
                    //登錄頁面退出
                    break;
                }else if(signal == 103) {
                    //開始游戲(生成數(shù)字)
                    number = StartServer.getRandomNumber(); //得到隨機(jī)數(shù)字
                    System.out.println(number);
                    l1 = System.currentTimeMillis();
                    rec = "OK";
                }else if(signal == 104) {
                    //猜數(shù)字
                    int guess = Integer.parseInt(ss[1]); //用戶猜測(cè)的數(shù)字
                    rec = StartServer.compareNumber(number, guess);
                    //結(jié)果是4A0B,結(jié)束計(jì)時(shí)
                    if(rec.equals("4A0B")) {
                        l2 = System.currentTimeMillis();
                        long t = l2 - l1; //耗時(shí)
                        long n = dao.getBestTime(ac);//數(shù)據(jù)庫中的當(dāng)前記錄
                        //如果當(dāng)前記錄是0  ,t保存
                        //如果t小于當(dāng)前的最好記錄,t保存
                        if(n == 0 || t < n) {
                            Player temp = new Player();
                            temp.setAccount(ac);
                            temp.setBesttime(t);
                            dao.updateTime(temp);
                        }
                        l1 = 0;
                        l2 = 0;
                        number = 0;
                    }
                    
                }else if(signal == 105) {
                    //投降
                    rec = number+"";
                    l1 = 0;
                    l2 = 0;
                    number = 0;
                }else if(signal == 106) {
                    //查看排名
                    rec = dao.getList();
                }else {
                    
                }
                dos.writeUTF(rec); //回應(yīng)客戶端
                dos.flush(); 
                
            } catch (IOException e) {
                break;
            }
        }
    }
}

StartServer.java
服務(wù)器啟動(dòng)類,開啟通信監(jiān)聽和創(chuàng)建用戶處理線程,提供部分工具性質(zhì)方法。

public class StartServer {

    public static void main(String[] args) {
        //創(chuàng)建了ServerSocket服務(wù)器
        ServerSocket ss = null; 
        try {
            ss = new ServerSocket(40000);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
        while(true) {
            try {
                //監(jiān)聽來自客戶端的請(qǐng)求,這是一個(gè)阻塞事件
                Socket s = ss.accept();
                UserThread ut = new UserThread(s);
                ut.start();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }
    
    
    /**
     * 隨機(jī)生成一個(gè)各個(gè)為上數(shù)字不同的四位數(shù)
     * @return
     */
    public static int getRandomNumber() {
        Random r = new Random();
        int q = r.nextInt(9)+1; //[1,9]
        int b,s,g;
        while(true) {
           int temp = r.nextInt(10); //[0,9]
           if(temp != q) {
               b = temp;
               break;
           }
        }
        while(true) {
           int temp = r.nextInt(10); //[0,9]
           if(temp != q && temp != b) {
               s = temp;
               break;
           }
        }
        while(true) {
           int temp = r.nextInt(10); //[0,9]
           if(temp != q && temp != b && temp != s) {
               g = temp;
               break;
           }
        } 
        return q*1000+b*100+s*10+g;
    }
    
    /**
     * 比較n1和n2的結(jié)果
     * @param n1
     * @param n2
     * @return
     */
    public static String compareNumber(int n1, int n2) {
        int[] a = new int[4];
        int[] b = new int[4];
        
        a[0] = n1/1000;
        a[1] = n1/100%10;
        a[2] = n1/10%10;
        a[3] = n1%10;
        
        b[0] = n2/1000;
        b[1] = n2/100%10;
        b[2] = n2/10%10;
        b[3] = n2%10;
        
        int x = 0; //A
        int y = 0; //B
        
        for(int i = 0; i < 4; i++) {
            for(int j = 0; j < 4; j++) {
                if(a[i] == b[j] && i == j) {
                    x++;
                }else if(a[i] == b[j] && i != j) {
                    y++;
                }
            }
        }
        return x+"A"+y+"B";
    }
}

3. 客戶端(GameClient)

StartClient.java
通信,數(shù)字輸入和各項(xiàng)操作。相當(dāng)于客戶端界面

public class StartClient {
    
    public static void main(String[] args) {
        //建議IP和端口通過配置文件獲取
        try {
            Socket s = new Socket("localhost", 40000);
            
            DataOutputStream dos = new DataOutputStream(s.getOutputStream());//處理輸出流
            DataInputStream dis = new DataInputStream(s.getInputStream());//處理輸入流
            
            while(true) {
                /*
                 * 數(shù)據(jù)庫表players表, 賬號(hào),密碼,最好時(shí)間
                 * 
                 * 1. 用戶輸入賬號(hào)和密碼  登錄       
                 * 2. 注冊(cè)
                 * 
                 * 3. 開始游戲 - 猜數(shù)字
                 * 4. 查看排名
                 * 
                 * 5. 退出
                 */
                
                System.out.println("1 - 登錄");
                System.out.println("2 - 注冊(cè)");
                System.out.println("9 - 退出");
                System.out.println("請(qǐng)選擇:");
                Scanner sc1 = new Scanner(System.in);
                int s1 = sc1.nextInt();
                if(s1 == 1) {
                    //登錄
                    //1.提示用戶輸入賬號(hào)
                    Scanner sc2 = new Scanner(System.in);
                    System.out.println("請(qǐng)輸入賬號(hào):");
                    String account = sc2.nextLine();
                    //2.提示用戶輸入密碼
                    Scanner sc3 = new Scanner(System.in);
                    System.out.println("請(qǐng)輸入密碼:");
                    String apass = sc3.nextLine();
                    //3.將賬號(hào)和密碼發(fā)送給服務(wù)器   (服務(wù)器驗(yàn)證)
                    dos.writeUTF(100+","+account+","+apass);
                    dos.flush();
                    //4.接收服務(wù)器的驗(yàn)證結(jié)果   NG-重新執(zhí)行該界面
                    String rec = dis.readUTF();
                    if(rec.equals("OK")) {
                        //OK- 進(jìn)入下一個(gè)界面
                        while(true) {
                            System.out.println("1 - 開始游戲");
                            System.out.println("2 - 查看排名");
                            System.out.println("9 - 退出");
                            System.out.println("請(qǐng)選擇:");
                            Scanner sc4 = new Scanner(System.in);
                            int s2 = sc4.nextInt();
                            if(s2 == 1) {
                                //開始游戲
                                //1.發(fā)送指令,服務(wù)器生成隨機(jī)數(shù)字
                                dos.writeUTF(103+",");
                                dos.flush();
                                
                                String rec1 = dis.readUTF();
                                if(rec1.equals("OK")) {
                                    //2.開始猜
                                    while(true) {
                                        Scanner sc5 = new Scanner(System.in);
                                        System.out.println("請(qǐng)輸入猜測(cè)的四位數(shù)(投降請(qǐng)輸入-1):");
                                        int guess = sc5.nextInt();
                                        if(guess == -1) {
                                            //(2)投降 -1
                                            dos.writeUTF(105+",");
                                            dos.flush();
                                            
                                            String rec2 = dis.readUTF();
                                            System.out.println("服務(wù)器生成的數(shù)字是:"+rec2);
                                            break;
                                        }else {
                                            //(1)輸入數(shù)字 - 猜
                                            dos.writeUTF(104+","+guess);
                                            dos.flush();
                                            
                                            String rec2 = dis.readUTF();
                                            System.out.println("比較結(jié)果:"+rec2);
                                            if(rec2.equals("4A0B")) {
                                                System.out.println("恭喜您猜對(duì)了");
                                                break;
                                            }
                                        }
                                    }
                                    
                                }else {
                                    System.out.println("服務(wù)器出現(xiàn)問題");
                                }
                                
                            }else if(s2 == 2) {
                                //查看排名
                                dos.writeUTF(106+",");
                                dos.flush();
                                
                                //接收消息
                                String rec2 = dis.readUTF();
                                String[] ps = rec2.split(";");
                                for(String p : ps) {
                                    String[] ts = p.split(",");
                                    for(String t : ts) {
                                        System.out.print(t);
                                        System.out.print("\t");
                                    }
                                    System.out.println();
                                }
                                
                                
                            }else if(s2 == 9) {
                                //退出
                                dos.writeUTF(102+",");
                                dos.flush();
                                System.exit(0);
                            }
                        }   
                    }else {
                        System.out.println("賬號(hào)密碼錯(cuò)誤");
                    }
                    
                }else if(s1 == 2) {
                    //注冊(cè)
                    //1.提示用戶輸入賬號(hào)
                    Scanner sc2 = new Scanner(System.in);
                    System.out.println("請(qǐng)輸入賬號(hào):");
                    String account = sc2.nextLine();
                    //2.提示用戶輸入密碼
                    Scanner sc3 = new Scanner(System.in);
                    System.out.println("請(qǐng)輸入密碼:");
                    String apass = sc3.nextLine();
                    //3.將賬號(hào)和密碼發(fā)送給服務(wù)器   (服務(wù)器保存)
                    dos.writeUTF(101+","+account+","+apass);
                    dos.flush();
                    
                    //4.接收服務(wù)器的驗(yàn)證結(jié)果   
                    String rec = dis.readUTF();
                    if(rec.equals("OK")) {
                        //注冊(cè)成功
                        System.out.println("注冊(cè)成功");
                    }else {
                        System.out.println("注冊(cè)失?。嘿~號(hào)被使用");
                    }
                }else if(s1 == 9) {
                    //退出
                    dos.writeUTF(102+",");
                    dos.flush();
                    break;
                }
            }       
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容