sync: implement hint dependency on flags
This commit is contained in:
parent
6ad11e49d5
commit
f3a34c00db
5 changed files with 175 additions and 116 deletions
|
|
@ -174,6 +174,104 @@ type importFlag struct {
|
|||
FlagsDeps []int64
|
||||
}
|
||||
|
||||
// buildExerciceFlags read challenge.txt and extract all flags.
|
||||
func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nline int) (ret []importFlag, errs []string) {
|
||||
switch strings.ToLower(flag.Type) {
|
||||
case "":
|
||||
flag.Type = "key"
|
||||
case "key":
|
||||
flag.Type = "key"
|
||||
case "vector":
|
||||
flag.Type = "vector"
|
||||
case "ucq":
|
||||
flag.Type = "ucq"
|
||||
case "mcq":
|
||||
flag.Type = "mcq"
|
||||
default:
|
||||
errs = append(errs, fmt.Sprintf("%q: flag #%d: invalid type of flag: should be 'key', 'mcq', 'ucq' or 'vector'.", path.Base(exercice.Path), nline+1))
|
||||
return
|
||||
}
|
||||
|
||||
if flag.Type == "key" || flag.Type == "ucq" || flag.Type == "vector" {
|
||||
addedFlag, choices, berrs := buildKeyFlag(exercice, flag, nline+1, "Flag")
|
||||
if len(berrs) > 0 {
|
||||
errs = append(errs, berrs...)
|
||||
}
|
||||
if addedFlag != nil {
|
||||
ret = append(ret, importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: *addedFlag,
|
||||
Choices: choices,
|
||||
})
|
||||
}
|
||||
} else if flag.Type == "mcq" {
|
||||
addedFlag := fic.MCQ{
|
||||
IdExercice: exercice.Id,
|
||||
Title: flag.Label,
|
||||
Entries: []fic.MCQ_entry{},
|
||||
}
|
||||
|
||||
hasOne := false
|
||||
isJustified := false
|
||||
|
||||
if !flag.NoShuffle {
|
||||
rand.Shuffle(len(flag.Choice), func(i, j int) {
|
||||
flag.Choice[i], flag.Choice[j] = flag.Choice[j], flag.Choice[i]
|
||||
})
|
||||
}
|
||||
|
||||
for cid, choice := range flag.Choice {
|
||||
var val bool
|
||||
|
||||
if choice.Raw != nil {
|
||||
if hasOne && !isJustified {
|
||||
errs = append(errs, fmt.Sprintf("%q: error MCQ #%d: all true items has to be justified in this MCQ.", path.Base(exercice.Path), nline+1))
|
||||
continue
|
||||
}
|
||||
|
||||
val = true
|
||||
isJustified = true
|
||||
} else if p, ok := choice.Value.(bool); ok {
|
||||
val = p
|
||||
if isJustified {
|
||||
errs = append(errs, fmt.Sprintf("%q: error MCQ #%d: all true items has to be justified in this MCQ.", path.Base(exercice.Path), nline+1))
|
||||
continue
|
||||
}
|
||||
} else if choice.Value == nil {
|
||||
val = false
|
||||
} else {
|
||||
errs = append(errs, fmt.Sprintf("%q: error in MCQ %d choice %d: incorrect type for value: %T is not boolean.", path.Base(exercice.Path), nline+1, cid, choice.Value))
|
||||
continue
|
||||
}
|
||||
|
||||
addedFlag.Entries = append(addedFlag.Entries, fic.MCQ_entry{
|
||||
Label: choice.Label,
|
||||
Response: val,
|
||||
})
|
||||
|
||||
if isJustified && choice.Raw != nil {
|
||||
addedFlag, choices, berrs := buildKeyFlag(exercice, choice.ExerciceFlag, nline+1, "Flag correspondant")
|
||||
if len(berrs) > 0 {
|
||||
errs = append(errs, berrs...)
|
||||
}
|
||||
if addedFlag != nil {
|
||||
ret = append(ret, importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: *addedFlag,
|
||||
Choices: choices,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = append(ret, importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: addedFlag,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// buildExerciceFlags read challenge.txt and extract all flags.
|
||||
func buildExerciceFlags(i Importer, exercice fic.Exercice) (flags map[int64]importFlag, flagids []int64, errs []string) {
|
||||
params, gerrs := getExerciceParams(i, exercice)
|
||||
|
|
@ -195,115 +293,29 @@ func buildExerciceFlags(i Importer, exercice fic.Exercice) (flags map[int64]impo
|
|||
flag.Id = rand.Int63()
|
||||
}
|
||||
|
||||
switch strings.ToLower(flag.Type) {
|
||||
case "":
|
||||
flag.Type = "key"
|
||||
case "key":
|
||||
flag.Type = "key"
|
||||
case "vector":
|
||||
flag.Type = "vector"
|
||||
case "ucq":
|
||||
flag.Type = "ucq"
|
||||
case "mcq":
|
||||
flag.Type = "mcq"
|
||||
default:
|
||||
errs = append(errs, fmt.Sprintf("%q: flag #%d: invalid type of flag: should be 'key', 'mcq', 'ucq' or 'vector'.", path.Base(exercice.Path), nline+1))
|
||||
continue
|
||||
newFlags, ferrs := buildExerciceFlag(i, exercice, flag, nline)
|
||||
if len(ferrs) > 0 {
|
||||
errs = append(errs, ferrs...)
|
||||
}
|
||||
|
||||
if flag.Type == "key" || flag.Type == "ucq" || flag.Type == "vector" {
|
||||
addedFlag, choices, berrs := buildKeyFlag(exercice, flag, nline+1, "Flag")
|
||||
if len(berrs) > 0 {
|
||||
errs = append(errs, berrs...)
|
||||
}
|
||||
if addedFlag != nil {
|
||||
flags[flag.Id] = importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: *addedFlag,
|
||||
Choices: choices,
|
||||
}
|
||||
}
|
||||
} else if flag.Type == "mcq" {
|
||||
addedFlag := fic.MCQ{
|
||||
IdExercice: exercice.Id,
|
||||
Title: flag.Label,
|
||||
Entries: []fic.MCQ_entry{},
|
||||
}
|
||||
|
||||
hasOne := false
|
||||
isJustified := false
|
||||
|
||||
if !flag.NoShuffle {
|
||||
rand.Shuffle(len(flag.Choice), func(i, j int) {
|
||||
flag.Choice[i], flag.Choice[j] = flag.Choice[j], flag.Choice[i]
|
||||
})
|
||||
}
|
||||
|
||||
for cid, choice := range flag.Choice {
|
||||
var val bool
|
||||
|
||||
if choice.Raw != nil {
|
||||
if hasOne && !isJustified {
|
||||
errs = append(errs, fmt.Sprintf("%q: error MCQ #%d: all true items has to be justified in this MCQ.", path.Base(exercice.Path), nline+1))
|
||||
continue
|
||||
}
|
||||
|
||||
val = true
|
||||
isJustified = true
|
||||
} else if p, ok := choice.Value.(bool); ok {
|
||||
val = p
|
||||
if isJustified {
|
||||
errs = append(errs, fmt.Sprintf("%q: error MCQ #%d: all true items has to be justified in this MCQ.", path.Base(exercice.Path), nline+1))
|
||||
continue
|
||||
}
|
||||
} else if choice.Value == nil {
|
||||
val = false
|
||||
} else {
|
||||
errs = append(errs, fmt.Sprintf("%q: error in MCQ %d choice %d: incorrect type for value: %T is not boolean.", path.Base(exercice.Path), nline+1, cid, choice.Value))
|
||||
continue
|
||||
if len(newFlags) > 0 {
|
||||
for _, newFlag := range newFlags {
|
||||
fId := flag.Id
|
||||
for _, ok := flags[fId]; ok; _, ok = flags[fId] {
|
||||
fId = rand.Int63()
|
||||
}
|
||||
|
||||
addedFlag.Entries = append(addedFlag.Entries, fic.MCQ_entry{
|
||||
Label: choice.Label,
|
||||
Response: val,
|
||||
})
|
||||
|
||||
if isJustified && choice.Raw != nil {
|
||||
addedFlag, choices, berrs := buildKeyFlag(exercice, choice.ExerciceFlag, nline+1, "Flag correspondant")
|
||||
if len(berrs) > 0 {
|
||||
errs = append(errs, berrs...)
|
||||
}
|
||||
if addedFlag != nil {
|
||||
flags[flag.Id] = importFlag{
|
||||
Line: nline,
|
||||
Flag: *addedFlag,
|
||||
Choices: choices,
|
||||
}
|
||||
}
|
||||
// Read dependency to flag
|
||||
for _, nf := range flag.NeedFlag {
|
||||
newFlag.FlagsDeps = append(newFlag.FlagsDeps, nf.Id)
|
||||
}
|
||||
}
|
||||
|
||||
flags[flag.Id] = importFlag{
|
||||
Line: nline + 1,
|
||||
Flag: addedFlag,
|
||||
}
|
||||
}
|
||||
// Read dependency to file
|
||||
for _, lf := range flag.LockedFile {
|
||||
newFlag.FilesDeps = append(newFlag.FilesDeps, lf.Filename)
|
||||
}
|
||||
|
||||
flagids = append(flagids, flag.Id)
|
||||
|
||||
// Read dependency to flag
|
||||
for _, nf := range flag.NeedFlag {
|
||||
if v, ok := flags[flag.Id]; ok {
|
||||
v.FlagsDeps = append(v.FlagsDeps, nf.Id)
|
||||
flags[flag.Id] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Read dependency to file
|
||||
for _, lf := range flag.LockedFile {
|
||||
if v, ok := flags[flag.Id]; ok {
|
||||
v.FilesDeps = append(v.FilesDeps, lf.Filename)
|
||||
flags[flag.Id] = v
|
||||
flags[fId] = newFlag
|
||||
flagids = append(flagids, fId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -346,6 +358,24 @@ func CheckExerciceFlags(i Importer, exercice fic.Exercice, files []fic.EFile) (r
|
|||
return
|
||||
}
|
||||
|
||||
// ExerciceFlagsMap builds the flags bindings between challenge.txt and DB.
|
||||
func ExerciceFlagsMap(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Flag) {
|
||||
flags, flagids, _ := buildExerciceFlags(i, exercice)
|
||||
|
||||
kmap = map[int64]fic.Flag{}
|
||||
|
||||
for _, flagid := range flagids {
|
||||
if flag, ok := flags[flagid]; ok {
|
||||
if addedFlag, err := flag.Flag.RecoverId(); err == nil {
|
||||
kmap[flagid] = addedFlag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// SyncExerciceFlags imports all kind of flags for the given challenge.
|
||||
func SyncExerciceFlags(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Flag, errs []string) {
|
||||
if _, err := exercice.WipeFlags(); err != nil {
|
||||
|
|
|
|||
Reference in a new issue