[PYTHON] I made a Numer0n battle game in Java (I also made AI)

I tried to make a Numer0n battle game in Java

Introduction

This time, in a university class, I had the task of creating something in Java via communication between a server and a client, so when I was a high school student, I decided to make a Numer0n game that I used to play during class. When I was a high school student, I was so addicted to the Numer0n game that I enjoyed manually calculating the probability of becoming 〇EAT〇BITE in the first move. .. ..

If you are reading this article, I think you know the basic rules of Numer0n, so I will omit that part. Numeron Wikipedia

Development environment

Java:version 7 Eclipse: Juno 4.2 OS: windows10

Development policy

What I want to implement in this system is

  1. Communicate between server and client, allow multiple clients to access at the same time, create rooms, and play against each other
  2. Make it possible to play a strong computer match (implementation of algorithm)
  3. Respond to typos and duplicate numbers
  4. Since it is a turn-based game, it will receive input alternately.

code

If you put all the code, it will be long, so this time I will only post the Channel class that is in charge of sending and receiving on the server side and the Numer0nAI class that implements the computer algorithm. All classes and presentation materials (PowerPoint) are posted on GitHub, so please take a look if you like! Numeron AI is also implemented in python, so if you use python often, please do that too! Numer0n (GitHub) made with Java Python's Numer0nAI (GitHub)

About the Channel class

Upon confirming the input from the client, the server creates a Channel, and the Channel and the client interact with each other. Thanks to that, even if an unintended exception occurs to the client, the original server will not go down and the connection of other clients will be maintained.

Channel.java


package server;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Channel extends Thread {
	JUDGE judge = new JUDGE();
	Server server;
	Socket socket = null;
	BufferedReader input;
	OutputStreamWriter output;
	String handle;
	String playertype;
	String roomnumber;
	String mynumber;
	String tekinumber;
	boolean turn;

	String ex = "926";//First prediction of AI
	String ca ="0123456789";//candidate number: 0-9 at first
	String ex_number;
	List<String> old_list = new ArrayList<>();

	final char controlChar = (char)05;
	final char separateChar = (char)06;

	Channel(Socket s,Server cs){
		this.server = cs;
		this.socket = s;
		this.start();
	}

	synchronized void write(String s){
		try{
			output.write(s + "\r\n");
			output.flush();
		}catch(IOException e){
			System.out.println("Write Err");
			close();
		}
	}

	public void run(){
		List<String> s_list = new ArrayList<>();//A list that receives and stores input from clients
		String s;
		String opponent = null;
		try{
			input = new BufferedReader(
					new InputStreamReader(socket.getInputStream()));
			output = new OutputStreamWriter(socket.getOutputStream());
			write("# Welcome to Numr0n Game");
			write("# Please input your name");
			handle = input.readLine();
			System.out.println("new user: "+ handle);
			while(true){//HOST or GUEST Waiting for input
				write("INPUT YOUR TYPE(HOST or GUEST or AI)");
				playertype = input.readLine();
				if(playertype.equals("HOST")){
					Random rnd = new Random();
					s = String.valueOf(rnd.nextInt(100)+100);
					write("[HOST]Room number: "+s);
					break;
				}else if(playertype.equals("GUEST")){
					write("[GUEST]Please enter the room number");
					s = input.readLine();
					write("[GUEST]Room number: "+s);
					break;
				}else if(playertype.equals("AI")){
					write("[vs AI mode]");
					Random rnd = new Random();
					s = String.valueOf(rnd.nextInt(100)+100);
					write("[HOST]Room number: "+s);
					break;
				}else{
					write("Error entering room number");
				}
			}

			roomnumber  = s;	//Determining room number
			System.out.println(roomnumber);
			write("Waiting for an opponent");

			if(playertype.equals("AI")){
				//Play against AI
				write("Decide on your own number (*3-digit number*From 0 to 9*No number cover)");

				boolean firstnum = false;
				while(firstnum == false){//Does your first number meet the above criteria?
					mynumber = input.readLine();
					firstnum = judge.isNumber(mynumber);
				}
				write("My numbers: "+ mynumber);
				write(handle + "Start from");
				tekinumber="864";
				NumeronAI numeron = new NumeronAI();
				while(true){
					//Game Start
					boolean finish = false;

					s = input.readLine();

					if(s == null){
						close();
					}else{
						System.out.println(s);
						boolean numsuccess = judge.isNumber(s);//Numbers in the definition
						if (numsuccess) {
							JUDGE eatbite = judge.EatBite(s, tekinumber);
							finish = judge.Finish(eatbite.eat);//Whether it became 3eat
							write("["+ s +"] eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));

							//AI turn from here
							JUDGE AIeatbite = judge.EatBite(ex, mynumber);

							NumeronAI squeeze = numeron.Squeeze(AIeatbite.eat,AIeatbite.bite,ex,ca,old_list);
							if(squeeze.new_can_list.size()<300){
								//System.out.println(Arrays.toString(squeeze.new_can_list.toArray()));
								//System.out.println(squeeze.can_num);
								ex_number = numeron.choice(squeeze.new_can_list,squeeze.can_num);
							}else{
								Random rnd = new Random();
								int index = rnd.nextInt(100);
								ex_number = squeeze.new_can_list.get(index);
							}
							old_list = new ArrayList<>(squeeze.new_can_list);
							//System.out.println("Number of remaining candidates: " + String.valueOf(old_list.size()));
							write("AI prediction value:" + ex + "		[Number of remaining candidates: " + String.valueOf(old_list.size())+"Pieces]");
							//System.out.println("AI prediction value: "+ ex);
							if(mynumber.equals(ex)){
								write("#################you lose#################");
							}
							ex = ex_number;

								//This is the AI turn
						} else {
							write(" did not send such a number");
						}
					}
					if(finish){
						write("#################you win#################");
					}
				}

			}else{//vs human
				while(opponent == null){//Waiting for an opponent
					opponent = server.findopponent(handle,roomnumber);
				}
				//write("The opponent has been decided");
				write("Decide on your own number (*3-digit number*From 0 to 9*No number cover)");

				boolean firstnum = false;
				while(firstnum == false){//Does your first number meet the above criteria?
					mynumber = input.readLine();
					firstnum = judge.isNumber(mynumber);
				}
				write("My numbers: "+ mynumber);

				while(tekinumber == null){//Wait until you get the enemy numbers
					tekinumber = server.findopponentnumber(handle, roomnumber);
				}

				if(playertype.equals("HOST")){
					turn = true;
				}else{
					turn =false;
				}

				write("Start from the HOST player");
				while(true){
					//Game Start
					boolean finish = false;
					while(true){
						//Confirmation of turn
						s_list.add(input.readLine());//Enter the input
						turn = server.isTurn(handle);//Confirmation of turn
						if(turn == true){
							break;
						}
					}

					s = s_list.get(s_list.size()-1);
					s_list.clear();

					if(s == null){
						close();
					}else{
						System.out.println(s);
						boolean numsuccess = judge.isNumber(s);//Numbers in the definition
						if (numsuccess) {
							//write("judge ok");
							boolean connectsuccess = server.singleSend(opponent,"[Prediction of the other party] "+s);//There is a partner
							if(connectsuccess){
								//write("There is a partner");
								JUDGE eatbite = judge.EatBite(s, tekinumber);
								finish = judge.Finish(eatbite.eat);//Whether it became 3eat
								write("		[My prediction]"+ s +" eat: " +String.valueOf(eatbite.eat) +" bite: "+ String.valueOf(eatbite.bite));
								server.ChangeTurn(handle, opponent);//Switch turn
							}else{
								write("did not find opponent");
							}
						} else {
							write(" did not send such a number");
						}


						}
					if(finish){
						write("#################you win#################");
						server.singleSend(opponent, "#################you lose#################");
					}

					}
			}



		}catch(IOException e){
			System.out.println("Exception occurs in Channel: "+handle);
		}
	}
	public void close(){
		try{
			input.close();
			output.close();
			socket.close();
			socket = null;
			//server.broadcast("Line disconnection: " + handle);
		}catch(IOException e){
			System.out.println("Close Err");
		}
	}



}

About Numeron AI class

The Numeron AI class is a class that implements the prediction part of a computer. The prediction consists of the Squeeze method that narrows down the possible candidates from the obtained EAT-BITE information, the Choice method that selects a good move from the candidates, and the count_cand method that calculates a good move. A hand that looks good is the one with the smallest number of expected correct answer candidates from all the combinations of EAT-BITE that are returned when a certain hand is selected. For details, see Thinking about how to win numer0n. I'm implementing something close to this theory! By the way, I think the average number of calls is about 5 or 6 (experience).

NumeronAI.java


package server;

import java.util.ArrayList;
import java.util.List;

public class NumeronAI {
	List<String> new_can_list = new ArrayList<>();//candidate list
	String can_num;//candidate number


	//Narrow down to the number of possible candidates
	public NumeronAI Squeeze(int eat,int bite,String pred_num,String ca_num,List<String> old_list){
		NumeronAI squeeze = new NumeronAI();
		List<String> can_list = new ArrayList<>();
		List<String> li = new ArrayList<>();

		if(eat == 0 && bite == 0){
			//System.out.println("--------" + String.valueOf(ca_num.length()));
			for(int i = 0; i<ca_num.length();i++){
				if(ca_num.charAt(i) != pred_num.charAt(0) && ca_num.charAt(i) != pred_num.charAt(1) && ca_num.charAt(i) != pred_num.charAt(2)){
					li.add(String.valueOf(ca_num.charAt(i)));
				}
			}
			ca_num ="";
			StringBuilder builder = new StringBuilder();
			for(String num : li){
				builder.append(num);
			}
			ca_num = builder.substring(0,builder.length());

			for(int i = 0;i<ca_num.length();i++){
				for(int j = 0;j<ca_num.length();j++){
					for(int k = 0;k<ca_num.length();k++){
						if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=ca_num.charAt(k) && ca_num.charAt(j)!=ca_num.charAt(k)){
							can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(ca_num.charAt(k)));
						}
					}
				}
			}
		}else if(eat ==0 && bite ==1){
			for(int i = 0;i<ca_num.length();i++){
				for(int j = 0;j<ca_num.length();j++){
					if(ca_num.charAt(i) != ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
						can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(j)));
						can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(0)));
						can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
						can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(1)));
						can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
						can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(j)));
					}

				}
			}
		}else if(eat ==0 && bite ==2){
			for(int i = 0;i<ca_num.length();i++){
				if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
					can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
					can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
					can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
					can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0)));
					can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
					can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i)));
				}
			}
		}else if(eat == 0 && bite ==3){
			can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0)));
			can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1)));

		}else if(eat == 1 && bite ==0){
			for(int i = 0;i<ca_num.length();i++){
				for(int j = 0;j<ca_num.length();j++){
					if(ca_num.charAt(i)!=ca_num.charAt(j) && ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) &&
							ca_num.charAt(i)!=pred_num.charAt(2) && ca_num.charAt(j)!=pred_num.charAt(0) &&
							ca_num.charAt(j)!=pred_num.charAt(1) && ca_num.charAt(j)!=pred_num.charAt(2)){
					can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(j)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(ca_num.charAt(j))+String.valueOf(pred_num.charAt(2)));
					}
				}
			}

		}else if(eat ==1 && bite ==1){
			for(int i = 0;i<ca_num.length();i++){
				if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
					can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1)));
					can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(ca_num.charAt(i)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
					can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
					can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
				}
			}

		}else if(eat ==1 && bite ==2){
			for(int i = 0;i<ca_num.length();i++){
				can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1)));
				can_list.add(String.valueOf(pred_num.charAt(2))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0)));
				can_list.add(String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(2)));
			}

		}else if(eat ==2 && bite ==0){
			for(int i = 0;i<ca_num.length();i++){
				if(ca_num.charAt(i)!=pred_num.charAt(0) && ca_num.charAt(i)!=pred_num.charAt(1) && ca_num.charAt(i)!=pred_num.charAt(2)){
					can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(pred_num.charAt(1))+String.valueOf(ca_num.charAt(i)));
					can_list.add(String.valueOf(pred_num.charAt(0))+String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(2)));
					can_list.add(String.valueOf(ca_num.charAt(i))+String.valueOf(pred_num.charAt(1))+String.valueOf(pred_num.charAt(2)));
				}
			}

		}else if(eat ==3 && bite ==0){
			can_list.add(pred_num);
		}

		if(old_list.size()!=0){
			for(String num : can_list){
				if(old_list.contains(num)){
					squeeze.new_can_list.add(num);
					squeeze.can_num =ca_num;
				}
			}

		}else{
			squeeze.new_can_list = can_list;
			squeeze.can_num = ca_num;
		}
		//System.out.println(can_num);
		return squeeze;
	}


	//Calculate the expected number of candidates
	public double count_cand(String pred_num,String ca_num,List<String> ca_list){
		double ave_ca = 0;
		int[][] info_list = {{0,0},{0,1},{0,2},{0,3},{1,0},{1,1},{1,2},{2,1},{3,0}};
		int sum_ex = 0;
		int sum_ex2 = 0;
		List<String> old_count_list = new ArrayList<>(ca_list);
		String ca_count_num = ca_num;
		NumeronAI squeeze2 = new NumeronAI();
		for(int[] info :info_list){
			squeeze2 = Squeeze(info[0],info[1],pred_num,ca_count_num,old_count_list);
			sum_ex=sum_ex+squeeze2.new_can_list.size();
			sum_ex2=sum_ex2+squeeze2.new_can_list.size()^2;
		}
		if(sum_ex!=0){
			ave_ca=sum_ex2/sum_ex;
		}
		return ave_ca;
	}


	//Select the number with the smallest expected number of candidates
	public String choice(List<String> ca_list,String ca_num){
		List<Double> ave_list = new ArrayList<>();
		int min_index =0;
		try{
			for(String num :ca_list){
				double ave_ca = count_cand(num,ca_num,ca_list);
				ave_list.add(ave_ca);
			}
			double min =ave_list.get(0);
			for(int i =0;i<ave_list.size();i++){
				double val = ave_list.get(i);
				if(min > val){
					min = val;
					min_index = i;
				}
			}
			return ca_list.get(min_index);
		}catch(Exception e){
		System.out.println("Choice Miss:" + e);
		return "111";
	}
	}


}

Execution result

実行結果.PNG This time, I was hit in 6 turns.

Impressions

I haven't written much about Java, but I think I've done what I wanted to make. However, I haven't reached the level of practicing knowledge of design patterns yet, so I realized that I need to study. (Design pattern is difficult ...) Writing Numer0n's AI (I don't want to call it AI) by myself is recommended for those who know Numer0n and want to make something because the rules are easy to understand!

Also, I created only the Numeron AI part in python, so I have not written Java, but if you can understand it with python, please refer to it.

This is my first post on Qiita, so if you have any improvements to this article, please leave a comment <(_ _)>

I will do my best to output little by little from now on!

Recommended Posts

I made a Numer0n battle game in Java (I also made AI)
〇✕ I made a game
I made a simple typing game with tkinter in Python
I made a puzzle game (like) with Tkinter in Python
I made a game called Battle Ship using pygame and tkinter
I made a life game with Numpy
I made a roguelike game with Python
I tried playing a typing game in Python
I wrote a class in Python3 and Java
I made a Caesar cryptographic program in Python.
I made a bin picking game with Python
I made a prime number generation program in Python
I made a Christmas tree lighting game with Python
I made a vim learning game "PacVim" with Go
I made a script to put a snippet in README.md
I made a prime number generation program in Python 2
I made a school festival introduction game using Ren’py
I made a falling block game with Sense HAT
I made a quick feed reader using feedparser in Python
I made a command to generate a table comment in Django
I made a face diagnosis AI for a female professional golfer ③
I made a python text
I made a discord bot
An amateur made his own game AI from scratch in a free study during summer vacation
I tried to implement a misunderstood prisoner's dilemma game in Python
I made a prime number table output program in various languages
I made a poker game server chat-holdem using websocket with python
I made a command to display a colorful calendar in the terminal
I made a C ++ learning site
I get a UnicodeDecodeError in mecab-python3
I made a Line-bot using Python!
I made a wikipedia gacha bot
I get a KeyError in pyclustering.xmeans
Numer0n with items made in Python
I made a fortune with Python.
I made a CUI-based translation script
Zura made like a life game
I made a daemon with Python
I made a plugin to generate Markdown table from csv in Vim
I made a web application in Python that converts Markdown to HTML
I made a Discord bot in Python that translates when it reacts
I made a poop AI drill. Please do your summer vacation homework.
I made a CLI tool to convert images in each directory to PDF
I made a kind of simple image processing tool in Go language.
I made a script in python to convert .md files to Scrapbox format
[IOS] I made a widget that displays Qiita trends in Pythonista3. [Python]
I made a program to check the size of a file in Python
I made a mistake in fetching the hierarchy with MultiIndex of pandas
I tried to implement a card game of playing cards in Python
I made a new AWS S3 bucket
I made a dash docset for Holoviews
I want to print in a comprehension
I touched "Orator" so I made a note
I made a character counter with Python
I tried playing a ○ ✕ game using TensorFlow
Beginner: I made a launcher using dictionary
I made a conversation partner like Siri
I made a script to display emoji
I made a Hex map with Python
I made a stamp generator with GAN
I made a browser automatic stamping tool.