Slay the Spire

競プロ他の他はこういうこと

アーリーアクセスが終了して値上げするらしいので最安値ではなかったが購入した.1

こういう「駆け込み」で開発したゲームの多くは経験上,積まれる運命にあるのだが珍しくハマった.点けっぱなしなことも多いので正確な時間はわからないが現時点で85hプレイしている.にもかかわらず進度はイマイチで,シレンで言うところのテーブルマウンテンを攻略した程度.「深い」「泣けます…」

プレイ感としては風来のシレンゴッドフィールドと麻雀とロックマンエグゼを足したような足さないような.自分は四者とも好き.対人や協力要素がないのにこれらと肩を並べる面白さがあってすごい.最高です.

プレイメモ

基本方針

  • 休憩<鍛冶.ボスを倒すと(基本的に)全快する.
  • デッキ圧縮は直感以上に効果的.機会があれば積極的に狙っていく.
  • デッキ方針を早めに決める.一長一短なカードが多い.
  • 呪いはそこまで怖くない.リターンが強力なら全然あり.

    序章

  • モンスターを倒してカードとゴールドを集める.
  • 商人ではカード削除.ストライクと防御優先.
  • ボスグレムリンラガヴーリンは速攻.セントリーは一体だけ速攻であとは適当.
    スライムボス
  • HPを半分削るとnextが分裂に強制変化.攻撃ターンに合わせると効果的.
  • 分裂後のHPは分裂前の残HPなので,できるだけ大ダメージで分裂させる.頭数が増えるのはよくない.
    ヘクサゴースト
  • 多段ヒットを多用.脱力や筋力ダウンが効く.反射ダメージも良い.
  • 初回のインフェルノはHP依存なので気にしないことにする.
    ガーディアン
  • デッキによって難易度が変わる.スキルマシでは危険.
  • モードシフトを意図的に狙うのは難しい.
  • シャープハイドはアタック「プレイ」時に反応するので多段ヒットも安心して打てる.ブロックが有効なので先に張ること.

    シティ

  • ここまでにエナジー増加レリックがないとちょっと厳しい.
  • 敵が強い.敵よけとレリック集めを兼ねて?マスによるべき.
  • 呪われた本は絶対もらう.
  • エリートと雑魚の差が小さい.雑魚連戦よりかはエリートに行ったほうが損小利大.
    ブロンズ・オートマトン
  • 6ターン毎にハイパービーム.最悪なので2回目までに絶対倒す.
  • ミニオンに取られたカードは倒すと「手札」に戻ってくる.
    チャンプ
  • 速攻.できないなら基本負け.
    コレクター
  • 倒せるデッキなら倒せるしそうでないなら倒せない.よくわからない.

    彼方

  • 雑魚がそんなに強くない,というか苦戦してたらボスが無理.
  • 基本ボスに直行.お祈り.
    目覚めし者
  • 弱い
    デカ&ドヌー
  • ドヌーとかいう問題児を早く穀そう.
    タイムイーター
  • こいつ一番強いくせに一番出てくる
  • ターン強制終了時のブロック値に注意.あとデバフ解除.

    終点

    無理なので隠し
    矛と盾
    • ここでいかにHPを残すかみたいなところがある.
    • 矛を速攻する風潮あるけど盾のほうが強い気がする.
    • 矛は放ってほこう.
    堕落の心臓
    • 倒したことない
    • ディフェクトのフロストデッキが一番可能性ありそう.
    • どの主人公でもデッキに相当な完成度が要求されるので運ゲー.倍満ぐらい.




バフかけて俺TUEEEするゲームたのしい


  1. 一年経っても圧倒的に好評を外れなかったのが大きい

近況

f:id:ChiyosBigDragon:20181216000655p:plain f:id:ChiyosBigDragon:20181216000736p:plain

import numpy as np
import sympy
from scipy.optimize import curve_fit
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
fp = FontProperties(fname=r'C:\WINDOWS\Fonts\ipagp.ttf',size=28) # 日本語入力用
plt.rcParams['xtick.direction'] = 'in' # x軸の目盛りin/out/inout
plt.rcParams['ytick.direction'] = 'in' # y軸の目盛りin/out/inout
plt.rcParams['xtick.major.width'] = 1.0 # x軸主目盛り線の線幅
plt.rcParams['ytick.major.width'] = 1.0 # y軸主目盛り線の線幅
plt.rcParams['axes.linewidth'] = 1.0 # 軸の線幅edge linewidth。囲みの太さ
plt.rcParams['font.size'] = 20 # フォントサイズを設定 default : 12
# plt.rcParams['xtick.labelsize'] = 15 # 横軸のフォントサイズ
# plt.rcParams['ytick.labelsize'] = 15 # 縦軸のフォントサイズ
# plt.rcParams["figure.figsize"] = [20, 12] # グラフサイズ
# plt.gca().set_xscale('log')  # x軸をlogスケールで
orange = "#ff9800"
cyan = "#2196f3"
red = "#f44336"

# データ取得
x,y = np.loadtxt("./input", unpack=True)

# プロット
plt.plot(x,y,"o-",color=orange,label="Rating") # 折れ線
# plt.scatter(x,y,color="#ff9800",label="Rating") #散布図

# スプライン補間
# f = interp1d(x,y,kind='cubic') # 2d='quadratic'
# x1 = np.linspace(x[0],x[-1],1000)
# plt.plot(x1,f(x1),'-',color=cyan)

# フィッティング
def fit_func(x,a,b,c):
    return a*np.log10(x+b)+c
res,cov = curve_fit(fit_func,x,y)
print(res)
a=res[0]
b=res[1]
c=res[2]
x1 = np.linspace(0,800,100) # [0,800]を100等分したxの値を生成
y1 = a*np.log10(x1+b)+c
plt.plot(x1,y1,color=cyan,label="Fitting")
plt.scatter(10**((1600-c)/a)-b,1600,color=red,label="Fitting")
pre = int(np.ceil(10**((1600-c)/a)-b))
plt.text(pre,1600,pre,color=red)

# 表示
plt.xlim(0,800)
plt.ylim(0,1700)
plt.xlabel('Day',fontproperties=fp) # x軸ラベル
plt.ylabel('Rating',fontproperties=fp) # y軸ラベル
plt.grid(which="both") # グリッド表示
# plt.legend(prop=fp) # 凡例表示/場所指定loc="upper left"
plt.show()

今日の反省会場

AtCoder Grand Contest 028 - AtCoder

早解きしないとまずいと思ったので嘘っぽいとは思いつつ投げたらWA。撤退できなくなる。BもCも救いがなかったので残り30分からAを嘘のまま改善した。茶パフォでも大きいくらい😇
あしたはがんばります。

大嘘解法

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) (x).begin(),(x).end()
using namespace std;
const int INF=1145141919,MOD=1e9+7;
const long long LINF=8931145141919364364,LMOD=998244353;
// const int dx[]={1,0,-1,0,1,1,-1,-1},dy[]={0,-1,0,1,1,-1,-1,1};

int gcd(int x,int y){
    if(x<y) swap(x,y); //常にx>=y
    //ユークリッドの互除法
    if(!(x%y)) return y;
    else return gcd(y,x%y);
}

int main(){
    long long n,m; cin>>n>>m;
    string s,t; cin>>s>>t;
    // if(max(n,m)%min(n,m)==0){
    //     cout<<-1<<endl;
    //     return 0;
    // }
    long long cnt=0;
    for(long long i=n*m/gcd(n,m);;i+=n*m/gcd(n,m),cnt++){
        if(i<0||i>LINF||cnt>1e3) break;
        // cout<<i<<endl;
        long long ss=0,tt=0;
        bool flg=1;
        while(ss<n&&tt<m){
            // cout<<ss<<" "<<tt<<endl;
            if(ss*i/n==tt*i/m){
                if(s[ss]!=t[tt]){
                    flg=0;
                    break;
                }
            }
            if(ss*i/n>tt*i/m) tt++;
            else ss++;
        }
        if(flg){
            cout<<i<<endl;
            return 0;
        }
    }
    cout<<-1<<endl;
    return 0;
}

ARC061-E すぬけ君の地下鉄旅行/Snuke's Subway Trip

問題URL:すぬけ君の地下鉄旅行/Snuke's Subway Trip
最近ダイクストラ書きすぎて、そらで書けるようになってきた。mapmap入れる書き方は結構気に入ってるけど、枝刈りがちょい面倒なのと計算量やばそう。CFとかでこれがボトルネックで落ちたら考える。

考察

このまえおぼえた拡張ダイクストラをやればいいんだろうな

実装

思うままに書いたらTLEした。頂点数の2倍ぐらいで済むと思っていたが多分O(M^{2})なのでしょう。つらい。

TLE解(クリックで展開)

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) (x).begin(),(x).end()
using namespace std;
const int INF=1145141919,MOD=1e9+7;
const long long LINF=8931145141919364364,LMOD=998244353;
// const int dx[]={1,0,-1,0,1,1,-1,-1},dy[]={0,-1,0,1,1,-1,-1,1};

#define ppi pair<int,pair<int,int>>
#define fi first
#define se second
// edge[from]={to,color}
vector<pair<int,int>> edge[100010];
// cost[goal][color]
map<int,map<int,int>> cost;

int main(){
    int n,m; cin>>n>>m;
    rep(i,m){
        int p,q,c; cin>>p>>q>>c;
        edge[p].push_back({q,c});
        edge[q].push_back({p,c});
    }
    // {cost,{from,color}}
    priority_queue<ppi,vector<ppi>,greater<ppi>> pq;
    pq.push({0,{1,-1}});
    while(pq.size()){
        auto pre=pq.top(); pq.pop();
        int pre_place=pre.se.fi,pre_color=pre.se.se,pre_dist=pre.fi;
        // cout<<pre_place<<" "<<pre_color<<" "<<pre_dist<<endl;
        for(auto to:edge[pre_place]){
            int to_place=to.fi,to_color=to.se;
            if(cost[to_place][to_color]==0||pre_dist+(pre_color==to_color?0:1)<cost[to_place][to_color]){
                cost[to_place][to_color]=pre_dist+(pre_color==to_color?0:1);
                // cout<<"in:"<<to_place<<" "<<to_color<<" "<<cost[to_place][to_color]<<endl;
                pq.push({cost[to_place][to_color],{to_place,to_color}});
            }
        }
    }
    int ans=INF;
    for(auto i:cost[n]){
        ans=min(ans,i.second);
    }
    cout<<(ans==INF?-1:ans)<<endl;
    return 0;
}


結局editorialを見た。すごい。参考にして枝刈りしたらWAした。ひどい。でも方針は間違ってないはず。書き直さないで敢えてひたすら刈る。盆栽?
色々やってたらなんか通ってしまった(2137ms)
多分この行が一番効果的だったと思います。

if(pre_dist>=cost[pre_place][-1]+1) continue;
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) (x).begin(),(x).end()
using namespace std;
const int INF=1145141919,MOD=1e9+7;
const long long LINF=8931145141919364364,LMOD=998244353;
// const int dx[]={1,0,-1,0,1,1,-1,-1},dy[]={0,-1,0,1,1,-1,-1,1};

#define ppi pair<int,pair<int,int>>
#define fi first
#define se second
// edge[from]={to,color}
vector<pair<int,int>> edge[100010];
// cost[goal][color]
map<int,map<int,int>> cost;

int main(){
    int n,m; cin>>n>>m;
    rep(i,m){
        int p,q,c; cin>>p>>q>>c;
        edge[p].push_back({q,c});
        edge[q].push_back({p,c});
    }
    // {cost,{from,color}}
    priority_queue<ppi,vector<ppi>,greater<ppi>> pq;
    pq.push({0,{1,-1}});
    while(pq.size()){
        auto pre=pq.top(); pq.pop();
        int pre_place=pre.se.fi,pre_color=pre.se.se,pre_dist=pre.fi;
        if(cost[pre_place][-1]==0||pre_dist<cost[pre_place][-1]){
            cost[pre_place][-1]=pre_dist;
            if(pre_place!=1) pq.push({cost[pre_place][-1],{pre_place,-1}});
        }
        if(pre_dist>=cost[pre_place][-1]+1) continue;
        // cout<<pre_place<<" "<<pre_color<<" "<<pre_dist<<endl;
        for(auto to:edge[pre_place]){
            int to_place=to.fi,to_color=to.se;
            if(pre_color==-1){
                if(cost[to_place][to_color]==0||pre_dist+1<cost[to_place][to_color]){
                    cost[to_place][to_color]=pre_dist+1;
                    pq.push({cost[to_place][to_color],{to_place,to_color}});
                }
            }else{
                if(pre_color==to_color){
                    if(cost[to_place][to_color]==0||pre_dist<cost[to_place][to_color]){
                        cost[to_place][to_color]=pre_dist;
                        pq.push({cost[to_place][to_color],{to_place,to_color}});
                    }
                }
            }
        }
    }
    cout<<(cost[n][-1]==0?-1:cost[n][-1])<<endl;
    return 0;
}

ARC061-D すぬけ君の塗り絵/Snuke's Coloring

問題URL:すぬけ君の塗り絵/Snuke's Coloring
制約があからさま過ぎだからできる人は秒で終わりそう。

考察

制約からして黒マス中心に考えるしかない。全ての3\times 3の正方形のうち、黒マスを含むものは高々9Nしかないので、これらが含む黒マスの個数を数えてみる。時間は大丈夫そうだけど、メモリが怪しい。

実装

map使うとほとんど感覚通りに書けたので特になし。

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define all(x) (x).begin(),(x).end()
using namespace std;
const int INF=1145141919,MOD=1e9+7;
const long long LINF=8931145141919364364,LMOD=998244353;
// const int dx[]={1,0,-1,0,1,1,-1,-1},dy[]={0,-1,0,1,1,-1,-1,1};

int main(){
    int h,w,n; cin>>h>>w>>n;
    // 中心が{y,x}である3*3マスに含まれる黒マス
    map<pair<int,int>,int> mp;
    rep(i,n){
        int a,b; cin>>a>>b;
        for(int y=max(a-1,2);y<=min(a+1,h-1);y++){
            for(int x=max(b-1,2);x<=min(b+1,w-1);x++){
                mp[{y,x}]++;
            }
        }
    }
    long long ans[10]={}; ans[0]=(long long)(h-2)*(w-2);
    for(auto i:mp){
        ans[i.second]++;
        ans[0]--;
    }
    rep(i,10) cout<<ans[i]<<endl;
    return 0;
}

まらそん

以下に参加中です。期間終了後この記事は追記予定ですが、スコアが終了した場合は記事ごと消えます。

スコア : 2,396,247 で終了しました。多分120thぐらい。
チャレンジスコアにも届かなかったのでアレなんですけど、長期間のマラソンは初参加だったので記念に残しておきます。途中までは書いてるからすぐに公開できるはず。