UNOシミュレータ [ yukicoder No.769 ]
問題
UNOの対戦ログから局面をシミュレーションして、
・勝った人の番号
・勝った人が最初に持っていた手札の枚数
を出力せよ。
考察
純粋な実装の問題です。
よって、コードを見ていただいたほうが手っ取り早いです。
コード
void solve (FastScanner in, PrintWriter out) { int n = in.nextInt(), m = in.nextInt(); String[] turn = in.nextArray(m); int next = 0; //次は誰の番か int[] put = new int[n]; //i番目の人がカードを何枚置いたか int[] draw = new int[n]; //i番目の人がカードを何枚引いたか boolean reverse = false; //順番の方向(reverseが置かれるたびに変化) int draw2Num = 0; //drawtwoが場に何枚蓄積されているか int draw4Num = 0; //drawfourが場に何枚蓄積されているか for (int i=0; i<m; i++) { //next番目の人がカードを置く put[next]++; //最後の人がカードを置いた場合、そこで終了なのでループを抜ける if (i == m-1) break; if (turn[i].equals("drawtwo")) { draw2Num += 2; //場へ蓄積させる //次の人が最後の人でなく、かつ、置いた札が"drawtwo"でない場合、 //その人の一つ前の人に蓄積した"drawtwo"を引かせる if (i!=m-1 && !turn[i+1].equals("drawtwo")) { //次の人へターンを回す関数 next = nextTurn(next, 1, n, reverse); //蓄積した"drawtwo"を引く draw[next] += draw2Num; draw2Num = 0; } //もう1回ターンを回す(補足にて後述) next = nextTurn(next, 1, n, reverse); } else if (turn[i].equals("drawfour")) { //"drawtwo"と同じ draw4Num += 4; if (i!=m-1 && !turn[i+1].equals("drawfour")) { next = nextTurn(next, 1, n, reverse); draw[next] += draw4Num; draw4Num = 0; } next = nextTurn(next, 1, n, reverse); } else if (turn[i].equals("skip")) { next = nextTurn(next, 2, n, reverse); //移動量を2にする } else if (turn[i].equals("reverse")) { reverse = reverse==true? false : true; //方向を逆転 next = nextTurn(next, 1, n, reverse); } else { //通常のターン移行 next = nextTurn(next, 1, n, reverse); } } //<出力> //最後に置いた人は、その時点で手札が0枚のはず //最初に持っていた枚数 - 置いた枚数 + 引いた枚数 = 0 //最初に持っていた枚数 = 置いた枚数 - 引いた枚数 out.println((next+1)+" "+(put[next]-draw[next])); } static int nextTurn (int now, int move, int num, boolean b) { if (b == true) { return Math.max(now-move, (now-move+num)%num); } else { return Math.min(now+move, (now+move)%num); } }
補足
この問題で一番難しいのは "drawtwo","drawfour" の処理です。
"drawtwo" の処理を例にとって説明します。
ログに
・drawtwo
・number
とあった場合、
・i 番目の人が "drawtwo" を置く
・i+1 番目の人が "number" を置く
ではなく、
・i 番目の人が "drawtwo" を置く
・i+1 番目の人がカードを2枚引く
・i+2 番目の人が "number" を置く
と処理しなければなりません。ログは2つですが、実際には3人のプレイヤーが関与しています。
ではここで、上記のコードの "drawtwo" の処理部分を見てみます。
if (turn[i].equals("drawtwo")) { //i番目の人の処理 draw2Num += 2; //i+1番目の人の処理 if (i!=m-1 && !turn[i+1].equals("drawtwo")) { next = nextTurn(next, 1, n, reverse); draw[next] += draw2Num; draw2Num = 0; } //i+2番目の人にターンを回す処理 next = nextTurn(next, 1, n, reverse); }
他のカードより余計にターンが回されていたのは、ログには現れないプレイヤーがいたせいなんですね。