Newer
Older
Ruby / odquiz.rb
#!/usr/bin/env ruby
#-*- coding: utf-8 -*-

#csquizのやばくなった方です。いつか絶対動かす!!
#なんでやばくなった、って、、3択未満でも動くようにしたいじゃないですかぁ
#そしてnil対応が間に合わなかった((泣))のコードですす、、書き換えかけ

require 'csv'
require 'roo'

ods = Roo::Spreadsheet.open("quizod.ods")        #odsをもってくる
neta = CSV.parse(ods.to_csv, :headers => true)   #odsをcsvにする

fuseikai = 0
def wrong()
  puts"不正解!"
  sleep(0.5)

end

def makeNumbers(santaku) #三択未満の場合に備え、割り振る番号の調整
  santaku = santaku.compact
  numbers = []
  (santaku.length).times do |num|
    numbers << (num+1).to_s
  end
  return numbers                # 1 => "選択肢1",2 => "選択肢3" とか
end                             # 1 => "選択肢2" とかに対応する番号の配列


# ans = answer,opt = row["オプション"],san = santaku,seikai = row["答え"],fu = fuseikaiと書きたいけど無理だった
def isRightAns(ans,opt,san,seikai,fu)

  alreadySantaku = (fu >= 3)
  ansAry = ans.chars
  ansLength = ans.length
  santakuNumbers = makeNumbers(san)
  santakuTotalLength = san.join.length     

  if san[0]  #でえきたあ(?)
    aboutAnsA ={ansIsIt:  (ans == san[0]), ansHasIt:  (Regexp.new(san[0]) =~ ans),
                ansIsNum: (ans ==    "1"), ansHasNum: (Regexp.new(   "1") =~ ans)}
  end                     # sanにnilがあるとinclude?で
  if san[1]               # エラーになるのでこうなった
    aboutAnsB ={ansIsIt:  (ans == san[1]), ansHasIt:  (Regexp.new(san[1]) =~ ans),
                ansIsNum: (ans ==    "2"), ansHasNum: (Regexp.new(   "2") =~ ans)}
  end
  if san[2]
    aboutAnsC ={ansIsIt:  (ans == san[2]), ansHasIt:  (Regexp.new(san[2]) =~ ans),
                ansIsNum: (ans ==    "3"), ansHasNum: (Regexp.new(   "3") =~ ans)}
  end
  aboutAns = [aboutAnsA,aboutAnsB,aboutAnsC].compact
  ansHasAll = []                # 判断材料を集めるために一時的に配列にしている
  ansIsAll  = []
  doreka = []
  aboutAns.each do |aa|
    ansHasAll << aa[:ansHasIt]
    doreka    << (aa[:ansIsNum]&& alreadySantaku) || aa[:ansIsIt]
  end
  ansHasAll = ansHasAll.compact.all?
  doreka = doreka.compact.one?
  
  jyunfudou_AnsIsAll = san.permutation.zip(santakuNumbers.permutation) do |p,n|
    ansIsAll << (ans == p.join      || ans == n.join      ||
                 ans == p.join(",") || ans == n.join(",") ||
                 ans == p.join(" ") || ans == n.join(" ") ||
                 ans == p.join("、")|| ans == n.join("、"))
  end
  
  ansIsAll = (ansIsAll.one?) || (ansHasAll && ansLength == santakuTotalLength)
  aboutAllAns = {ansHasAll: ansHasAll,
                 ansIsAllNumbers: (ansAry + santakuNumbers).tally == {},
                 ansIsAll:  ansIsAll
                }
  
  #ansIs順不同

  selectNumber = (ans.to_i)-1
  select = san[selectNumber]
  
  #文字で答えた場合 || 番号で答えた場合
  if opt =~/(すべて)/
    return  (aboutAllAns[:ansIsAll]) ||
            (aboutAllAns[:ansIsAllNumbers] && alreadySantaku)

  elsif opt =~ /(どれかひとつ)/
    return doreka

  else    #通常の三択
    return false if ans == ""
    return (ans == seikai) || (select == seikai && alreadySantaku)

  end        
    
end


def putAnswer(row,santaku)
  if row["答え"] != nil      # 正解表示(通常)
    printf("正解は%sでした。\n",row["答え"])
    return
  end
  # 以下では row["答え"] = nil
  if    row["オプション"] =~ /(すべて)/  # 正解表示(すべて)
    printf("正解は%sすべてでした。\n",*santaku)
    return
    
  elsif row["オプション"] =~ /(どれかひとつ)/ # 正解表示(どれか)
    printf("正解は%sの中からひとつでした。\n",*santaku)
    return
  end  
end

def makeSelectHash(keyAry,valAry)
  keyAry.compact!
  valAry.compact!
  newHash = {}
  newAry = []
  keyAry.zip(valAry).each do|key,val|
    newAry << [key,val]if key && val      # なんかちゃう?
  end
  newAry.compact.to_h
  
end

setumei = ["カスタムクイズ",
           "              説明",
           "専用のodsを使うことで、自由にクイズを作ることができます。",
           "ですが今回は私についてのクイズになっています。",
           "特別版ということです。といっても実はquiz2102を書き換えればカスタマイズ可能です。",
           "特別版だからってodsからの設定ではできないことをやるのは個人的に嫌なので、",
           "「この説明文」と「呼び出すodsファイルの名前」以外は通常版と全く同じものになっています。",
           "調整中。。。"
          ]

for i in setumei
  puts i
end
gets

countAns = 0
countRight = 0

count = 0                       # 今何問目なのか
print("\e[2J")
print("\e[H")

startTime = Time.now.to_i
neta.each{|row|

          if row["オプション"] == "表示物"
            printf("%s\n",row["問題"])
            gets
            print("--------------------------\n")
            next
          end
              count += 1
              dasita = 0
              comeback = 0
             printf("第%d問\n",count) 
             printf("%s\n", row["問題"])
             santaku = [row["三択1"], row["三択2"], row["三択3"]]
             sanHash = makeSelectHash([:'1',:'2',:'3'],santaku,)
             santaku.compact!
             fuseikai = 0   # fuseikai >= 3で三択表示
             kaitou = nil
          while true
                       
               #入力と三択システム
              if comeback == 1
                wrong
                
              end
              if row["オプション"] =~ /(三択なし)/ # 意地悪問題がいい人へ
                dasita = 1
                
              elsif ( fuseikai == 3 || row["オプション"] =~ /(三択)/ ) &&
                    dasita   != 1
                if row["オプション"] =~ /(三択)/
                  fuseikai = 3
                end
                num = 1         # 選択肢の番号
                for i in santaku
                  printf("%d => %s\n",num,i)
                  num += 1
                end
                dasita = 1   # dasitaが1 =「三択出した」 2回以上の三択表示を防ぐ
              end
              
              print"答えを入力..."
              kaitou = gets.chomp
              countAns += 1

             if row["オプション"] !~ /(判定なし)/
              if isRightAns(kaitou,row["オプション"],santaku,row["答え"],fuseikai)
                puts"正解!!"
                countRight += 1
                sleep(0.5)
                break
              else
                fuseikai += 1
                wrong
                if row["オプション"] !~ /(1回だけ)/
                 print("\e[2A")      # 2行上
                 print("\e[J")        # 下のやつを消す
                end
              end
             end
              if row["オプション"] =~ /(正解を出す)/
                putAnswer(row,santaku)
              end
              if row["オプション"] =~ /(1回だけ|判定なし)/
                break
              end
                
          end
          if row["解説"]
            printf("%s\n",row["解説"])
            gets
            print"\e[1A"
          end
        
            print("--------------------------\n") #何個でもいい仕切りの機能
          }
if false
# 終了時演出の変数の準備
finishTime = Time.now.to_i

text = neta["変更テキスト"][0]
finish = neta["終了時演出"][0]

seitouritu = (((countRight.to_f)/(countAns.to_f))*100).truncate(1)
keikajikan = (finishTime - startTime)
heikinjikan = ((keikajikan.to_f)/(count.to_f)).truncate(1)


# 終了時演出の表示
  printf("正解数: %d回/%d回中     ",countRight,countAns)if finish =~ /(結果表示)/

  printf("正答率: #{seitouritu}%%     ")if finish =~ /(正答率)/
print"\n" if finish =~ /(正解表示|正答率)/
  printf("経過時間: %d秒     ",keikajikan)if finish =~ /(経過時間)/

  printf("平均回答時間: #{heikinjikan}秒     ")if finish =~ /(平均時間)/

print"\n"
if text
  printf("%s\n",text)if text != "なし"
else
  puts"終了!!おつかれさまでした!"
end
# おつかれさまでした!!
end