【java】ロト6で夢を買おう～申込番号を決めてみよう～

#１．きっかけ

ここ1年半話題といえば__「コロナ絶賛感染拡大中！一年半前の数人から今は5000人に伸びました！」__
という話でニュースがにぎわっている。
__`オリンピックで日本経済が盛り上がる予定だったけど、夢に終わってしまった。`__
さらに、と悪いことを挙げればきりがない。

そんな暗い空気を背負って、テレワークを終えて近所を歩いていた。
私と同じ暗い空気をまといながらも、やけに野望に燃えた目の人々が集まっている場所がある。
高額当選を叩き出した宝くじ売り場だ。
その集まりの先に「キャリーオーバー発生中！」「サマージャンボ」のポスターが見えた。
「では〇〇と〇〇で五万円になります。」と無機質な店員さんの声も聞こえる。
渋い顔をしたオジサンが、財布からお札を取り出している。
サマージャンボやロトの当選金額の大きさと、列に並ぶ人の熱気に呑まれてしまった。
__「これもし当たったら、どうしよう？？？」__と根拠のない自信が溢れ出してきた。
サマージャンボは、自分で番号を決められないけど、ロト6、ロト7は自分で番号を決められるということも分かった。
しかもキャリーオーバー発生中で、当選金額も大きくなっている。

ロト6は毎週結果がわかるということも、サマージャンボより、1等当選の確率がわずかに高いことも大きな興味を持った。
ロト6だと1から43までの数字から、重複しない6つの数字を選ぶことができる。
でもいざとなると、どうやって数字を選べばいいかわからない。
とりあえずクイックピック(機械が自動で6つの数字の組み合わせを出してくれる仕組み)でトライをしてみた。

__結果発表前日は眠れなかった。当たったらどうしようと緊張をしていた。
慌てないように1等当選したときのリハーサルも頭の中で重ねてきた。__

結果はどうだったかというと
####`【清々しいまでに外れていた(泣)】`

何一つ、自分で努力もしなかった癖に、もの凄く悔しかった。
####`「確実に一等当選する方法は、6,096,454通りの数字の組み合わせでロト6を購入する事。」`

ただ、それだと憶単位のマイナスになってしまう。
その事実を知った時の心境は。。。
某有名漫画の登場人物のセリフを思い出した。
到底勝てない敵に立ち向かった時のあのセリフ。
####『どうせ死ぬなら戦って死ぬ』

自分で番号を決められるのに人任せにする事はない。
どうせコロナが怖くてどこにも出られないのだ。
クイックピックを自作してみようと考えた。

#２．目標

+ __申し込み口数分で重複しない第一数字～第六数字の組み合わせを表示したい。(全桁自動のものと、一桁好きな数字を含むもの)__
+ __過去の当選番号以外の申し込み候補番号を表示したい。__

#３．実行環境
xamppのバージョン：7.2.3
eclipseのバージョン：Version: 2019-12 (4.14.0)
mariadbのバージョン:10.1.31
java:11
OS:windows10 home 64bit

#４．実装

※下記のソース内で使っているテーブルの構造
![loto6_tbl.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689780/764c25d6-6895-b5a9-17df-e1a2dc78bd77.jpeg)

※キャリーオーバー中かや、ボーナス数字の情報は入れていません。

```java:LotoBean1.java
package model;
public class LotoBean1 {
  private int n_cnt;
  private int like_num;
  private String lot6_str;

  public int getN_cnt() {
    return n_cnt;
  }
  public void setN_cnt(int n_cnt) {
    this.n_cnt = n_cnt;
  }
  public String getLot6_str() {
    return lot6_str;
  }
  public void setLot6_str(String lot6_str) {
    this.lot6_str = lot6_str;
  }
  public int getLike_num() {
    return like_num;
  }
  public void setLike_num(int like_num) {
    this.like_num = like_num;
  }
}
```
`メモ１）ArrayListは、要素数を自由に変更できるので便利`
`メモ２）要素を追加する場合は ArrayList配列名.Add(追加したい値)`
`メモ３）特定の要素を削除する場合はArrayList配列名.remove(削除したい値の要素番号)`
`メモ４）ArrayListの全要素を削除するのは配列名.clear`
`メモ５）ある要素が対象のArrayListに含まれるかを調べるのはArrayList配列名.contains(調べたい値)：含まれる場合はtrue`


```java:CalcLotoBean.java
package model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
public class CalcLotoBean {
  public void execute(LotoBean1 loto1) {
    int cnum0=loto1.getN_cnt();
    int like_num0=loto1.getLike_num();
    String ret_loto6=getlot6data(cnum0,like_num0);
    loto1.setLot6_str(ret_loto6);
  }
  private String getlot6data(int cnum,int like_num2) {
    String retstr="";
    String tmpstr="";
    //計算回数が6096454を超えたときにfalse
    boolean flg=true;
    //カンマで連結した6つの数字の文字列を格納する配列
    ArrayList<String> lotoarr = new ArrayList<>();

    int i=0;
    long n=0;
    while(i<cnum) {
      int chk_flg=0;
      tmpstr=make_6number(like_num2);

      //tmpstrがlotoarrにない場合
      if(lotoarr.contains(tmpstr) == false ) {
        chk_flg=check_uniqedata(tmpstr);
        if(chk_flg==2) {
          return "その他のエラー発生<br>";
        }
        if(chk_flg==0) {
          lotoarr.add(tmpstr);
          i++;
        }
      }

      if(n>6096454) {
        flg=false;
        break;
      }
      n++;
    }

    if(flg==false) {
      return "組み合わせが存在しません<br>";
    }
    for(i=0;i<cnum;i++) {
      if(i>0) {
        retstr=retstr+"<br>"+lotoarr.get(i);
      }else {
        retstr=retstr+lotoarr.get(i);
      }
    }
    return retstr;
  }

  private String make_6number(int like_num2) {
    String tmpstr="";
    //ランダムに選ばれる番号を入れる配列
    ArrayList<Integer> arrrandom=new ArrayList<>();
    int len1=6;
    if(like_num2>0) {
      len1=5;
    }
    int[] tmpnum= new int[6];
    //最終の位置に好きな番号を入れる
    if(like_num2>0) {
      tmpnum[5]=like_num2;
    }
    //1から43までをarrrandomに入れる
    for(int k=0;k<43;k++) {
      if(like_num2>0) {
        //好きな番号は追加しない。
        if(like_num2!=k+1) {
          arrrandom.add(k+1);
        }
      }else {
        arrrandom.add(k+1);
      }
    }
    for(int j=0;j<len1;j++) {
      int num0=(int)(Math.random()*arrrandom.size());
      tmpnum[j]=arrrandom.get(num0);
      //arrrandomから既に選ばれたtmpnum[j]を削除する
      arrrandom.remove(arrrandom.indexOf(tmpnum[j]));
    }
    //全要素の削除
    arrrandom.clear();
    //配列のソート
    Arrays.sort(tmpnum);
    for(int j=0;j<6;j++) {
      if(j>0) {
        tmpstr=tmpstr+","+tmpnum[j];
      }else {
        tmpstr=tmpstr+""+tmpnum[j]+"";
      }
    }
    return tmpstr;
  }

  //既にDBに登録されている番号と重複していないかチェック
  private int check_uniqedata(String checkstr) {
    final String URL
      = "jdbc:mariadb://localhost:3306/loto6_db?useUnicode=true&characterEncoding=utf8mb4";
    String USER = "root";
    String PASS = "";
    int [] chknum={0,0,0,0,0,0};
    String[] tmpstr0=checkstr.split(",");
    for(int i=0;i<6;i++) {
      chknum[i]=Integer.parseInt(tmpstr0[i]);
    }
    final String sql = "select * from loto6_tbl where num1=? and num2=? and num3=? and num4=? and num5=? and num6=?";
    try(Connection conn =
      DriverManager.getConnection(URL, USER, PASS)){

      conn.setAutoCommit(false);

      PreparedStatement ps = conn.prepareStatement(sql);

      for(int i=0;i<6;i++) {
        ps.setInt(i+1,chknum[i]);
      }
      try(ResultSet rs = ps.executeQuery()){
        //条件を満たすレコードが存在しないとき
        if(!rs.next()) {
          return 0;
        //条件を満たしたレコードが存在するとき
        }else {
          return 1;
        }
      } catch (Exception e) {
        conn.rollback();
        System.out.println("rollback");
        return 2;
      }
    }catch(Exception e) {
      e.printStackTrace();
      return 2;
    }finally {
      System.out.println("処理が完了しました");
    }
  }
}
```

```java:Loto6Servlet.java
package servlet;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.CalcLotoBean;
import model.LotoBean1;
/**
 * Servlet implementation class Loto6Servlet
 */
@WebServlet("/Loto6Servlet")
public class Loto6Servlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public Loto6Servlet() {
        super();
        // TODO Auto-generated constructor stub
    }

  /**
   * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub

      RequestDispatcher dispatchar=request.getRequestDispatcher("input_loto.jsp");
      dispatchar.forward(request, response);
  }

  /**
   * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
   */
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    if (request.getParameter("btn_auto") != null) {
        //口数
      int select_num=Integer.parseInt(request.getParameter("sel_num"));
      //好きな数字を0とする
      int like_num0=0;
      LotoBean1 loto6=new LotoBean1();
      loto6.setN_cnt(select_num);
      loto6.setLike_num(like_num0);
      CalcLotoBean calcloto6=new CalcLotoBean();
      calcloto6.execute(loto6);
      request.setAttribute("loto6_result", loto6);
      RequestDispatcher dispatchar2=request.getRequestDispatcher("loto6_result.jsp");
      dispatchar2.forward(request, response);
    }
    if (request.getParameter("btn_auto2") != null) {
        //口数
      int select_num=Integer.parseInt(request.getParameter("sel_num2"));
        //好きな数
      int like_num0=Integer.parseInt(request.getParameter("sel_like_num2"));

      LotoBean1 loto6=new LotoBean1();
      loto6.setN_cnt(select_num);
      loto6.setLike_num(like_num0);
      CalcLotoBean calcloto6=new CalcLotoBean();
      calcloto6.execute(loto6);
      request.setAttribute("loto6_result", loto6);
      RequestDispatcher dispatchar2=request.getRequestDispatcher("loto6_result.jsp");
      dispatchar2.forward(request, response);
    }
  }
}
```
```jsp:input_loto.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>口数入力</title>
</head>
<body>
<h1>6桁の数字が自動で出力されるタイプ</h1>
<form action="/loto6/Loto6Servlet" method="post">
<h3>
口数  :
<select name="sel_num">
	<option>3</option>
	<option>5</option>
	<option>7</option>
</select>
<input type="submit" name="btn_auto" value="出力">
<br>
</h3>
<h1>好きな数字を1つだけ選択できるタイプ</h1>
<h3>
口数  :
<select name="sel_num2">
	<option>3</option>
	<option>5</option>
	<option>7</option>

</select>
<br>
くじに入れる数字  :
<select name="sel_like_num2">

<% for(int i=0;i<43;i++){ %>
	<option><%= i+1 %></option>
<% } %>
</select>
<input type="submit" name="btn_auto2" value="出力">
</h3>
</form>

</body>
</html>
```

```jsp:loto6_result.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- 下記でモデルを指定するとモデル内のデータを取得できるようになる --%>
<%@ page import ="model.LotoBean1" %>
<% LotoBean1 loto6_r=(LotoBean1) request.getAttribute("loto6_result"); %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>結果</title>
</head>
<body>
<h1>結果</h1>
<h2>
結果：<br>
<%= loto6_r.getLot6_str() %><br><br>
<a href="/loto6/input_loto.jsp">戻る</a>
</h2>
</body>
</html>
```
#５．実行結果

__(1)全自動で7口申し込みしたとき__

![loto6_auto.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689780/4856546d-a1cc-072b-7269-067e7c7eb2c9.jpeg)

![loto6_auto_result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689780/416d3525-5087-965b-ff13-99984f1eae7d.jpeg)
重複しない7口分の組み合わせが表示

__(2)好きな数字11を選んで5口申し込みしたとき__

![loto6_auto2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689780/b049989d-7b5a-eef9-1142-6ebb2ecad3ed.jpeg)
![loto6_auto_result2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689780/c7521e40-e274-99af-8a6c-d1f5ae6eb7c7.jpeg)

数字11を含む重複しない5口分の組み合わせが表示。

#６．参考url
[ロト６生活](http://sougaku.com/loto6/data/list1/)

#７．最後に

こういう予測ロジックを入れたら1000万以上の高額当選をされた、
という情報が頂けたら嬉しいです。(笑)
この記事を読んでくれた方も、私も大きく当たりますように。