From 9b0ead9695002c6b19af530f6593e02e4cc25dee Mon Sep 17 00:00:00 2001 From: LeeJooHwan Date: Thu, 18 Jun 2020 15:26:21 +0900 Subject: [PATCH 1/5] Add files via upload --- WarGameClient.java | 172 ++++++++++++++++++++++++------ WarGameGUI.java | 14 ++- WarGameImpl.java | 254 +++++++++++++++++++++++++++++++++++++-------- WarGameServer.java | 150 +++++--------------------- 4 files changed, 392 insertions(+), 198 deletions(-) diff --git a/WarGameClient.java b/WarGameClient.java index 02a53f4..c9b431b 100644 --- a/WarGameClient.java +++ b/WarGameClient.java @@ -1,21 +1,31 @@ import java.rmi.AccessException; import java.rmi.Naming; import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; -import java.util.Scanner; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.net.InetAddress; import java.net.MalformedURLException; +import java.net.UnknownHostException; import java.rmi.NotBoundException; -import java.net.MalformedURLException; +import java.rmi.server.UnicastRemoteObject; +import java.util.ArrayList; +import java.util.Scanner; import java.rmi.NotBoundException; + + + public class WarGameClient implements Runnable {//handle connection and use rmi function here from client side // private static final long serialVersionUID = 1L; + private static final int PORT = 2019; + private String id; boolean chkLog=false; private WarGame server; boolean boolean_ReadyBtnStatus; boolean boolean_HitBtnStatus; boolean boolean_DropBtnStatus; - + ArrayList client; + WarGameGUI gui; protected WarGameClient(WarGame wg,String id,String pw){ boolean_ReadyBtnStatus=false; boolean_HitBtnStatus=false; @@ -28,72 +38,176 @@ protected WarGameClient(WarGame wg,String id,String pw){ System.out.println("wrong id or wrong passworld"); System.exit(0); } - - + + }catch(RemoteException re) { System.out.println("RemoteException: "+re); - + }catch(java.lang.ArithmeticException ae) { System.out.println("java.lang.ArithmeticException: "+ae); } + + } + void drop() { + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + try { + server.doDrop(id);//id가 필요한지 모르겠음... + }catch(Exception e) { + e.printStackTrace(); + } + } + void hit() { + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + try { + server.doHit(id); + }catch(Exception e) { + e.printStackTrace(); + } } - public void run() { if(chkLog) { System.out.println(id); - WarGameGUI gui=new WarGameGUI(id); + gui=new WarGameGUI(id); + gui.deactivatedHitDropBtn(); try { while(server.checkAllReady()==false) { boolean_ReadyBtnStatus=gui.returnReadyBtnStatus(); - server.setReadyStatus(id, boolean_ReadyBtnStatus); + server.setReadyStatus(id, boolean_ReadyBtnStatus); } - - }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯.. 예외처리 사이즈가 + + }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯.. 예외처리 사이즈가 e.printStackTrace(); } + gui.activatedHitDropBtn(); System.out.println("game start");//this will be deleted in the end gui.setGameInfo("game start"); gui.deactivateReadyBtn(); - -// try { -// do{//게임중... do while인 이유는 마지막 카드가 공격이어서 기회가 남아 있을수도 있다.. -// //////////////////// -// }while(server.checkStatus()); -// }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯..예외처리 사이즈가 커 + try {//최종 참가자 리스트 추가 + client=server.getClientList(); + String tmp=client.get(0); + String tmp2=client.get(1); + gui.setPlayerList("Player1: "+tmp); + gui.setPlayerList("Player2: "+tmp2); + }catch(Exception e) { + e.printStackTrace(); + } +// try {//턴 돌아갈때 마다 올라가는 것으로 바꿔야 할것 같다. 1번에 국한되지 말고... +// if(id.contentEquals(server.whosTurn())) { +// String tmp=server.whosTurn(); +// sendMsgToAll(tmp+"'s turn\n"); +// +// } +// +//// System.out.println(tmp+"'s turn. good luck~!"); +//// gui.setGameInfo(tmp+"'s turn. good luck~!"); +//// String msg=receiveMsg(); +//// gui.setMsgView(msg); +// +// +// }catch(Exception e) { // e.printStackTrace(); // } + try { + while(server.checkEndingStatus()){//게임중... + while(id.equals(server.whosTurn())){//자신의 턴 동안... + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + if(boolean_DropBtnStatus) { + drop(); + gui.setMsgView("플레이어 "+ id+" 가 drop을 했습니다."); +// server.doDrop(id);//id는 안쓰고, serverImpl에서 turn보고 알아서 판단하고 있음. 필요 없는거 확실해지면 그때 지우기. + gui.setDropStatusFalse();//버튼 눌리면 true로 변하기 때문에 변경 안하면 항상 true인 효과 한번 버튼 누르면 다시 false로 변환 + //server.changeTurn(); + gui.repaint(); + }else if(boolean_HitBtnStatus) { + hit(); +// server.doHit(id); + gui.setHitStatusFalse(); + + }else { + + } + } + if(!id.equals(server.whosTurn())){//player가 잘못누르는 경우... + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + if(boolean_DropBtnStatus){ + System.out.println("it's not your turn..please wait"); + gui.setGameInfo("it's not your turn..please wait"); + gui.setDropStatusFalse(); + } + if(boolean_HitBtnStatus){ + System.out.println("it's not your turn..please wait"); + gui.setGameInfo("it's not your turn..please wait"); + gui.setHitStatusFalse(); + } + } + } + +// gui.deactivatedHitDropBtn(); + + }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯..예외처리 사이즈가 커 + e.printStackTrace(); + } + } + } + public void sendMsgToAll(String str) {//행동 취하고 나면 반드시 해당함수를 써서 메시지를 보내야한다. 그리고 바로 receiveMSG도 작동해야한다. + try { + server.sendMsg(str); + + }catch(Exception e) { + e.printStackTrace(); } } +// public String receiveMsg() { +// String msg=""; +// try { +// msg=server.receiveMsg(); +//// gui.setMsgView(msg+"\n"); +// +// }catch(Exception e) { +// e.printStackTrace(); +// +// } +// return msg; +// } public static void main(String[] args) { String mServer="127.0.0.1"; -// String mServer=args[0]; String mServName="WarGame"; - + System.out.println("Remote Method Invocate to "+mServer+", service name: "+mServName); - + try { + System.setProperty("javax.net.ssl.trustStore", "trustedcerts"); + System.setProperty("javax.net.ssl.trustStorePasssword", "123456"); String id; String pw; Scanner sc=new Scanner(System.in);//this is for temporary - System.out.println("enter id: "); + System.out.print("enter id: "); id=sc.nextLine(); - System.out.println("enter pw: "); + System.out.print("enter pw: "); pw=sc.nextLine(); + + + Registry registry = LocateRegistry.getRegistry( + InetAddress.getLocalHost().getHostName(), PORT, + new RMISSLClientSocketFactory()); - WarGame wg=(WarGame)Naming.lookup("rmi://"+mServer+":1099/"+mServName); - new Thread(new WarGameClient(wg,id,pw)).start(); - - }catch(MalformedURLException mue) { - System.out.println("MalformedURLException: "+mue); + WarGame c=(WarGame)registry.lookup("WarGame"/*"rmi://"+mServer+":1099/"+mServName*/); + new Thread(new WarGameClient(c,id,pw)).start(); + }catch(RemoteException re) { System.out.println("RemoteException: "+re); }catch(NotBoundException nbe) { System.out.println("NotBoundException: "+nbe); }catch(java.lang.ArithmeticException ae) { System.out.println("java.lang.ArithmeticException: "+ae); + } catch (UnknownHostException e) { + System.out.println("UnknownHostException: "+e); } } - + } + diff --git a/WarGameGUI.java b/WarGameGUI.java index a695d46..96a37e8 100644 --- a/WarGameGUI.java +++ b/WarGameGUI.java @@ -234,16 +234,24 @@ public void setPlayerList(String str) {//참가자 리스트를 보여줌 public void deactivateReadyBtn() { readyBtn.setEnabled(false); } + public void deactivatedHitDropBtn() { + hitBtn.setEnabled(false); + dropBtn.setEnabled(false); + } + public void activatedHitDropBtn() { + hitBtn.setEnabled(true); + dropBtn.setEnabled(true); + } + public void actionPerformed(ActionEvent ae) { try { if(ae.getSource()==dropBtn) { // System.out.println("drop"); boolean_DropBtn=true; - - } else if(ae.getSource()==hitBtn) { - System.out.println("hit"); + boolean_HitBtn=true; +// System.out.println("hit"); } // else if(ae.getSource()==tf_Send) { // String msg=tf_Send.getText(); diff --git a/WarGameImpl.java b/WarGameImpl.java index a3908fe..0544dd9 100644 --- a/WarGameImpl.java +++ b/WarGameImpl.java @@ -8,37 +8,48 @@ import java.util.Set; public class WarGameImpl extends UnicastRemoteObject implements WarGame { + + private static final int PORT = 2019; private static final long serializedversion=1L; private String clientID[]= {"aaa","bbb"}; private String clientPassword[]= {"1234","1234"}; - private ArrayList clientList; +// private ArrayList clientList; private Game game; private boolean turn=true; + private String msg; private ArrayList deck0,deck1,deck2; private int clientCnt=0; + //private HashMap clientStatus;//어떤 클라이언트의 순서인지 확인할 수 있다(이름,0)/(이름,1) -> 전자는 비활성화, 후자는 활성화 + private ArrayList client; private HashMap readyStatus; private boolean boolean_readyStatus[]; + private int attackCount=-1; + + private boolean isAttack = false; + private int dropCount = 0; + protected WarGameImpl() throws RemoteException{ super(); //clientList=new ArrayList(); + msg=""; game=new Game(); deck1=game.returnDeck1(); deck2=game.returnDeck2(); - deck0=null; + deck0=game.returnDeck0(); readyStatus=new HashMap(); - + client=new ArrayList(); + //clientStatus=new HashMap(); // boolean_readyStatus=new boolean[2]; // boolean_readyStatus[0]=false; // boolean_readyStatus[1]=false; //System.out.println(deck1);//test } - public synchronized boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException{ + public synchronized boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException{ //id, pw 확인 boolean checkLog=false; for(int i=0;i getClientList() throws RemoteException{ + return client; + } + @Override + public synchronized void sendMsg(String msg) throws RemoteException{ + this.msg=msg; + } + @Override + public synchronized String receiveMsg() throws RemoteException{ + return msg; + } + @Override + public int checkGameStatus() throws RemoteException {//drop을 해야할지 hit를 해야할지, 공격중인 상황인지 평시 상황인지 판단한담에 거기에 맞춰 int리턴 + // TODO Auto-generated method st + int loc = deck0.size(); + String value=deck0.get(loc-1).returnValue(); + System.out.println("Value: "+value); + if(value=="K")//공격카드의 값만큼 리턴 + return 3; + else if(value.equals("Q")) + return 2; + else if(value.equals("J")) + return 1; + else if(value.equals("A")) + return 3; + else if(value.equals("2")) { + System.out.println("2임"); + return 2; + } + else { + System.out.println("Value????: "+value); + return -1;//평시 상태 + } + } + public boolean checkEndingStatus() throws RemoteException{ //deck이 비면 끝남 if(deck1.isEmpty()==true || deck2.isEmpty()==true) return false;//game over else return true; } - public synchronized void setReadyStatus(String id,boolean status) throws RemoteException{ + public String whosTurn() throws RemoteException{ //누구의 턴인지 반환 + if(turn==true) + return client.get(0); + else + return client.get(1); + } + public void changeTurn() throws RemoteException{ + turn=!turn; + } + public synchronized void setReadyStatus(String id,boolean status) throws RemoteException{//플레이어 각각이 레디했는지 확인 int tmp=0; if(status==true) tmp=1; @@ -71,61 +125,173 @@ public synchronized void setReadyStatus(String id,boolean status) throws RemoteE readyStatus.put(id, tmp); else { readyStatus.put(id,tmp); + } } - public synchronized boolean checkAllReady() throws RemoteException{ + public synchronized boolean checkAllReady() throws RemoteException{//player 2명 전부 레디 했는지 확인 int cnt=0; Iterator> itr=readyStatus.entrySet().iterator(); Set>set=readyStatus.entrySet(); while(itr.hasNext()) { Map.Entrye=(Map.Entry)itr.next(); - if(e.getValue()==1) + if(e.getValue()==1) { cnt++; + } } - if(cnt==2) + if(cnt==2) { + client.addAll(readyStatus.keySet()); +// clientStatus.put(client.get(0),1); +// clientStatus.put(client.get(1),0); return true; + } + else return false; } - public synchronized void doDrop() throws RemoteException{ + public synchronized void doDrop(String id) throws RemoteException{ + Card c=null; if(turn==true) {//player 1's drop - c=deck1.get(0); - if(c==null) { - System.out.println("Player2 win!!"); - } - deck0.add(c); - + if(isAttack == false) { + System.out.println("player 1 drop!"); + if(deck1.size() == 0) { + System.out.println("Player2 win!!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + + System.out.println("뽑힌카드 : " +c); + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 1 drop! : Attack"); + if(deck1.size() == 0) { + System.out.println("Player2 win!!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); + + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck2.add(deck0.get(i)); + } + deck0 = new ArrayList(); + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); + + } + } + else { + isAttack = true; + dropCount = 0; + attackCount = checkGameStatus(); + turn = !turn; + } + System.out.println("뽑힌카드 : " +c); + } + }else {//player 2's drop - c=deck2.get(0); - if(c==null) { - System.out.println("Player1 win!!"); + if(isAttack == false) { + System.out.println("player 2 drop!"); + if(deck2.size() == 0) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + + System.out.println("뽑힌카드 : " +c); + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 2 drop! : Attack"); + if(deck2.size() == 0) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); + + deck0.add(c); + + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck1.add(deck0.get(i)); + } + deck0 = new ArrayList(); + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); + } + } + else { + isAttack = true; + dropCount = 0; + attackCount = checkGameStatus(); + turn = !turn; + } + System.out.println("뽑힌카드 : " +c); } - deck0.add(c); } } - public synchronized void doHit() throws RemoteException{ + public synchronized void doHit(String id) throws RemoteException{ + System.out.println("hit이 실행됨"); //플레이어 구분해서 해야하는데 아직 못함. Card []c=new Card[2]; - c[0]=deck0.get(0); - c[1]=deck0.get(1); - if(c[0].returnType()==c[1].returnType()) { - System.out.println("Hit Success!!"); - } - else + if(deck0.size() < 2) { System.out.println("Hit Fail..."); - - - } - public boolean changeTurn() { - return !turn; + } + else { + c[0]=deck0.get(0); + c[1]=deck0.get(1); + if(c[0].returnType()==c[1].returnType()) { + System.out.println("Hit Success!!"); + } + else + System.out.println("Hit Fail..."); + + } } + public void pop() { if(turn==true) { - + deck1.remove(0); }else { - + deck2.remove(0); } } public void push() { diff --git a/WarGameServer.java b/WarGameServer.java index f41b75e..0e3cd45 100644 --- a/WarGameServer.java +++ b/WarGameServer.java @@ -4,137 +4,43 @@ import java.io.*; import java.rmi.Naming; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.UnicastRemoteObject; -public class WarGameServer { +public class WarGameServer extends UnicastRemoteObject { public int clientCnt=0; -// private WarGameServerRunnable client[]=new WarGameServerRunnable[2]; - public WarGameServer(String server,String servName) { - try { - WarGame wg=new WarGameImpl(); - Naming.rebind("rmi://"+server+":1099/"+servName, wg); - }catch(Exception e) { - System.out.println("Trouble: "+e); - } + private static final int PORT = 2019; + + public WarGameServer(String server,String servName) throws Exception{ + super(PORT, + new RMISSLClientSocketFactory(), + new RMISSLServerSocketFactory()); + } public static void main(String[] args) throws UnknownHostException { -// String mServer=InetAddress.getLocalHost().getHostName(); -// String mServer=args[0]; String mServer="127.0.0.1"; String mServName="WarGame"; System.out.println("started at"+mServer+"and use default port(1099). service name: "+mServName); - new WarGameServer(mServer,mServName); + + try { + + //SSL-based registry 생성 + Registry registry = LocateRegistry.createRegistry(PORT, new RMISSLClientSocketFactory(), new RMISSLServerSocketFactory()); + + //Create new impl object + WarGameImpl warGameImpl = new WarGameImpl(); + + registry.bind("WarGame", warGameImpl); + + System.out.println("WarGame bound in registry"); + + } catch (Exception e) { + System.out.println("WarGame Error : " + e.getMessage()); + e.printStackTrace(); + } } } -// public int whoClient(int clientID) { -// for (int i = 0; i < clientCnt; i++) -// if (client[i].getClientID() == clientID) -// return i; -// return -1; -// } -// public void putClient(int clientID, String inputLine) { -// for (int i = 0; i < clientCnt; i++) -// if (client[i].getClientID() == clientID) { -// System.out.println("writer: "+clientID); -// } else { -// System.out.println("write: "+client[i].getClientID()); -// client[i].out.println(inputLine); -// } -// } - //this is about chatting. so.. -// public void addClient(ServerSocket serverSocket) { -// Socket clientSocket = null; -// -// if (clientCnt < client.length) { -// try { -// clientSocket = serverSocket.accept(); -// clientSocket.setSoTimeout(40000); // 1000/sec -// } catch (IOException i) { -// System.out.println ("Accept() fail: "+i); -// } -// client[clientCnt] = new WarGameServerRunnable(this, clientSocket); -// new Thread(client[clientCnt]).start(); -// clientCnt++; -// System.out.println ("Client connected: " + clientSocket.getPort() -// +", CurrentClient: " + clientCnt); -// } else { -// try { -// Socket dummySocket = serverSocket.accept(); -// WarGameServerRunnable dummyRunnable = new WarGameServerRunnable(this, dummySocket); -// new Thread(dummyRunnable); -// dummyRunnable.out.println(dummySocket.getPort() -// + " < Sorry maximum user connected now"); -// System.out.println("Client refused: maximum connection " -// + client.length + " reached."); -// dummyRunnable.close(); -// } catch (IOException i) { -// System.out.println(i); -// } -// } -// } -// public synchronized void delClient(int clientID) { -// int pos = whoClient(clientID); -// WarGameServerRunnable endClient = null; -// if (pos >= 0) { -// endClient = client[pos]; -// if (pos < clientCnt-1) -// for (int i = pos+1; i < clientCnt; i++) -// client[i-1] = client[i]; -// clientCnt--; -// System.out.println("Client removed: " + clientID -// + " at client[" + pos +"], CurrentClient: " + clientCnt); -// endClient.close(); -// } -// } -//} -//class WarGameServerRunnable implements Runnable{ -// protected WarGameServer warGameServer=null; -// protected Socket clientSocket=null; -// protected PrintWriter out=null; -// protected BufferedReader in=null; -// public int clientID=-1; -// -// Game game=new Game(); -// ArrayList deck0=null;//내려놓는 곳 -// ArrayList deck1;//p1 deck -// ArrayList deck2;//p2 deck -// int playerCardCnt[]=new int[2];//player의 카드 갯 -// int deck0Cnt;//내려놓는 곳 카드 수 -// int turn=0; -// public WarGameServerRunnable(WarGameServer server,Socket socket){ -// this.warGameServer=server; -// this.clientSocket=socket; -// clientID=clientSocket.getPort(); -// try{ -// out=new PrintWriter(clientSocket.getOutputStream(),true); -//// out=new BufferedWriter(clientSocket.getOutputStream()); -// in=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); -// }catch(IOException ioe){} -// } -// public void run() { -// gameInit(); -// } -// public void close() { -// try { -// if(in !=null) in.close(); -// if(out !=null) out.close(); -// if(clientSocket!=null)clientSocket.close(); -// -// }catch(IOException i) { -// i.printStackTrace(); -// } -// } -// public int getClientID() { -// return clientID; -// } -// public void gameInit() { -// -// deck1=game.returnDeck1();//이미 셔플된 상태로 나온거라 따로 안해줘도 -// deck2=game.returnDeck2(); -// playerCardCnt[0]=deck1.size(); -// playerCardCnt[1]=deck2.size(); -// deck0Cnt=0; -// -// } From 6c5a91554946bd4ec7d10c73cc5a894b8a0adb6f Mon Sep 17 00:00:00 2001 From: LeeJooHwan Date: Thu, 18 Jun 2020 15:43:32 +0900 Subject: [PATCH 2/5] Add files via upload --- Cards.java | 6 +--- Game.java | 5 +-- RMISSLClientSocketFactory.java | 27 +++++++++++++++ RMISSLServerSocketFactory.java | 62 ++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 RMISSLClientSocketFactory.java create mode 100644 RMISSLServerSocketFactory.java diff --git a/Cards.java b/Cards.java index 21107f4..6b120b8 100644 --- a/Cards.java +++ b/Cards.java @@ -10,7 +10,7 @@ public class Cards { ArrayList cards; public Cards() { this.cards=new ArrayList(); - for(int i=2;i<=10;i++) { + for(int i=2;i<=10;i++) { // 52 cards cards.add(new Card(i,"S")); cards.add(new Card(i,"H")); cards.add(new Card(i,"D")); @@ -48,13 +48,9 @@ Card pop() { } void show() { - Iterator iter=cards.iterator(); while(iter.hasNext()) { System.out.println(iter.next()); - } - - } } diff --git a/Game.java b/Game.java index 1d6213e..2e48973 100644 --- a/Game.java +++ b/Game.java @@ -4,12 +4,10 @@ import java.util.Iterator; import java.util.List; - - public class Game { Cards cards; - private ArrayList deck0,deck1,deck2; + ArrayList deck0,deck1,deck2; public Game() { cards=new Cards(); @@ -24,7 +22,6 @@ public Game() { } - ArrayList returnDeck0(){ return deck0; } diff --git a/RMISSLClientSocketFactory.java b/RMISSLClientSocketFactory.java new file mode 100644 index 0000000..a7a634f --- /dev/null +++ b/RMISSLClientSocketFactory.java @@ -0,0 +1,27 @@ +import java.io.*; +import java.net.*; +import java.rmi.server.*; +import javax.net.ssl.*; + +public class RMISSLClientSocketFactory + implements RMIClientSocketFactory, Serializable { + + public Socket createSocket(String host, int port) throws IOException { + SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); + SSLSocket socket = (SSLSocket)factory.createSocket(host, port); + return socket; + } + + public int hashCode() { + return getClass().hashCode(); + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj == null || getClass() != obj.getClass()) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/RMISSLServerSocketFactory.java b/RMISSLServerSocketFactory.java new file mode 100644 index 0000000..695fe6b --- /dev/null +++ b/RMISSLServerSocketFactory.java @@ -0,0 +1,62 @@ +import java.io.FileInputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.rmi.server.RMIServerSocketFactory; +import java.security.KeyStore; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; + +public class RMISSLServerSocketFactory implements RMIServerSocketFactory{ + private static SSLServerSocketFactory ssf = null; + + final String runRoot = "C:/eclipse/java/WarGame/bin/"; + String ksName = runRoot + ".keystore/SSLSocketServerKey"; + + public RMISSLServerSocketFactory() throws Exception{ + try { + KeyStore ks; + KeyManagerFactory kmf; + SSLContext sc ; + + + char[] keyStorePass = "123456".toCharArray(); + char[] keyPass = "123456".toCharArray(); + + ks = KeyStore.getInstance("JKS"); + ks.load(new FileInputStream(ksName), keyStorePass); + kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, keyPass); + + sc = SSLContext.getInstance("TLS"); + sc.init(kmf.getKeyManagers(), null, null); + ssf = sc.getServerSocketFactory(); + + } catch(Exception e) { + e.printStackTrace(); + throw e; + } + } + + + public ServerSocket createServerSocket(int port) throws IOException { + return ssf.createServerSocket(port); + } + + public int hashCode() { + return getClass().hashCode(); + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj == null || getClass() != obj.getClass()) { + return false; + } + return true; + } + + +} From e194ec3738f93f86cfd2d2275ba4e89686390a73 Mon Sep 17 00:00:00 2001 From: LeeJooHwan Date: Thu, 18 Jun 2020 23:42:05 +0900 Subject: [PATCH 3/5] Add files via upload --- Cards.java | 2 +- WarGame.java | 23 +- WarGameClient.java | 47 +++- WarGameGUI.java | 17 +- WarGameImpl.java | 661 ++++++++++++++++++++++++++------------------- WarGameServer.java | 113 +++++++- 6 files changed, 568 insertions(+), 295 deletions(-) diff --git a/Cards.java b/Cards.java index 6b120b8..64b4478 100644 --- a/Cards.java +++ b/Cards.java @@ -36,7 +36,7 @@ public Cards() { cards.add(new Card("A","H")); cards.add(new Card("A","D")); cards.add(new Card("A","C")); - Collections.shuffle(cards); +// Collections.shuffle(cards); } Card pop() { Card c=cards.get(0); diff --git a/WarGame.java b/WarGame.java index 5f69aae..2bdd974 100644 --- a/WarGame.java +++ b/WarGame.java @@ -1,14 +1,25 @@ import java.rmi.Remote; import java.rmi.RemoteException; +import java.util.ArrayList; public interface WarGame extends Remote{ //public void func() throws RemoteException; boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException; - void broadcastMsg(String name, String message) throws RemoteException;//useless - void sendMsgToClient(String message) throws RemoteException;//useless - void doDrop() throws RemoteException; - void doHit() throws RemoteException; +// void broadcastMsg(String name, String message) throws RemoteException;//useless +// void sendMsgToClient(String message) throws RemoteException;//useless + void doDrop(String id) throws RemoteException; + void doHit(String id) throws RemoteException; boolean checkAllReady() throws RemoteException;//player 2명 전부 레디 했는지 확인 void setReadyStatus(String id,boolean status) throws RemoteException;//플레이어 각각이 레디했는지 확인. 아이디로 key, status value 임. - boolean checkStatus() throws RemoteException;//게임 종료시점인지 확인..p1나 p2의 카드가 제로인 경우 게임 끝.. -} + boolean checkEndingStatus() throws RemoteException;//게임 종료시점인지 확인..p1나 p2의 카드가 제로인 경우 게임 끝.. + int checkGameStatus() throws RemoteException;//drop을 해야할지 hit를 해야할지, 공격중인 상황인지 평시 상황인지 판단한담에 거기에 맞춰 int리턴 해주기..대신 #define방식으로 해서 + //가독성을 높이 + String whosTurn() throws RemoteException;//누구턴인지 알려줌 + void changeTurn() throws RemoteException; + void sendMsg(String msg) throws RemoteException;//client가 서버에게 메시지를 보내는 역할을 한다. + String receiveMsg() throws RemoteException;//client입장에서 서버로부터 메지시를 받는 역할을 한다. + ArrayList getClientList() throws RemoteException; + int getDeckLength(int player) throws RemoteException; + int whosWin() throws RemoteException; + void refreshDeck(int who) throws RemoteException; +} \ No newline at end of file diff --git a/WarGameClient.java b/WarGameClient.java index c9b431b..fd5f00c 100644 --- a/WarGameClient.java +++ b/WarGameClient.java @@ -16,7 +16,7 @@ public class WarGameClient implements Runnable {//handle connection and use rmi function here from client side // private static final long serialVersionUID = 1L; - private static final int PORT = 2019; + private static final int PORT = 2020; private String id; boolean chkLog=false; @@ -110,7 +110,33 @@ public void run() { // } try { while(server.checkEndingStatus()){//게임중... + if(!server.checkEndingStatus()) { + System.out.println("끝남ㅎㅎ"); + server.refreshDeck(server.whosWin()); + gui.deactivatedHitDropBtn(); + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + gui.getMessageBox(client.get(server.whosWin()-1)); + + } + + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); while(id.equals(server.whosTurn())){//자신의 턴 동안... + int num = -1; + for(int i = 0 ; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(server.getDeckLength(num) == 0 || server.getDeckLength(num) == 52) { + break; + } + + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + boolean_DropBtnStatus=gui.returnDropBtnStatus(); boolean_HitBtnStatus=gui.returnHitBtnStatus(); if(boolean_DropBtnStatus) { @@ -119,14 +145,12 @@ public void run() { // server.doDrop(id);//id는 안쓰고, serverImpl에서 turn보고 알아서 판단하고 있음. 필요 없는거 확실해지면 그때 지우기. gui.setDropStatusFalse();//버튼 눌리면 true로 변하기 때문에 변경 안하면 항상 true인 효과 한번 버튼 누르면 다시 false로 변환 //server.changeTurn(); - gui.repaint(); +// gui.repaint(); }else if(boolean_HitBtnStatus) { hit(); // server.doHit(id); gui.setHitStatusFalse(); - }else { - } } if(!id.equals(server.whosTurn())){//player가 잘못누르는 경우... @@ -138,14 +162,22 @@ public void run() { gui.setDropStatusFalse(); } if(boolean_HitBtnStatus){ - System.out.println("it's not your turn..please wait"); - gui.setGameInfo("it's not your turn..please wait"); +// System.out.println("it's not your turn..please wait"); +// gui.setGameInfo("it's not your turn..please wait"); + hit(); gui.setHitStatusFalse(); } } + } -// gui.deactivatedHitDropBtn(); + + server.refreshDeck(server.whosWin()); + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + gui.deactivatedHitDropBtn(); + gui.getMessageBox(client.get(server.whosWin()-1)); + }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯..예외처리 사이즈가 커 e.printStackTrace(); @@ -210,4 +242,3 @@ public static void main(String[] args) { } } - diff --git a/WarGameGUI.java b/WarGameGUI.java index 96a37e8..ca8bb75 100644 --- a/WarGameGUI.java +++ b/WarGameGUI.java @@ -97,6 +97,11 @@ protected void paintComponent(Graphics g) { super.paintComponent(g); playerCard.paintIcon(this,g,200,50); } + void setCardNumLabel(int p,int num) { + cardNumLabel[p].setText(""+num); + + } + } public class WarGameGUI extends JFrame implements ActionListener{ JTextArea ta_msgView; @@ -204,6 +209,12 @@ public WarGameGUI(String id) { this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } + + + //playerLabel[0],[1] + public void setCardNumLabel(int p,int num) { + board.setCardNumLabel(p, num); + } public String returnID() { return id; } @@ -242,6 +253,10 @@ public void activatedHitDropBtn() { hitBtn.setEnabled(true); dropBtn.setEnabled(true); } + public void getMessageBox(String Gid) { + JOptionPane.showMessageDialog(null, Gid+"가 승리하였습니다."); + } + public void actionPerformed(ActionEvent ae) { try { @@ -286,4 +301,4 @@ else if(ae.getSource()==readyBtn) { } } -} +} \ No newline at end of file diff --git a/WarGameImpl.java b/WarGameImpl.java index 0544dd9..a1e6b26 100644 --- a/WarGameImpl.java +++ b/WarGameImpl.java @@ -8,298 +8,405 @@ import java.util.Set; public class WarGameImpl extends UnicastRemoteObject implements WarGame { - - private static final int PORT = 2019; - private static final long serializedversion=1L; - private String clientID[]= {"aaa","bbb"}; - private String clientPassword[]= {"1234","1234"}; -// private ArrayList clientList; - private Game game; - private boolean turn=true; - private String msg; - private ArrayList deck0,deck1,deck2; - private int clientCnt=0; - //private HashMap clientStatus;//어떤 클라이언트의 순서인지 확인할 수 있다(이름,0)/(이름,1) -> 전자는 비활성화, 후자는 활성화 - private ArrayList client; - private HashMap readyStatus; - private boolean boolean_readyStatus[]; - private int attackCount=-1; - - private boolean isAttack = false; - private int dropCount = 0; - - protected WarGameImpl() throws RemoteException{ - super(); - //clientList=new ArrayList(); - msg=""; - game=new Game(); - deck1=game.returnDeck1(); - deck2=game.returnDeck2(); - deck0=game.returnDeck0(); - readyStatus=new HashMap(); - client=new ArrayList(); - //clientStatus=new HashMap(); -// boolean_readyStatus=new boolean[2]; -// boolean_readyStatus[0]=false; -// boolean_readyStatus[1]=false; - //System.out.println(deck1);//test + + private static final int PORT = 2020; + private static final long serializedversion=1L; + private String clientID[]= {"aaa","bbb"}; + private String clientPassword[]= {"1234","1234"}; +// private ArrayList clientList; + private Game game; + private boolean turn=true; + private String msg; + private ArrayList deck0,deck1,deck2; + private int clientCnt=0; + //private HashMap clientStatus;//어떤 클라이언트의 순서인지 확인할 수 있다(이름,0)/(이름,1) -> 전자는 비활성화, 후자는 활성화 + private ArrayList client; + private HashMap readyStatus; + private boolean boolean_readyStatus[]; + private int attackCount=-1; + + private boolean isAttack = false; + private int dropCount = 0; + private int whoIsWin = 0; + + + protected WarGameImpl() throws RemoteException{ + super(); + //clientList=new ArrayList(); + msg=""; + game=new Game(); + deck1=game.returnDeck1(); + deck2=game.returnDeck2(); + deck0=game.returnDeck0(); + readyStatus=new HashMap(); + client=new ArrayList(); + //clientStatus=new HashMap(); +// boolean_readyStatus=new boolean[2]; +// boolean_readyStatus[0]=false; +// boolean_readyStatus[1]=false; + //System.out.println(deck1);//test + } + + public synchronized boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException{ //id, pw 확인 + boolean checkLog=false; + for(int i=0;i getClientList() throws RemoteException{ + return client; + } + @Override + public synchronized void sendMsg(String msg) throws RemoteException{ + this.msg=msg; + } + @Override + public synchronized String receiveMsg() throws RemoteException{ + return msg; + } + @Override + public int checkGameStatus() throws RemoteException {//drop을 해야할지 hit를 해야할지, 공격중인 상황인지 평시 상황인지 판단한담에 거기에 맞춰 int리턴 + // TODO Auto-generated method st + int loc = deck0.size(); + String value=deck0.get(loc-1).returnValue(); + System.out.println("Value: "+value); + if(value=="K")//공격카드의 값만큼 리턴 + return 3; + else if(value.equals("Q")) + return 2; + else if(value.equals("J")) + return 1; + else if(value.equals("A")) + return 3; + else if(value.equals("2")) { + return 2; + } + else { + return -1;//평시 상태 + } + } + public void refreshDeck(int who) throws RemoteException{ + if(who == 2) { + for(int i = 0; i < deck0.size(); i++) { + deck2.add(deck0.get(i)); + } + deck0 = new ArrayList(); + } + else if(who == 1) { + for(int i = 0; i < deck0.size(); i++) { + deck1.add(deck0.get(i)); + } + deck0 = new ArrayList(); + } + } + + public boolean checkEndingStatus() throws RemoteException{ //deck이 비면 끝남 + if(deck1.isEmpty()==true || deck2.isEmpty()==true) { + if(deck1.isEmpty()) { + whoIsWin = 2; + } + else if(deck2.isEmpty()) { + whoIsWin = 1; + } + return false;//game over + } + else + return true; + } + + public int whosWin() throws RemoteException { + return whoIsWin; } - public synchronized boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException{ //id, pw 확인 - boolean checkLog=false; - for(int i=0;i getClientList() throws RemoteException{ - return client; - } - @Override - public synchronized void sendMsg(String msg) throws RemoteException{ - this.msg=msg; - } - @Override - public synchronized String receiveMsg() throws RemoteException{ - return msg; - } - @Override - public int checkGameStatus() throws RemoteException {//drop을 해야할지 hit를 해야할지, 공격중인 상황인지 평시 상황인지 판단한담에 거기에 맞춰 int리턴 - // TODO Auto-generated method st - int loc = deck0.size(); - String value=deck0.get(loc-1).returnValue(); - System.out.println("Value: "+value); - if(value=="K")//공격카드의 값만큼 리턴 - return 3; - else if(value.equals("Q")) - return 2; - else if(value.equals("J")) - return 1; - else if(value.equals("A")) - return 3; - else if(value.equals("2")) { - System.out.println("2임"); - return 2; - } - else { - System.out.println("Value????: "+value); - return -1;//평시 상태 - } - } - public boolean checkEndingStatus() throws RemoteException{ //deck이 비면 끝남 - if(deck1.isEmpty()==true || deck2.isEmpty()==true) - return false;//game over - else - return true; - } - public String whosTurn() throws RemoteException{ //누구의 턴인지 반환 - if(turn==true) - return client.get(0); - else - return client.get(1); - } - public void changeTurn() throws RemoteException{ - turn=!turn; - } - public synchronized void setReadyStatus(String id,boolean status) throws RemoteException{//플레이어 각각이 레디했는지 확인 - int tmp=0; - if(status==true) - tmp=1; - else - tmp=0; - if(!readyStatus.containsKey(id))//결국엔 같은건데 구분할까 말까? - readyStatus.put(id, tmp); - else { - readyStatus.put(id,tmp); - - } - - } - public synchronized boolean checkAllReady() throws RemoteException{//player 2명 전부 레디 했는지 확인 - int cnt=0; - Iterator> itr=readyStatus.entrySet().iterator(); - Set>set=readyStatus.entrySet(); - while(itr.hasNext()) { - Map.Entrye=(Map.Entry)itr.next(); - if(e.getValue()==1) { - cnt++; + public String whosTurn() throws RemoteException{ //누구의 턴인지 반환 + if(turn==true) + return client.get(0); + else + return client.get(1); + } + public void changeTurn() throws RemoteException{ + turn=!turn; + } + public synchronized void setReadyStatus(String id,boolean status) throws RemoteException{//플레이어 각각이 레디했는지 확인 + int tmp=0; + if(status==true) + tmp=1; + else + tmp=0; + if(!readyStatus.containsKey(id))//결국엔 같은건데 구분할까 말까? + readyStatus.put(id, tmp); + else { + readyStatus.put(id,tmp); + + } + + } + public synchronized boolean checkAllReady() throws RemoteException{//player 2명 전부 레디 했는지 확인 + int cnt=0; + Iterator> itr=readyStatus.entrySet().iterator(); + Set>set=readyStatus.entrySet(); + while(itr.hasNext()) { + Map.Entrye=(Map.Entry)itr.next(); + if(e.getValue()==1) { + cnt++; + } + + } + if(cnt==2) { + client.addAll(readyStatus.keySet()); +// clientStatus.put(client.get(0),1); +// clientStatus.put(client.get(1),0); + return true; + } + + else + return false; + } + public synchronized void doDrop(String id) throws RemoteException{ + + Card c=null; + if(turn==true) {//player 1's drop + if(isAttack == false) { + System.out.println("player 1 drop!"); + if(deck1.isEmpty()) { + System.out.println("Player2 win!!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + + System.out.println("뽑힌카드 : " +c); + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 1 drop! : Attack"); + if(deck1.isEmpty()) { + System.out.println("Player2 win!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + if(deck1.isEmpty()) { + return; + } + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); + + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck2.add(deck0.get(i)); + } + deck0 = new ArrayList(); + turn = !turn; + + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); + + } + } + else { + isAttack = true; + dropCount = 0; + if(deck1.isEmpty()) { + return; + } + attackCount = checkGameStatus(); + turn = !turn; + } + System.out.println("뽑힌카드 : " +c); + } + + }else {//player 2's drop + if(isAttack == false) { + System.out.println("player 2 drop!"); + if(deck2.isEmpty()) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); //가져온 카드 1개 제거 + + deck0.add(c); + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + + System.out.println("뽑힌카드 : " +c); + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 2 drop! : Attack"); + if(deck2.isEmpty()) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); + + deck0.add(c); + + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck1.add(deck0.get(i)); + } + deck0 = new ArrayList(); + turn = !turn; + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); + } + } + else { + isAttack = true; + dropCount = 0; + if(deck2.isEmpty()) { + return; + } + attackCount = checkGameStatus(); + turn = !turn; + } + System.out.println("뽑힌카드 : " +c); + } + } + } + public synchronized void doHit(String id) throws RemoteException{ + System.out.println("hit이 실행됨"); //플레이어 구분해서 해야하는데 아직 못함. + int who = -1; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + who = i+1; + break; } - } - if(cnt==2) { - client.addAll(readyStatus.keySet()); -// clientStatus.put(client.get(0),1); -// clientStatus.put(client.get(1),0); - return true; - } - - else - return false; - } - public synchronized void doDrop(String id) throws RemoteException{ - - Card c=null; - if(turn==true) {//player 1's drop - if(isAttack == false) { - System.out.println("player 1 drop!"); - if(deck1.size() == 0) { - System.out.println("Player2 win!!"); - return; - } - c=deck1.get(0); - pop(); //가져온 카드 1개 제거 - - deck0.add(c); - attackCount = checkGameStatus(); - if(attackCount == -1) { - turn = !turn; - } - else { - isAttack = true; - turn = !turn; + Card []c=new Card[2]; + if(deck0.size() < 2) { + System.out.println("Hit Fail..."); + if(who == 1){ + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); } - - System.out.println("뽑힌카드 : " +c); + deck0 = new ArrayList(); + turn = false; } - else if(isAttack == true) { //공격 상태일 때 - System.out.println("player 1 drop! : Attack"); - if(deck1.size() == 0) { - System.out.println("Player2 win!!"); - return; + else if(who == 2){ + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); } - c=deck1.get(0); - pop(); //가져온 카드 1개 제거 - - deck0.add(c); - if(checkGameStatus() == -1) { //공격카드가 아닐 경우 - dropCount++; - System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); - - if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 - dropCount = 0; - isAttack = false; - for(int i = 0; i < deck0.size(); i++) { - deck2.add(deck0.get(i)); - } - deck0 = new ArrayList(); - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); - - } - } - else { - isAttack = true; - dropCount = 0; - attackCount = checkGameStatus(); - turn = !turn; - } - System.out.println("뽑힌카드 : " +c); + deck0 = new ArrayList(); + turn = true; } - - }else {//player 2's drop - if(isAttack == false) { - System.out.println("player 2 drop!"); - if(deck2.size() == 0) { - System.out.println("Player1 win!!"); - return; - } - c=deck2.get(0); - pop(); //가져온 카드 1개 제거 - - deck0.add(c); - attackCount = checkGameStatus(); - if(attackCount == -1) { - turn = !turn; + + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); + } + else { + c[0]=deck0.get(deck0.size()-2); + c[1]=deck0.get(deck0.size()-1); + if(c[0].returnValue().equals(c[1].returnValue())) { + System.out.println("Hit Success..."); + if(who == 1) { + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = true; } - else { - isAttack = true; - turn = !turn; + else if(who == 2) { + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = false; } - - System.out.println("뽑힌카드 : " +c); } - else if(isAttack == true) { //공격 상태일 때 - System.out.println("player 2 drop! : Attack"); - if(deck2.size() == 0) { - System.out.println("Player1 win!!"); - return; - } - c=deck2.get(0); - pop(); - - deck0.add(c); - - if(checkGameStatus() == -1) { //공격카드가 아닐 경우 - dropCount++; - System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); - if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 - dropCount = 0; - isAttack = false; - for(int i = 0; i < deck0.size(); i++) { - deck1.add(deck0.get(i)); - } - deck0 = new ArrayList(); - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); + else { + System.out.println("Hit Fail!!!"); + if(who == 1){ + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); } + deck0 = new ArrayList(); + turn = false; } - else { - isAttack = true; - dropCount = 0; - attackCount = checkGameStatus(); - turn = !turn; + else if(who == 2){ + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = true; } - System.out.println("뽑힌카드 : " +c); - } - } - } - public synchronized void doHit(String id) throws RemoteException{ - System.out.println("hit이 실행됨"); //플레이어 구분해서 해야하는데 아직 못함. - Card []c=new Card[2]; - if(deck0.size() < 2) { - System.out.println("Hit Fail..."); - } - else { - c[0]=deck0.get(0); - c[1]=deck0.get(1); - if(c[0].returnType()==c[1].returnType()) { - System.out.println("Hit Success!!"); } - else - System.out.println("Hit Fail..."); - - } - } - - public void pop() { - if(turn==true) { - deck1.remove(0); - }else { - deck2.remove(0); - } - } - public void push() { - if(turn==true) { - - }else { + System.out.println("aaa의 카드 수 : "+deck1.size()); + System.out.println("bbb의 카드 수 : "+deck2.size()); + System.out.println("깔려 있는 카드 수 :"+deck0.size()); } + dropCount = 0; + isAttack = false; } - -} + + public void pop() { + if(turn==true) { + deck1.remove(0); + }else { + deck2.remove(0); + } + } + public void push() { + if(turn==true) { + + }else { + + } + } + + + +} \ No newline at end of file diff --git a/WarGameServer.java b/WarGameServer.java index 0e3cd45..852221e 100644 --- a/WarGameServer.java +++ b/WarGameServer.java @@ -10,7 +10,7 @@ public class WarGameServer extends UnicastRemoteObject { public int clientCnt=0; - private static final int PORT = 2019; + private static final int PORT = 2020; public WarGameServer(String server,String servName) throws Exception{ super(PORT, @@ -43,4 +43,113 @@ public static void main(String[] args) throws UnknownHostException { } } - +//public int whoClient(int clientID) { +// for (int i = 0; i < clientCnt; i++) +// if (client[i].getClientID() == clientID) +// return i; +// return -1; +//} +//public void putClient(int clientID, String inputLine) { +// for (int i = 0; i < clientCnt; i++) +// if (client[i].getClientID() == clientID) { +// System.out.println("writer: "+clientID); +// } else { +// System.out.println("write: "+client[i].getClientID()); +// client[i].out.println(inputLine); +// } +//} +//this is about chatting. so.. +//public void addClient(ServerSocket serverSocket) { +// Socket clientSocket = null; +// +// if (clientCnt < client.length) { +// try { +// clientSocket = serverSocket.accept(); +// clientSocket.setSoTimeout(40000); // 1000/sec +// } catch (IOException i) { +// System.out.println ("Accept() fail: "+i); +// } +// client[clientCnt] = new WarGameServerRunnable(this, clientSocket); +// new Thread(client[clientCnt]).start(); +// clientCnt++; +// System.out.println ("Client connected: " + clientSocket.getPort() +// +", CurrentClient: " + clientCnt); +// } else { +// try { +// Socket dummySocket = serverSocket.accept(); +// WarGameServerRunnable dummyRunnable = new WarGameServerRunnable(this, dummySocket); +// new Thread(dummyRunnable); +// dummyRunnable.out.println(dummySocket.getPort() +// + " < Sorry maximum user connected now"); +// System.out.println("Client refused: maximum connection " +// + client.length + " reached."); +// dummyRunnable.close(); +// } catch (IOException i) { +// System.out.println(i); +// } +// } +//} +//public synchronized void delClient(int clientID) { +// int pos = whoClient(clientID); +// WarGameServerRunnable endClient = null; +// if (pos >= 0) { +// endClient = client[pos]; +// if (pos < clientCnt-1) +// for (int i = pos+1; i < clientCnt; i++) +// client[i-1] = client[i]; +// clientCnt--; +// System.out.println("Client removed: " + clientID +// + " at client[" + pos +"], CurrentClient: " + clientCnt); +// endClient.close(); +// } +//} +//} +//class WarGameServerRunnable implements Runnable{ +// protected WarGameServer warGameServer=null; +// protected Socket clientSocket=null; +// protected PrintWriter out=null; +// protected BufferedReader in=null; +// public int clientID=-1; +// +// Game game=new Game(); +// ArrayList deck0=null;//내려놓는 곳 +// ArrayList deck1;//p1 deck +// ArrayList deck2;//p2 deck +// int playerCardCnt[]=new int[2];//player의 카드 갯 +// int deck0Cnt;//내려놓는 곳 카드 수 +// int turn=0; +// public WarGameServerRunnable(WarGameServer server,Socket socket){ +// this.warGameServer=server; +// this.clientSocket=socket; +// clientID=clientSocket.getPort(); +// try{ +// out=new PrintWriter(clientSocket.getOutputStream(),true); +// // out=new BufferedWriter(clientSocket.getOutputStream()); +// in=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); +// }catch(IOException ioe){} +// } +// public void run() { +// gameInit(); +// } +// public void close() { +// try { +// if(in !=null) in.close(); +// if(out !=null) out.close(); +// if(clientSocket!=null)clientSocket.close(); +// +// }catch(IOException i) { +// i.printStackTrace(); +// } +// } +// public int getClientID() { +// return clientID; +// } +// public void gameInit() { +// +// deck1=game.returnDeck1();//이미 셔플된 상태로 나온거라 따로 안해줘도 +// deck2=game.returnDeck2(); +// playerCardCnt[0]=deck1.size(); +// playerCardCnt[1]=deck2.size(); +// deck0Cnt=0; +// +// } From 9e1887bdd363a0a77d77912f2333ef046be9955f Mon Sep 17 00:00:00 2001 From: LeeJooHwan Date: Thu, 18 Jun 2020 23:42:35 +0900 Subject: [PATCH 4/5] Delete midWar.jpg --- midWar.jpg | Bin 63920 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 midWar.jpg diff --git a/midWar.jpg b/midWar.jpg deleted file mode 100644 index fbb382215a3c6396d65569680ab92c6be29eb0de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63920 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
0R}i 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 Date: Wed, 8 Jul 2020 14:28:41 +0900 Subject: [PATCH 5/5] Add files via upload --- Cards.java | 2 +- LoginGUI.java | 188 ++++++++++++++ SignUpGUI.java | 112 ++++++++ WarGame.java | 13 +- WarGameClient.java | 480 ++++++++++++++++++---------------- WarGameGUI.java | 175 +++++++------ WarGameImpl.java | 633 ++++++++++++++++++++++++++------------------- WarGameServer.java | 110 -------- 8 files changed, 1039 insertions(+), 674 deletions(-) create mode 100644 LoginGUI.java create mode 100644 SignUpGUI.java diff --git a/Cards.java b/Cards.java index 64b4478..6b120b8 100644 --- a/Cards.java +++ b/Cards.java @@ -36,7 +36,7 @@ public Cards() { cards.add(new Card("A","H")); cards.add(new Card("A","D")); cards.add(new Card("A","C")); -// Collections.shuffle(cards); + Collections.shuffle(cards); } Card pop() { Card c=cards.get(0); diff --git a/LoginGUI.java b/LoginGUI.java new file mode 100644 index 0000000..39c6ef0 --- /dev/null +++ b/LoginGUI.java @@ -0,0 +1,188 @@ +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.swing.*; + + +public class LoginGUI extends JFrame implements ActionListener{ +// JFrame frame; + JLabel label_id,label_pw; + JTextField tf_id; + JPasswordField tf_pw; + JButton logInBtn,signUpBtn; + String id; + String pw; + boolean flag; + ArrayList clientID; + ArrayList clientPassword; + ArrayList clientLogin; + + + LoginGUI(){ + flag=false; + clientID = new ArrayList(); + clientPassword = new ArrayList(); + clientLogin = new ArrayList(); + + label_id=new JLabel(); + label_pw=new JLabel(); + tf_id=new JTextField(); + tf_pw=new JPasswordField(); + logInBtn=new JButton(); + signUpBtn=new JButton(); + + label_id.setText("ID"); + label_id.setBounds(3,3,20,10); + label_pw.setText("Password"); + label_pw.setBounds(3,6,20,10); + logInBtn.setText("Login"); + signUpBtn.setText("Sign up"); + + this.setLayout(new BorderLayout()); + + JPanel panel1=new JPanel(); + panel1.setLayout(new GridLayout(2,2)); + panel1.add(label_id); + panel1.add(tf_id); + panel1.add(label_pw); + panel1.add(tf_pw); + + JPanel panel2=new JPanel(); + panel2.setLayout(new GridLayout(1,2)); + panel2.add(logInBtn); + panel2.add(signUpBtn); + + this.add(panel1,BorderLayout.CENTER); + this.add(panel2,BorderLayout.SOUTH); + + logInBtn.addActionListener(this); + signUpBtn.addActionListener(this); + + this.setSize(200,100); + this.setVisible(true); + this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + } + public void actionPerformed(ActionEvent ae) { + try { + if(ae.getSource()==logInBtn) { + String tmp_id; + String tmp_pw; + + id=tf_id.getText(); + char[] tmp=tf_pw.getPassword(); + pw=""; + for(char c : tmp){ + Character.toString(c); + pw += (pw.equals("")) ? ""+c+"" : ""+c+""; + } + try { + File f = new File("account.txt"); + if(!f.exists()) { + FileWriter fw=null; + BufferedWriter bw=null; + File file=new File("account.txt"); + try { + fw=new FileWriter(file,true); + bw=new BufferedWriter(fw); + bw.write(""); + }catch(IOException io) { + io.printStackTrace(); + } + + JOptionPane.showMessageDialog(null, "계정이 없거나 비밀번호가 틀렸습니덜.", "로그인 실패", JOptionPane.ERROR_MESSAGE); + tf_id.setText(""); + tf_pw.setText(""); + } + if(f.length() == 0) { + JOptionPane.showMessageDialog(null, "계정이 없거나 비밀번호가 틀렸다.", "로그인 실패", JOptionPane.ERROR_MESSAGE); + tf_id.setText(""); + tf_pw.setText(""); + } + + BufferedReader br=new BufferedReader(new FileReader("account.txt")); + + String s; + while ((s = br.readLine()) != null) { + String[] split = s.split("\t"); + clientID.add(split[0]); + clientPassword.add(split[1]); + clientLogin.add(false); + } + + for(int i=0;i getClientList() throws RemoteException; int getDeckLength(int player) throws RemoteException; - int whosWin() throws RemoteException; - void refreshDeck(int who) throws RemoteException; + String getTopType() throws RemoteException; + String getTopValue() throws RemoteException; + boolean getDeckZeroStatus() throws RemoteException; + public void refreshDeck(int who) throws RemoteException; + public int whosWin() throws RemoteException; +// public int getDeckSize() throws RemoteException; + public void modifyBtnStatus(int whichBtn, String id) throws RemoteException; + public boolean checkBtnStatus(int whichBtn, String id) throws RemoteException; + public void modifyAnotherBtnStatus(int whichBtn, String id) throws RemoteException; + public String findAnotherId(String id) throws RemoteException; + } \ No newline at end of file diff --git a/WarGameClient.java b/WarGameClient.java index fd5f00c..41253a3 100644 --- a/WarGameClient.java +++ b/WarGameClient.java @@ -15,230 +15,256 @@ public class WarGameClient implements Runnable {//handle connection and use rmi function here from client side -// private static final long serialVersionUID = 1L; - private static final int PORT = 2020; - - private String id; - boolean chkLog=false; - private WarGame server; - boolean boolean_ReadyBtnStatus; - boolean boolean_HitBtnStatus; - boolean boolean_DropBtnStatus; - ArrayList client; - WarGameGUI gui; - protected WarGameClient(WarGame wg,String id,String pw){ - boolean_ReadyBtnStatus=false; - boolean_HitBtnStatus=false; - boolean_DropBtnStatus=false; - this.server=wg; - this.id=id; - try { - chkLog=server.checkClientCredentials(wg, id, pw); - if(chkLog==false) { - System.out.println("wrong id or wrong passworld"); - System.exit(0); - } - - - }catch(RemoteException re) { - System.out.println("RemoteException: "+re); - - }catch(java.lang.ArithmeticException ae) { - System.out.println("java.lang.ArithmeticException: "+ae); - } - - } - void drop() { - boolean_DropBtnStatus=gui.returnDropBtnStatus(); - try { - server.doDrop(id);//id가 필요한지 모르겠음... - - }catch(Exception e) { - e.printStackTrace(); - } - } - void hit() { - boolean_HitBtnStatus=gui.returnHitBtnStatus(); - try { - server.doHit(id); - }catch(Exception e) { - e.printStackTrace(); - } - } - public void run() { - if(chkLog) { - System.out.println(id); - gui=new WarGameGUI(id); - gui.deactivatedHitDropBtn(); - try { - while(server.checkAllReady()==false) { - boolean_ReadyBtnStatus=gui.returnReadyBtnStatus(); - server.setReadyStatus(id, boolean_ReadyBtnStatus); - } - - }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯.. 예외처리 사이즈가 - e.printStackTrace(); - } - gui.activatedHitDropBtn(); - System.out.println("game start");//this will be deleted in the end - gui.setGameInfo("game start"); - gui.deactivateReadyBtn(); - try {//최종 참가자 리스트 추가 - client=server.getClientList(); - String tmp=client.get(0); - String tmp2=client.get(1); - gui.setPlayerList("Player1: "+tmp); - gui.setPlayerList("Player2: "+tmp2); - }catch(Exception e) { - e.printStackTrace(); - } -// try {//턴 돌아갈때 마다 올라가는 것으로 바꿔야 할것 같다. 1번에 국한되지 말고... -// if(id.contentEquals(server.whosTurn())) { -// String tmp=server.whosTurn(); -// sendMsgToAll(tmp+"'s turn\n"); -// -// } -// -//// System.out.println(tmp+"'s turn. good luck~!"); -//// gui.setGameInfo(tmp+"'s turn. good luck~!"); -//// String msg=receiveMsg(); -//// gui.setMsgView(msg); -// -// -// }catch(Exception e) { -// e.printStackTrace(); -// } - try { - while(server.checkEndingStatus()){//게임중... - if(!server.checkEndingStatus()) { - System.out.println("끝남ㅎㅎ"); - server.refreshDeck(server.whosWin()); - gui.deactivatedHitDropBtn(); - gui.setCardNumLabel(0, server.getDeckLength(0)); - gui.setCardNumLabel(1, server.getDeckLength(1)); - gui.getMessageBox(client.get(server.whosWin()-1)); - - } - - gui.setCardNumLabel(0, server.getDeckLength(0)); - gui.setCardNumLabel(1, server.getDeckLength(1)); - while(id.equals(server.whosTurn())){//자신의 턴 동안... - int num = -1; - for(int i = 0 ; i < client.size(); i++) { - if(id.equals(client.get(i))) { - num = i; - break; - } - } - if(server.getDeckLength(num) == 0 || server.getDeckLength(num) == 52) { - break; - } - - gui.setCardNumLabel(0, server.getDeckLength(0)); - gui.setCardNumLabel(1, server.getDeckLength(1)); - - boolean_DropBtnStatus=gui.returnDropBtnStatus(); - boolean_HitBtnStatus=gui.returnHitBtnStatus(); - if(boolean_DropBtnStatus) { - drop(); - gui.setMsgView("플레이어 "+ id+" 가 drop을 했습니다."); -// server.doDrop(id);//id는 안쓰고, serverImpl에서 turn보고 알아서 판단하고 있음. 필요 없는거 확실해지면 그때 지우기. - gui.setDropStatusFalse();//버튼 눌리면 true로 변하기 때문에 변경 안하면 항상 true인 효과 한번 버튼 누르면 다시 false로 변환 - //server.changeTurn(); -// gui.repaint(); - }else if(boolean_HitBtnStatus) { - hit(); -// server.doHit(id); - gui.setHitStatusFalse(); - - } - } - if(!id.equals(server.whosTurn())){//player가 잘못누르는 경우... - boolean_DropBtnStatus=gui.returnDropBtnStatus(); - boolean_HitBtnStatus=gui.returnHitBtnStatus(); - if(boolean_DropBtnStatus){ - System.out.println("it's not your turn..please wait"); - gui.setGameInfo("it's not your turn..please wait"); - gui.setDropStatusFalse(); - } - if(boolean_HitBtnStatus){ -// System.out.println("it's not your turn..please wait"); -// gui.setGameInfo("it's not your turn..please wait"); - hit(); - gui.setHitStatusFalse(); - } - } - - } - - - server.refreshDeck(server.whosWin()); - gui.setCardNumLabel(0, server.getDeckLength(0)); - gui.setCardNumLabel(1, server.getDeckLength(1)); - gui.deactivatedHitDropBtn(); - gui.getMessageBox(client.get(server.whosWin()-1)); - - - }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯..예외처리 사이즈가 커 - e.printStackTrace(); - } - } - } - public void sendMsgToAll(String str) {//행동 취하고 나면 반드시 해당함수를 써서 메시지를 보내야한다. 그리고 바로 receiveMSG도 작동해야한다. - try { - server.sendMsg(str); - - }catch(Exception e) { - e.printStackTrace(); - } - } -// public String receiveMsg() { -// String msg=""; -// try { -// msg=server.receiveMsg(); -//// gui.setMsgView(msg+"\n"); -// -// }catch(Exception e) { -// e.printStackTrace(); -// -// } -// return msg; -// } - public static void main(String[] args) { - String mServer="127.0.0.1"; - String mServName="WarGame"; - - System.out.println("Remote Method Invocate to "+mServer+", service name: "+mServName); - - try { - System.setProperty("javax.net.ssl.trustStore", "trustedcerts"); - System.setProperty("javax.net.ssl.trustStorePasssword", "123456"); - - String id; - String pw; - Scanner sc=new Scanner(System.in);//this is for temporary - System.out.print("enter id: "); - id=sc.nextLine(); - System.out.print("enter pw: "); - pw=sc.nextLine(); - - - Registry registry = LocateRegistry.getRegistry( - InetAddress.getLocalHost().getHostName(), PORT, - new RMISSLClientSocketFactory()); - - WarGame c=(WarGame)registry.lookup("WarGame"/*"rmi://"+mServer+":1099/"+mServName*/); - new Thread(new WarGameClient(c,id,pw)).start(); - - }catch(RemoteException re) { - System.out.println("RemoteException: "+re); - }catch(NotBoundException nbe) { - System.out.println("NotBoundException: "+nbe); - }catch(java.lang.ArithmeticException ae) { - System.out.println("java.lang.ArithmeticException: "+ae); - } catch (UnknownHostException e) { - System.out.println("UnknownHostException: "+e); - } - } - -} +// private static final long serialVersionUID = 1L; + private static final int PORT = 2020; + + private String id; + boolean chkLog=false; + private WarGame server; + boolean boolean_ReadyBtnStatus; + boolean boolean_HitBtnStatus; + boolean boolean_DropBtnStatus; + Card top; + ArrayList client; + WarGameGUI gui; + protected WarGameClient(WarGame wg,String id,String pw){ + boolean_ReadyBtnStatus=false; + boolean_HitBtnStatus=false; + boolean_DropBtnStatus=false; + this.server=wg; + this.id=id; + try { + chkLog=server.checkClientCredentials(wg, id, pw); + if(chkLog==false) { + System.out.println("wrong id or wrong password"); + System.exit(0); + } + + + }catch(RemoteException re) { + System.out.println("RemoteException: "+re); + + }catch(java.lang.ArithmeticException ae) { + System.out.println("java.lang.ArithmeticException: "+ae); + } + + } + void drop() { + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + try { + server.doDrop(id);//id가 필요한지 모르겠음... + + }catch(Exception e) { + e.printStackTrace(); + } + } + void hit() { + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + try { + server.doHit(id); + }catch(Exception e) { + e.printStackTrace(); + } + } + public void run() { + if(chkLog) { + gui=new WarGameGUI(id); + gui.deactivatedHitDropBtn(); + try { + while(server.checkAllReady()==false) { + boolean_ReadyBtnStatus=gui.returnReadyBtnStatus(); + server.setReadyStatus(id, boolean_ReadyBtnStatus); + } + + }catch(Exception e) {//디테일하게 예외 잡아 줘야 할 듯.. 예외처리 사이즈가 + e.printStackTrace(); + } + gui.activatedHitDropBtn(); + gui.setGameInfo("game start"); + gui.deactivateReadyBtn(); + try {//최종 참가자 리스트 추가 + client=server.getClientList(); + String tmp=client.get(0); + String tmp2=client.get(1); + gui.setPlayerList("Player1: "+tmp); + gui.setPlayerList("Player2: "+tmp2); + }catch(Exception e) { + e.printStackTrace(); + } + try { + while(server.checkEndingStatus()){//게임중... + if(!server.checkEndingStatus()) { + server.refreshDeck(server.whosWin()); + gui.deactivatedHitDropBtn(); + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + gui.updateCardImg(); + gui.getMessageBox(client.get(server.whosWin()-1)); + + } + + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1,server.getDeckLength(1)); + + gui.setGameInfo("turn : "+server.whosTurn()); + + if(server.checkBtnStatus(0, id)){ + gui.setMsgView("플레이어 "+ server.findAnotherId(id)+" 가 drop을 했습니다."); + server.modifyAnotherBtnStatus(0, id); + } + if(server.checkBtnStatus(1, id)) { + gui.setMsgView("플레이어 "+ server.findAnotherId(id)+" 가 hit을 했습니다."); + server.modifyAnotherBtnStatus(1, id); + } + + + while(id.equals(server.whosTurn())){//자신의 턴 동안... + gui.setGameInfo("turn : "+server.whosTurn()); + if(server.checkBtnStatus(0, id)){ + gui.setMsgView("플레이어 "+ server.findAnotherId(id)+" 가 drop을 했습니다."); + server.modifyAnotherBtnStatus(0, id); + } + if(server.checkBtnStatus(1, id)) { + gui.setMsgView("플레이어 "+ server.findAnotherId(id)+" 가 hit을 했습니다."); + server.modifyAnotherBtnStatus(1, id); + } + + int num = -1; + for(int i = 0 ; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(server.getDeckLength(num) == 0 || server.getDeckLength(num) == 52) { + break; + } + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1,server.getDeckLength(1)); + + + if(server.getDeckZeroStatus()) {//바닥에 카드가 있을때만 작동 + + String topType=server.getTopType(); + String topValue=server.getTopValue(); + if(!topType.isEmpty() && !topValue.isEmpty()) { + gui.updateCardImg(topType, topValue); + } + else { + gui.updateCardImg(); + } + + }else { + gui.updateCardImg(); + } + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + if(boolean_DropBtnStatus) { + drop(); + gui.setMsgView("플레이어 "+ id+" 가 drop을 했습니다"); + server.modifyBtnStatus(0, id); + gui.setDropStatusFalse();//버튼 눌리면 true로 변하기 때문에 변경 안하면 항상 true인 효과 한번 버튼 누르면 다시 false로 변환 + + }else if(boolean_HitBtnStatus) { + hit(); + gui.setMsgView("플레이어 "+ id+" 가 hit을 했습니다."); + server.modifyBtnStatus(1, id); + + gui.setHitStatusFalse(); + + }else { + + } + } + if(!id.equals(server.whosTurn())){//player가 잘못누르는 경우... + gui.setGameInfo("turn : "+server.whosTurn()); + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + + if(server.getDeckZeroStatus()) { + + String topType=server.getTopType(); + String topValue=server.getTopValue(); + gui.updateCardImg(topType, topValue); + + }else { + gui.updateCardImg();//아무것도 없는 경우 뒷장 보이게 함 + } + + + boolean_DropBtnStatus=gui.returnDropBtnStatus(); + boolean_HitBtnStatus=gui.returnHitBtnStatus(); + if(boolean_DropBtnStatus){ + + gui.setGameInfo("it's not your turn..please wait"); + gui.setDropStatusFalse(); + } + if(boolean_HitBtnStatus){ + hit(); + gui.setMsgView("플레이어 "+ id+" 가 hit을 했습니다."); + server.modifyBtnStatus(1, id); + gui.setHitStatusFalse(); + } + } + + } + + server.refreshDeck(server.whosWin()); + gui.setCardNumLabel(0, server.getDeckLength(0)); + gui.setCardNumLabel(1, server.getDeckLength(1)); + gui.deactivatedHitDropBtn(); + gui.updateCardImg(); + gui.getMessageBox(client.get(server.whosWin()-1)); + + }catch(Exception e) { + e.printStackTrace(); + } + } + } + public void sendMsgToAll(String str) {//행동 취하고 나면 반드시 해당함수를 써서 메시지를 보내야한다. 그리고 바로 receiveMSG도 작동해야한다. + try { + server.sendMsg(str); + + }catch(Exception e) { + e.printStackTrace(); + } + } + + public static void main(String[] args) { + String mServer="127.0.0.1"; + String mServName="WarGame"; + + System.out.println("Remote Method Invocate to "+mServer+", service name: "+mServName); + + try { + System.setProperty("javax.net.ssl.trustStore", "trustedcerts"); + System.setProperty("javax.net.ssl.trustStorePasssword", "123456"); + + String id=""; + String pw=""; + + LoginGUI login = new LoginGUI(); + + while(login.returnFlag()==false) { + System.out.print(""); + } + id=login.returnID(); + pw=login.returnPW(); + Registry registry = LocateRegistry.getRegistry( + InetAddress.getLocalHost().getHostName(), PORT, + new RMISSLClientSocketFactory()); + WarGame c=(WarGame)registry.lookup("WarGame"/*"rmi://"+mServer+":1099/"+mServName*/); + new Thread(new WarGameClient(c,id,pw)).start(); + + }catch(RemoteException re) { + System.out.println("RemoteException: "+re); + }catch(NotBoundException nbe) { + System.out.println("NotBoundException: "+nbe); + }catch(java.lang.ArithmeticException ae) { + System.out.println("java.lang.ArithmeticException: "+ae); + } catch (UnknownHostException e) { + System.out.println("UnknownHostException: "+e); + } + } + +} \ No newline at end of file diff --git a/WarGameGUI.java b/WarGameGUI.java index ca8bb75..4b832f6 100644 --- a/WarGameGUI.java +++ b/WarGameGUI.java @@ -23,7 +23,7 @@ class WarGameBoard extends JPanel{ ImageIcon icon; JButton dropBtn; JButton hitBtn; - + CardGUI []cardGUI; public WarGameBoard() { setLayout(null); @@ -34,37 +34,33 @@ public WarGameBoard() { frontSideCard=new ImageIcon[52]; String address="img/trumpCard/"; String tmp=null; + + cardGUI=new CardGUI[52]; for(int i=1;i<10;i++) { - tmp=address+(i+1)+"S"+".png"; - frontSideCard[13*0+i]=new ImageIcon(tmp); - tmp=address+(i+1)+"D"+".png"; - frontSideCard[13*1+i]=new ImageIcon(tmp); - tmp=address+(i+1)+"H"+".png"; - frontSideCard[13*2+i]=new ImageIcon(tmp); - tmp=address+(i+1)+"C"+".png"; - frontSideCard[13*3+i]=new ImageIcon(tmp); + cardGUI[13*0+i]=new CardGUI("S",i); + cardGUI[13*1+i]=new CardGUI("D",i); + cardGUI[13*2+i]=new CardGUI("H",i); + cardGUI[13*3+i]=new CardGUI("C",i); } - frontSideCard[13*0+0]=new ImageIcon("img/trumpCard/AS.png"); - frontSideCard[13*1+0]=new ImageIcon("img/trumpCard/AD.png"); - frontSideCard[13*2+0]=new ImageIcon("img/trumpCard/AH.png"); - frontSideCard[13*3+0]=new ImageIcon("img/trumpCard/AC.png"); - - frontSideCard[13*0+10]=new ImageIcon("img/trumpCard/JS.png"); - frontSideCard[13*1+10]=new ImageIcon("img/trumpCard/JD.png"); - frontSideCard[13*2+10]=new ImageIcon("img/trumpCard/JH.png"); - frontSideCard[13*3+10]=new ImageIcon("img/trumpCard/JC.png"); - - frontSideCard[13*0+11]=new ImageIcon("img/trumpCard/QS.png"); - frontSideCard[13*1+11]=new ImageIcon("img/trumpCard/QD.png"); - frontSideCard[13*2+11]=new ImageIcon("img/trumpCard/QH.png"); - frontSideCard[13*3+11]=new ImageIcon("img/trumpCard/QC.png"); - - frontSideCard[13*0+12]=new ImageIcon("img/trumpCard/KS.png"); - frontSideCard[13*1+12]=new ImageIcon("img/trumpCard/KD.png"); - frontSideCard[13*2+12]=new ImageIcon("img/trumpCard/KH.png"); - frontSideCard[13*3+12]=new ImageIcon("img/trumpCard/KC.png"); - - + cardGUI[13*0+0]=new CardGUI("S","A");//type,value + cardGUI[13*1+0]=new CardGUI("D","A");//type,value + cardGUI[13*2+0]=new CardGUI("H","A");//type,value + cardGUI[13*3+0]=new CardGUI("C","A");//type,value + + cardGUI[13*0+10]=new CardGUI("S","J");//type,value + cardGUI[13*1+10]=new CardGUI("D","J");//type,value + cardGUI[13*2+10]=new CardGUI("H","J");//type,value + cardGUI[13*3+10]=new CardGUI("C","J");//type,value + + cardGUI[13*0+11]=new CardGUI("S","Q"); + cardGUI[13*1+11]=new CardGUI("D","Q"); + cardGUI[13*2+11]=new CardGUI("H","Q"); + cardGUI[13*3+11]=new CardGUI("C","Q"); + + cardGUI[13*0+12]=new CardGUI("S","K"); + cardGUI[13*1+12]=new CardGUI("D","K"); + cardGUI[13*2+12]=new CardGUI("H","K"); + cardGUI[13*3+12]=new CardGUI("C","K"); backSideCard=new ImageIcon("img/trumpCard/red_back.png"); @@ -92,6 +88,18 @@ public WarGameBoard() { playerCard=backSideCard; + } + void updateCardImg(String type,String value) { + playerCard=findImg(type,value); + repaint(); + + } + void callRepaint() { + repaint(); + } + void updateCardImg() { + playerCard=new ImageIcon("img/trumpCard/red_back.png"); + repaint(); } protected void paintComponent(Graphics g) { super.paintComponent(g); @@ -101,22 +109,26 @@ void setCardNumLabel(int p,int num) { cardNumLabel[p].setText(""+num); } + ImageIcon findImg(String type,String value) { + for(int i=0;i"); JLabel la_playerInfo=new JLabel(""); -// boolean ready=false; + boolean boolean_ReadyBtn; boolean boolean_HitBtn; boolean boolean_DropBtn; @@ -133,12 +145,12 @@ public class WarGameGUI extends JFrame implements ActionListener{ public WarGameGUI(String id) { super("War Game"); -// WarGameClient client=new WarGameClient(); + this.id=id; boolean_ReadyBtn=false; boolean_HitBtn=false; boolean_DropBtn=false; - //it was in main() at first.but need to change to use rmi... + Container ct=getContentPane(); ct.setLayout(null); @@ -148,7 +160,7 @@ public WarGameGUI(String id) { hitBtn.setText("Hit"); hitBtn.setName("hitBtn"); - hitBtn.setBounds(120,420,157,82); + hitBtn.setBounds(120,560,157,82); ct.add(hitBtn); hitBtn.addActionListener(this); @@ -158,14 +170,14 @@ public WarGameGUI(String id) { dropBtn.setText("Drop"); dropBtn.setName("dropBtn"); - dropBtn.setBounds(300,420,157,82); + dropBtn.setBounds(300,560,157,82); ct.add(dropBtn); dropBtn.addActionListener(this); ta_msgView=new JTextArea(1,1); scPane=new JScrollPane(ta_msgView); -// EtchedBorder eborder = new EtchedBorder(EtchedBorder.RAISED); + ta_msgView.setEditable(false); la_GameInfo.setBounds(10,10,480,30); ct.add(la_GameInfo); @@ -176,17 +188,13 @@ public WarGameGUI(String id) { JPanel connectPanel=new JPanel(); connectPanel.setLayout(new GridLayout(1,1)); -// connectPanel.add(new Label("IP Address: ",2)); -// connectPanel.add(tf_IPAddress); -// connectPanel.add(new Label("name : ",2)); -// connectPanel.add(tf_Name); -// connectPanel.add(connectBtn) + readyBtn.setFont(new java.awt.Font("Lucida Grande", 0, 24));; connectPanel.add(readyBtn); -// readyBtn.setEnabled(false); + connectPanel.setBounds(620,50,250,70); ct.add(connectPanel); -// connectBtn.addActionListener(this); + readyBtn.addActionListener(this); JPanel participantsPanel=new JPanel(); @@ -199,22 +207,30 @@ public WarGameGUI(String id) { JPanel infoPanel=new JPanel(); infoPanel.setLayout(new BorderLayout()); infoPanel.add(scPane,"Center"); -// infoPanel.add(tf_Send,"South"); + infoPanel.setBounds(620,360,250,200); ct.add(infoPanel); -// tf_Send.addActionListener(this); + ta_msgView.append("press ready to play game\n"); - this.setSize(880,650); + this.setSize(880,690); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } - + public void callRepaint() { + board.callRepaint(); + } //playerLabel[0],[1] public void setCardNumLabel(int p,int num) { board.setCardNumLabel(p, num); } + public void updateCardImg(String type,String value) { + board.updateCardImg(type, value); + } + public void updateCardImg() { + board.updateCardImg(); + } public String returnID() { return id; } @@ -254,45 +270,25 @@ public void activatedHitDropBtn() { dropBtn.setEnabled(true); } public void getMessageBox(String Gid) { - JOptionPane.showMessageDialog(null, Gid+"가 승리하였습니다."); - } - - + JOptionPane.showMessageDialog(null, Gid+"가 승리하였습니다."); + } public void actionPerformed(ActionEvent ae) { try { if(ae.getSource()==dropBtn) { -// System.out.println("drop"); boolean_DropBtn=true; } else if(ae.getSource()==hitBtn) { boolean_HitBtn=true; -// System.out.println("hit"); } -// else if(ae.getSource()==tf_Send) { -// String msg=tf_Send.getText(); -// if(msg.length()==0) -// return ; -// if(msg.length()>=30) { -// msg=msg.substring(0,30); -// } -//// writer.println("[MSG]: ",msg); -// System.out.println("[MSG]:"+ msg); -// tf_Send.setText(""); -// } -// else if(ae.getSource()==connectBtn) { -// System.out.println("[Connect]: button"); -// } + else if(ae.getSource()==readyBtn) { -// System.out.println("[Ready]: button"); if(boolean_ReadyBtn==false) { boolean_ReadyBtn=true; readyBtn.setText("not ready");//레디 박은 상 - System.out.println(boolean_ReadyBtn); } else { boolean_ReadyBtn=false; readyBtn.setText("ready");//레디 안했을 경우 - System.out.println(boolean_ReadyBtn); } } @@ -301,4 +297,35 @@ else if(ae.getSource()==readyBtn) { } } +} +class CardGUI{ + String type; + String value; + ImageIcon img; + String address="img/trumpCard/"; + String tmp=null; + CardGUI(String type,String value){ + this.type=type; + this.value=value; + tmp=address+value+type+".png"; + img=new ImageIcon(tmp); + + } + CardGUI(String type,int value){ + this.type=type; + value=value+1; + this.value=Integer.toString(value); + + tmp=address+value+type+".png"; + img=new ImageIcon(tmp); + } + String returnType() { + return type; + } + String returnValue() { + return value; + } + ImageIcon returnImg() { + return img; + } } \ No newline at end of file diff --git a/WarGameImpl.java b/WarGameImpl.java index a1e6b26..cdb77fd 100644 --- a/WarGameImpl.java +++ b/WarGameImpl.java @@ -1,3 +1,6 @@ +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; @@ -5,14 +8,17 @@ import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; + +import javax.swing.JOptionPane; + import java.util.Set; public class WarGameImpl extends UnicastRemoteObject implements WarGame { - private static final int PORT = 2020; private static final long serializedversion=1L; - private String clientID[]= {"aaa","bbb"}; - private String clientPassword[]= {"1234","1234"}; + private ArrayList clientID; + private ArrayList clientPassword; + private ArrayList clientLogin; // private ArrayList clientList; private Game game; private boolean turn=true; @@ -25,10 +31,12 @@ public class WarGameImpl extends UnicastRemoteObject implements WarGame { private boolean boolean_readyStatus[]; private int attackCount=-1; + private boolean boolean_dropStatus[]; + private boolean boolean_hitStatus[]; + private boolean isAttack = false; private int dropCount = 0; - private int whoIsWin = 0; - + private int whoIsWin=0; protected WarGameImpl() throws RemoteException{ super(); @@ -38,35 +46,179 @@ protected WarGameImpl() throws RemoteException{ deck1=game.returnDeck1(); deck2=game.returnDeck2(); deck0=game.returnDeck0(); + clientID = new ArrayList(); + clientPassword = new ArrayList(); + clientLogin = new ArrayList(); readyStatus=new HashMap(); + boolean_dropStatus = new boolean[2]; + boolean_hitStatus = new boolean[2]; + boolean_dropStatus[0] = false; + boolean_dropStatus[1] = false; + boolean_hitStatus[0] = false; + boolean_hitStatus[1] = false; + client=new ArrayList(); - //clientStatus=new HashMap(); -// boolean_readyStatus=new boolean[2]; -// boolean_readyStatus[0]=false; -// boolean_readyStatus[1]=false; - //System.out.println(deck1);//test + + } + + public String findAnotherId(String id) throws RemoteException{ + int num = -1; + String temp; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(num == 0) { + temp = client.get(1); + } + else { + temp = client.get(0); + } + return temp; + } + + public boolean checkBtnStatus(int whichBtn, String id) throws RemoteException{ + int num = -1; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(num == 0) { + num = 1; + } + else + num = 0; + + + if(whichBtn == 0) { //drop + return boolean_dropStatus[num]; + } + else { //hit + return boolean_hitStatus[num]; + } + } + + public void modifyBtnStatus(int whichBtn, String id) throws RemoteException{ + int num = -1; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(whichBtn == 0) { //drop + boolean_dropStatus[num] = true; + } + else { //hit + boolean_hitStatus[num] = true; + } } + public void modifyAnotherBtnStatus(int whichBtn, String id) throws RemoteException{ + int num = -1; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + num = i; + break; + } + } + if(num == 0) + num = 1; + else + num = 0; + + if(whichBtn == 0) //drop + boolean_dropStatus[num] = false; + else //hit + boolean_hitStatus[num] = false; + + } + + + public boolean getDeckZeroStatus() throws RemoteException{ + if(deck0.isEmpty()) + return false; + else + return true; + + } + public void refreshDeck(int who) throws RemoteException{ + if(who == 2) { + for(int i = 0; i < deck0.size(); i++) { + deck2.add(deck0.get(i)); + } + deck0 = new ArrayList(); + } + else if(who == 1) { + for(int i = 0; i < deck0.size(); i++) { + deck1.add(deck0.get(i)); + } + deck0 = new ArrayList(); + } + + } + public String getTopType() throws RemoteException{ + try { + if(deck0.size()>0) + return deck0.get(deck0.size()-1).returnType(); + else + return ""; + } + catch(NullPointerException e) { + System.out.println(e); + return ""; + } + } + public String getTopValue() throws RemoteException{ + try { + if(deck0.size()>0) + return deck0.get(deck0.size()-1).returnValue(); + else + return ""; + } + catch(NullPointerException e) { + System.out.println(e); + return ""; + } + } public synchronized boolean checkClientCredentials(WarGame wg,String id,String password) throws RemoteException{ //id, pw 확인 boolean checkLog=false; - for(int i=0;i(); - } - else if(who == 1) { - for(int i = 0; i < deck0.size(); i++) { - deck1.add(deck0.get(i)); - } - deck0 = new ArrayList(); - } - } - - public boolean checkEndingStatus() throws RemoteException{ //deck이 비면 끝남 + + public boolean checkEndingStatus() throws RemoteException{ //deck이 비면 끝남 if(deck1.isEmpty()==true || deck2.isEmpty()==true) { - if(deck1.isEmpty()) { - whoIsWin = 2; - } - else if(deck2.isEmpty()) { - whoIsWin = 1; - } - return false;//game over + if(deck1.isEmpty()) { + whoIsWin = 2; + } + else if(deck2.isEmpty()) { + whoIsWin = 1; + } + return false;//game over } else return true; } - - public int whosWin() throws RemoteException { - return whoIsWin; - } - + public String whosTurn() throws RemoteException{ //누구의 턴인지 반환 if(turn==true) return client.get(0); else return client.get(1); } + public void changeTurn() throws RemoteException{ turn=!turn; } + public synchronized void setReadyStatus(String id,boolean status) throws RemoteException{//플레이어 각각이 레디했는지 확인 int tmp=0; if(status==true) @@ -175,223 +310,203 @@ public synchronized boolean checkAllReady() throws RemoteException{//player 2명 } if(cnt==2) { client.addAll(readyStatus.keySet()); -// clientStatus.put(client.get(0),1); -// clientStatus.put(client.get(1),0); return true; } else return false; } + public int whosWin() throws RemoteException { + return whoIsWin; + } + public synchronized void doDrop(String id) throws RemoteException{ - - Card c=null; - if(turn==true) {//player 1's drop - if(isAttack == false) { - System.out.println("player 1 drop!"); - if(deck1.isEmpty()) { - System.out.println("Player2 win!!"); - return; - } - c=deck1.get(0); - pop(); //가져온 카드 1개 제거 + + Card c=null; + if(turn==true) {//player 1's drop + if(isAttack == false) { + System.out.println("player 1 drop!"); + if(deck1.isEmpty()) { + System.out.println("Player2 win!!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 - deck0.add(c); - - attackCount = checkGameStatus(); - if(attackCount == -1) { - turn = !turn; - } - else { - isAttack = true; - turn = !turn; - } - - System.out.println("뽑힌카드 : " +c); - } - else if(isAttack == true) { //공격 상태일 때 - System.out.println("player 1 drop! : Attack"); - if(deck1.isEmpty()) { - System.out.println("Player2 win!"); - return; - } - c=deck1.get(0); - pop(); //가져온 카드 1개 제거 + deck0.add(c); + + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 1 drop! : Attack"); + if(deck1.isEmpty()) { + System.out.println("Player2 win!!"); + return; + } + c=deck1.get(0); + pop(); //가져온 카드 1개 제거 - deck0.add(c); - if(deck1.isEmpty()) { - return; - } - if(checkGameStatus() == -1) { //공격카드가 아닐 경우 - dropCount++; - System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); - - if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 - dropCount = 0; - isAttack = false; - for(int i = 0; i < deck0.size(); i++) { - deck2.add(deck0.get(i)); - } - deck0 = new ArrayList(); - turn = !turn; - - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); - - } - } - else { - isAttack = true; - dropCount = 0; - if(deck1.isEmpty()) { - return; - } - attackCount = checkGameStatus(); - turn = !turn; - } - System.out.println("뽑힌카드 : " +c); - } - - }else {//player 2's drop - if(isAttack == false) { - System.out.println("player 2 drop!"); - if(deck2.isEmpty()) { - System.out.println("Player1 win!!"); - return; - } - c=deck2.get(0); - pop(); //가져온 카드 1개 제거 + deck0.add(c); + if(deck1.isEmpty()) { + return; + } + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck2.add(deck0.get(i)); + } + deck0 = new ArrayList(); + turn = !turn; + } + } + else { + isAttack = true; + dropCount = 0; + if(deck1.isEmpty()) { + return; + } + attackCount = checkGameStatus(); + turn = !turn; + } + } + + }else {//player 2's drop + if(isAttack == false) { + System.out.println("player 2 drop!"); + if(deck2.isEmpty()) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); //가져온 카드 1개 제거 - deck0.add(c); - attackCount = checkGameStatus(); - if(attackCount == -1) { - turn = !turn; - } - else { - isAttack = true; - turn = !turn; - } - - System.out.println("뽑힌카드 : " +c); - } - else if(isAttack == true) { //공격 상태일 때 - System.out.println("player 2 drop! : Attack"); - if(deck2.isEmpty()) { - System.out.println("Player1 win!!"); - return; - } - c=deck2.get(0); - pop(); - - deck0.add(c); - - if(checkGameStatus() == -1) { //공격카드가 아닐 경우 - dropCount++; - System.out.println("AttackCount: "+attackCount+ ", DropCount: "+dropCount); - if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 - dropCount = 0; - isAttack = false; - for(int i = 0; i < deck0.size(); i++) { - deck1.add(deck0.get(i)); - } - deck0 = new ArrayList(); - turn = !turn; - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); - } - } - else { - isAttack = true; - dropCount = 0; - if(deck2.isEmpty()) { - return; - } - attackCount = checkGameStatus(); - turn = !turn; - } - System.out.println("뽑힌카드 : " +c); - } - } - } - public synchronized void doHit(String id) throws RemoteException{ - System.out.println("hit이 실행됨"); //플레이어 구분해서 해야하는데 아직 못함. - int who = -1; - for(int i = 0; i < client.size(); i++) { - if(id.equals(client.get(i))) { - who = i+1; - break; - } - } - Card []c=new Card[2]; - if(deck0.size() < 2) { - System.out.println("Hit Fail..."); - if(who == 1){ - for(int j = 0; j < deck0.size();j++) { - deck2.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = false; - } - else if(who == 2){ - for(int j = 0; j < deck0.size();j++) { - deck1.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = true; - } - - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); - } - else { - c[0]=deck0.get(deck0.size()-2); - c[1]=deck0.get(deck0.size()-1); - if(c[0].returnValue().equals(c[1].returnValue())) { - System.out.println("Hit Success..."); - if(who == 1) { - for(int j = 0; j < deck0.size();j++) { - deck1.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = true; - } - else if(who == 2) { - for(int j = 0; j < deck0.size();j++) { - deck2.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = false; - } - } - else { - System.out.println("Hit Fail!!!"); - if(who == 1){ - for(int j = 0; j < deck0.size();j++) { - deck2.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = false; - } - else if(who == 2){ - for(int j = 0; j < deck0.size();j++) { - deck1.add(deck0.get(j)); - } - deck0 = new ArrayList(); - turn = true; - } - } - System.out.println("aaa의 카드 수 : "+deck1.size()); - System.out.println("bbb의 카드 수 : "+deck2.size()); - System.out.println("깔려 있는 카드 수 :"+deck0.size()); - - } - dropCount = 0; - isAttack = false; - } - + deck0.add(c); + attackCount = checkGameStatus(); + if(attackCount == -1) { + turn = !turn; + } + else { + isAttack = true; + turn = !turn; + } + + } + else if(isAttack == true) { //공격 상태일 때 + System.out.println("player 2 drop! : Attack"); + if(deck2.isEmpty()) { + System.out.println("Player1 win!!"); + return; + } + c=deck2.get(0); + pop(); + + deck0.add(c); + + if(checkGameStatus() == -1) { //공격카드가 아닐 경우 + dropCount++; + + if(dropCount == attackCount) { //낸 카드의 수가 조건을 넘어갔을 떄 + dropCount = 0; + isAttack = false; + for(int i = 0; i < deck0.size(); i++) { + deck1.add(deck0.get(i)); + } + deck0 = new ArrayList(); + turn = !turn; + } + } + else { + isAttack = true; + dropCount = 0; + if(deck2.isEmpty()) { + return; + } + attackCount = checkGameStatus(); + turn = !turn; + } + } + } + } + public synchronized void doHit(String id) throws RemoteException{ + int who = -1; + for(int i = 0; i < client.size(); i++) { + if(id.equals(client.get(i))) { + who = i+1; + break; + } + } + Card []c=new Card[2]; + if(deck0.size() < 2) { + System.out.println("Hit Fail"); + if(who == 1){ + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = false; + } + else if(who == 2){ + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = true; + } + + } + else { + c[0]=deck0.get(deck0.size()-2); + c[1]=deck0.get(deck0.size()-1); + if(c[0].returnValue().equals(c[1].returnValue())) { + System.out.println("Hit Success"); + if(who == 1) { + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = true; + } + else if(who == 2) { + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = false; + } + } + else { + System.out.println("Hit Fail"); + if(who == 1){ + for(int j = 0; j < deck0.size();j++) { + deck2.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = false; + } + else if(who == 2){ + for(int j = 0; j < deck0.size();j++) { + deck1.add(deck0.get(j)); + } + deck0 = new ArrayList(); + turn = true; + } + } + } + dropCount = 0; + isAttack = false; + } + public void pop() { if(turn==true) { deck1.remove(0); @@ -406,7 +521,5 @@ public void push() { } } - - } \ No newline at end of file diff --git a/WarGameServer.java b/WarGameServer.java index 852221e..9aeca7e 100644 --- a/WarGameServer.java +++ b/WarGameServer.java @@ -43,113 +43,3 @@ public static void main(String[] args) throws UnknownHostException { } } -//public int whoClient(int clientID) { -// for (int i = 0; i < clientCnt; i++) -// if (client[i].getClientID() == clientID) -// return i; -// return -1; -//} -//public void putClient(int clientID, String inputLine) { -// for (int i = 0; i < clientCnt; i++) -// if (client[i].getClientID() == clientID) { -// System.out.println("writer: "+clientID); -// } else { -// System.out.println("write: "+client[i].getClientID()); -// client[i].out.println(inputLine); -// } -//} -//this is about chatting. so.. -//public void addClient(ServerSocket serverSocket) { -// Socket clientSocket = null; -// -// if (clientCnt < client.length) { -// try { -// clientSocket = serverSocket.accept(); -// clientSocket.setSoTimeout(40000); // 1000/sec -// } catch (IOException i) { -// System.out.println ("Accept() fail: "+i); -// } -// client[clientCnt] = new WarGameServerRunnable(this, clientSocket); -// new Thread(client[clientCnt]).start(); -// clientCnt++; -// System.out.println ("Client connected: " + clientSocket.getPort() -// +", CurrentClient: " + clientCnt); -// } else { -// try { -// Socket dummySocket = serverSocket.accept(); -// WarGameServerRunnable dummyRunnable = new WarGameServerRunnable(this, dummySocket); -// new Thread(dummyRunnable); -// dummyRunnable.out.println(dummySocket.getPort() -// + " < Sorry maximum user connected now"); -// System.out.println("Client refused: maximum connection " -// + client.length + " reached."); -// dummyRunnable.close(); -// } catch (IOException i) { -// System.out.println(i); -// } -// } -//} -//public synchronized void delClient(int clientID) { -// int pos = whoClient(clientID); -// WarGameServerRunnable endClient = null; -// if (pos >= 0) { -// endClient = client[pos]; -// if (pos < clientCnt-1) -// for (int i = pos+1; i < clientCnt; i++) -// client[i-1] = client[i]; -// clientCnt--; -// System.out.println("Client removed: " + clientID -// + " at client[" + pos +"], CurrentClient: " + clientCnt); -// endClient.close(); -// } -//} -//} -//class WarGameServerRunnable implements Runnable{ -// protected WarGameServer warGameServer=null; -// protected Socket clientSocket=null; -// protected PrintWriter out=null; -// protected BufferedReader in=null; -// public int clientID=-1; -// -// Game game=new Game(); -// ArrayList deck0=null;//내려놓는 곳 -// ArrayList deck1;//p1 deck -// ArrayList deck2;//p2 deck -// int playerCardCnt[]=new int[2];//player의 카드 갯 -// int deck0Cnt;//내려놓는 곳 카드 수 -// int turn=0; -// public WarGameServerRunnable(WarGameServer server,Socket socket){ -// this.warGameServer=server; -// this.clientSocket=socket; -// clientID=clientSocket.getPort(); -// try{ -// out=new PrintWriter(clientSocket.getOutputStream(),true); -// // out=new BufferedWriter(clientSocket.getOutputStream()); -// in=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); -// }catch(IOException ioe){} -// } -// public void run() { -// gameInit(); -// } -// public void close() { -// try { -// if(in !=null) in.close(); -// if(out !=null) out.close(); -// if(clientSocket!=null)clientSocket.close(); -// -// }catch(IOException i) { -// i.printStackTrace(); -// } -// } -// public int getClientID() { -// return clientID; -// } -// public void gameInit() { -// -// deck1=game.returnDeck1();//이미 셔플된 상태로 나온거라 따로 안해줘도 -// deck2=game.returnDeck2(); -// playerCardCnt[0]=deck1.size(); -// playerCardCnt[1]=deck2.size(); -// deck0Cnt=0; -// -// }