F64 SpanTime() { if (run_bttn.state) return a.elapsed_t + tS - a.start_wall_t; else return a.elapsed_t; } F64 Cost(CMathODE *ode) { MyMass *tmpm; MySpring *tmps; F64 res = 0; tmpm=ode->next_mass; while (tmpm != &ode->next_mass) { res += tmpm->cost; tmpm = tmpm->next; } tmps = ode->next_spring; while (tmps != &ode->next_spring) { res += tmps->cost; tmps = tmps->next; } return res; } U0 DrawIt(CTask *task, CDC *dc) { MyMass *tmpm; MySpring *tmps; tmps = ode->next_spring; while (tmps != &ode->next_spring) { if (!(tmps->flags & SSF_INACTIVE)) { dc->color = tmps->color; dc->thick = tmps->thick; GrLine3(dc, tmps->end1->x, tmps->end1->y, 0, tmps->end2->x, tmps->end2->y, 0); } tmps = tmps->next; } if (cursor_mass) { dc->color = RED; dc->thick = 2; GrLine3(dc, mouse.pos.x - task->pix_left - task->scroll_x, mouse.pos.y - task->pix_top - task->scroll_y, 0, cursor_mass->x, cursor_mass->y, 0); } tmpm=ode->next_mass; while (tmpm != &ode->next_mass) { if (!(tmpm->flags&MSF_INACTIVE)) { dc->color = BLACK; GrCircle(dc, tmpm->x, tmpm->y, tmpm->radius); GrFloodFill(dc, tmpm->x, tmpm->y, TRUE); dc->color = tmpm->color; GrCircle(dc, tmpm->x, tmpm->y, tmpm->radius); GrFloodFill(dc, tmpm->x, tmpm->y, TRUE); dc->color = BLACK; GrCircle(dc, tmpm->x, tmpm->y, tmpm->radius); } tmpm = tmpm->next; } dc->color = BLACK; GrPrint(dc, 90, 0, "Cost:%12.2,f", Cost(ode)); GrPrint(dc, 90, FONT_HEIGHT, "Time:%12.2f", SpanTime); } MyMass *PlaceMass(I64 x, I64 y) { MyMass *tmpm = CAlloc(sizeof(MyMass)); tmpm->drag_profile_factor = 1.0; tmpm->x = x; tmpm->y = y; tmpm->mass = MASS_MASS; tmpm->radius = MASS_RADIUS; tmpm->cost = 25.0 * COST_SCALE; tmpm->color = YELLOW; QueueInsert(tmpm, ode->last_mass); return tmpm; } U0 NullSpring(MySpring *tmps, F64 scale) { F64 d = D3Dist(&tmps->end1->x, &tmps->end2->x); tmps->rest_len = d * scale; tmps->compression_strength = tmps->base_compression_strength / (tmps->rest_len + 1.0); tmps->tensile_strength = tmps->base_tensile_strength / (tmps->rest_len + 1.0); tmps->const = tmps->base_const / (tmps->rest_len + 1.0); tmps->cost = tmps->base_cost * tmps->rest_len; } U0 MoveMass(MyMass *tmpm, I64 x, I64 y) { MySpring *tmps; tmpm->x = x; tmpm->y = y; tmpm->DxDt = 0; tmpm->DyDt = 0; tmps = ode->next_spring; while (tmps != &ode->next_spring) { if (tmps->end1 == tmpm || tmps->end2 == tmpm) { if (tmps->flags & SSF_NO_COMPRESSION) NullSpring(tmps, WIRE_PERCENT); else NullSpring(tmps, 1.0); } tmps = tmps->next; } } U0 DelSpring(MySpring *tmps) { QueueRemove(tmps); Free(tmps); } U0 DelMass(MyMass *tmpm) { MySpring *tmps, *tmps1; tmps = ode->next_spring; while (tmps != &ode->next_spring) { tmps1 = tmps->next; if (tmps->end1 == tmpm || tmps->end2 == tmpm) DelSpring(tmps); tmps = tmps1; } QueueRemove(tmpm); Free(tmpm); } U0 DrawSpring(CDC *dc, MyMass *tmpm, I64 x, I64 y) { switch (mode_bttn.state) { case MD_CONCRETE: dc->color = LTGRAY; dc->thick = 2; break; case MD_STEEL: dc->color = DKGRAY; dc->thick = 2; break; case MD_WIRE: dc->color = RED; dc->thick = 1; break; } GrLine3(dc, tmpm->x, tmpm->y, 0, x, y, 0); } U0 PlaceSpring(MyMass *tmpm1, MyMass *tmpm2) { MySpring *tmps = CAlloc(sizeof(MySpring)); tmps->end1 = tmpm1; tmps->end2 = tmpm2; switch (mode_bttn.state) { case MD_CONCRETE: tmps->base_const = 3.00 * SPRING_SCALE; tmps->base_compression_strength = 10.00 * STRENGTH_SCALE; tmps->base_tensile_strength = 0.35 * STRENGTH_SCALE; tmps->base_cost = 0.30 * COST_SCALE; NullSpring(tmps, 1.0); tmps->color = LTGRAY; tmps->thick = 2; break; case MD_STEEL: tmps->base_const = 1.00 * SPRING_SCALE; tmps->base_compression_strength = 1.00 * STRENGTH_SCALE; tmps->base_tensile_strength = 1.00 * STRENGTH_SCALE; tmps->base_cost = 1.00 * COST_SCALE; NullSpring(tmps, 1.0); tmps->color = DKGRAY; tmps->thick = 2; break; case MD_WIRE: tmps->base_const = 0.25 * SPRING_SCALE; tmps->base_compression_strength = 0.00; tmps->base_tensile_strength = 0.50 * STRENGTH_SCALE; tmps->base_cost = 0.10 * COST_SCALE; NullSpring(tmps, WIRE_PERCENT); tmps->color = RED; tmps->thick = 1; tmps->flags |= SSF_NO_COMPRESSION; break; } QueueInsert(tmps, ode->last_spring); } U0 AnimateTask(SpanAnimateStruct *a) { MySpring *tmps, *tmps1; Bool old_run = FALSE; F64 f; while (TRUE) { tmps = ode->next_spring; while (tmps != &ode->next_spring) { tmps1 = tmps->next; f = tmps->f; if ( f > 0 && f > tmps->compression_strength && !(tmps->flags & SSF_NO_COMPRESSION) || f < 0 && -f>tmps->tensile_strength && !(tmps->flags & SSF_NO_TENSION)) tmps->flags |= SSF_INACTIVE; tmps = tmps1; } AdjustLoads(ode); Refresh; //CMathODE updated once per refresh. if (old_run != run_bttn.state) { if (run_bttn.state) { if (!a->elapsed_t || !a->saved_ode) { Free(a->saved_ode); a->saved_ode = SpanSave(ode); } a->start_wall_t = tS; ODEPause(ode, OFF); } else { ODEPause(ode); a->elapsed_t += tS - a->start_wall_t; } old_run = run_bttn.state; } } } U0 Init(SpanAnimateStruct *a) { SpanDel(ode); ode = SpanNew; run_bttn.state = 0; Refresh(2); //Allow stop to reg in animate task. if (a->saved_ode) SpanLoad(ode, a->saved_ode); else SpanBridge1Init(ode); a->elapsed_t = 0; cursor_mass = NULL; } U0 SongTask(I64) {//Song by Terry A. Davis Fs->task_end_cb = &SoundTaskEndCB; MusicSettingsReset; music.tempo = 3.636; music.stacatto_factor = 0.902; while (TRUE) { Play("5q.EeDqED4G5DhE"); Play("5q.EeDqED4G5DhE"); Play("5q.FeEFEqF4G5EhF"); Play("5q.FeEFEqF4G5EhF"); } } U0 Span() { I64 message_code, arg1, arg2; MyMass *tmpm1 = NULL, *tmpm2 = NULL; MySpring *tmps; CCtrl *bt_run, *bt_mode; U8 *src; CDC *dc = DCAlias; SettingsPush; //See SettingsPush Fs->text_attr = BROWN << 4 + BLACK; AutoComplete; WinBorder; WinMax; DocCursor; Fs->song_task = Spawn(&SongTask, NULL, "Song",, Fs); bt_run =CtrlBttnNew(0, 0, 80,, 2, "Stopped\0Running\0", run_colors, &run_bttn); bt_mode=CtrlBttnNew(0, 3.0 * FONT_HEIGHT, 80,, MD_MODES_NUM, Define("ST_SPAN_MODES"), mode_colors, &mode_bttn); a.saved_ode = NULL; Fs->win_inhibit |= WIG_DBL_CLICK; MenuPush( "File {" " New(,CH_CTRLN);" " Open(,CH_CTRLO);" " SaveAs(,CH_CTRLA);" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" " RunStop(,CH_SPACE);" " Mass(,'m');" " Concrete(,'c');" " Steel(,'s');" " Wire(,'w');" " Move(,'v');" " Delete(,'d');" "}" ); ode = NULL; Init(&a); Fs->animate_task = Spawn(&AnimateTask, &a, "Animate",, Fs); Fs->draw_it = &DrawIt; PopUpOk( "Build a bridge to hold-up the\n" "red masses. Test your design\n" "by pressing run/stop.\n\n" "The lowest cost bridge that\n" "stays standing wins.\n\n" "For a variation, try without\n" "using the center base point.\n" "\n" "Use\n" "\t$GREEN$'m'$FG$ass\n" "\t$GREEN$'c'$FG$oncrete\n" "\t$GREEN$'s'$FG$teel\n" "\t$GREEN$'w'$FG$ire\n" "\nto sel materials.\n"); try { while (TRUE) { message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_MS_L_DOWN | 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_L_UP | 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_MOVE); DCFill(dc); switch (message_code) { case MESSAGE_MS_L_DOWN: cursor_mass = tmpm1 = tmpm2 = NULL; switch (mode_bttn.state) { case MD_MASS: PlaceMass(arg1, arg2); break; case MD_CONCRETE: case MD_STEEL: case MD_WIRE: tmpm1 = MassFind(ode, arg1, arg2); break; case MD_MOVE: if (run_bttn.state) cursor_mass = MassFind(ode, arg1, arg2); else if (tmpm1 = MassFind(ode, arg1, arg2)) MoveMass(tmpm1, arg1, arg2); break; case MD_DELETE: MassOrSpringFind(ode, &tmpm1, &tmps, arg1, arg2); if (tmpm1) DelMass(tmpm1); if (tmps) DelSpring(tmps); break; } break; case MESSAGE_MS_L_UP: switch (mode_bttn.state) { case MD_CONCRETE: case MD_STEEL: case MD_WIRE: if (tmpm1 && (tmpm2 = MassFind(ode, arg1, arg2)) && tmpm1 != tmpm2) PlaceSpring(tmpm1, tmpm2); break; case MD_MOVE: if (!run_bttn.state && tmpm1) MoveMass(tmpm1, arg1, arg2); break; } cursor_mass = tmpm1 = tmpm2 = NULL; break; case MESSAGE_MS_MOVE: switch (mode_bttn.state) { case MD_MOVE: if (!run_bttn.state && tmpm1) MoveMass(tmpm1, arg1, arg2); break; case MD_CONCRETE: case MD_STEEL: case MD_WIRE: if (tmpm1) { DrawSpring(dc, tmpm1, arg1, arg2); } break; } break; case MESSAGE_MS_R_DOWN: mode_bttn.state++; if (mode_bttn.state >= MD_MODES_NUM) mode_bttn.state = 0; cursor_mass = tmpm1 = tmpm2 = NULL; break; case MESSAGE_KEY_DOWN: switch (arg1) { case '\n': if (!SpanTime || !a.saved_ode) { Free(a.saved_ode); a.saved_ode = SpanSave(ode); } Init(&a); break; case CH_CTRLN: Free(a.saved_ode); a.saved_ode = NULL; Init(&a); break; case CH_CTRLO: if (src = SpanRead) { Free(a.saved_ode); a.saved_ode = src; Init(&a); } break; case CH_CTRLA: if (!SpanTime || !a.saved_ode) { Free(a.saved_ode); a.saved_ode = SpanSave(ode); } Init(&a); SpanWrite(ode); break; case CH_SPACE: run_bttn.state = !run_bttn.state; break; case 'c': mode_bttn.state = MD_CONCRETE; break; case 's': mode_bttn.state = MD_STEEL; break; case 'w': mode_bttn.state = MD_WIRE; break; case 'm': mode_bttn.state = MD_MASS; break; case 'v': mode_bttn.state = MD_MOVE; break; case 'd': mode_bttn.state = MD_DELETE; break; case CH_ESC: if (!SpanTime || !a.saved_ode) { Free(a.saved_ode); a.saved_ode = SpanSave(ode); } Init(&a); SpanWrite(ode); case CH_SHIFT_ESC: goto span_done; } break; } } span_done: //Don't goto out of try MessageGet(,, 1 << MESSAGE_KEY_UP); } catch PutExcept; DocClear; SettingsPop; CtrlBttnDel(bt_run); CtrlBttnDel(bt_mode); SpanDel(ode); DCFill(dc); DCDel(dc); MenuPop; }